├── .devcontainer ├── devcontainer.json └── postCreateCommand.sh ├── .flake8 ├── .git-blame-ignore-revs ├── .github └── workflows │ ├── codespace-template.yml │ ├── deploy-nightly-dev.yml │ ├── deploy-nightly-old.yml │ ├── deploy-stable.yml │ ├── tests.yml │ └── update_core_commit.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── api.md ├── core_development.md ├── quickref-cli.pdf └── quickref-cli.tex ├── pelican ├── ptx-theme │ ├── static │ │ └── css │ │ │ ├── ptx-bg-dark.svg │ │ │ ├── ptx-bg-light.svg │ │ │ └── style.css │ └── templates │ │ ├── archives.html │ │ ├── article-block.html │ │ ├── article.html │ │ ├── author.html │ │ ├── authors.html │ │ ├── base.html │ │ ├── categories.html │ │ ├── category.html │ │ ├── index.html │ │ ├── page.html │ │ ├── pagination.html │ │ ├── period_archives.html │ │ ├── tag.html │ │ ├── tags.html │ │ └── translations.html └── sample-source │ ├── description.html │ ├── pages │ └── home.md │ ├── site.ptx │ └── updates │ └── 20240617.md ├── poetry.lock ├── pretext ├── __init__.py ├── __main__.py ├── cli.py ├── codechat.py ├── constants.py ├── core │ └── __init__.py ├── logger.py ├── plastex │ ├── Alignment.jinja2s │ ├── Arrays.jinja2s │ ├── Bibliography.jinja2s │ ├── Boxes.jinja2s │ ├── Breaking.jinja2s │ ├── Crossref.jinja2s │ ├── Floats.jinja2s │ ├── FontSelection.jinja2s │ ├── Footnotes.jinja2s │ ├── Index.jinja2s │ ├── Lists.jinja2s │ ├── Pictures.jinja2s │ ├── Quotations.jinja2s │ ├── Sectioning.jinja2s │ ├── Sentences.jinja2s │ ├── Space.jinja2s │ ├── Tabbing.jinja2s │ ├── Themes │ │ ├── __init__.py │ │ └── default │ │ │ ├── __init__.py │ │ │ ├── default-layout.jinja2 │ │ │ └── document-layout.jinja2 │ ├── Thms.jinja2s │ ├── Verbatim.jinja2s │ ├── __init__.py │ ├── babel.jinja2s │ ├── graphicx.jinja2s │ ├── hyperref.jinja2s │ ├── lipsum.jinja2s │ ├── longtable.jinja2s │ ├── math.jinja2s │ ├── misc.jinja2s │ ├── natbib.jinja2s │ ├── p.jinja2s │ ├── subfig.jinja2s │ ├── textcomp.jinja2s │ ├── tikzcd.jinja2 │ ├── tikzpicture.jinja2 │ ├── url.jinja2s │ └── wrapfig.jinja2s ├── project │ ├── __init__.py │ ├── generate.py │ └── xml.py ├── resources │ ├── __init__.py │ └── resource_hash_table.json ├── server.py ├── types.py └── utils.py ├── pyproject.toml ├── schema ├── README.md ├── project-ptx.rnc └── project-ptx.rng ├── scripts ├── __init__.py ├── build_package.py ├── bundle_resources.py ├── copy_cdn_files.py ├── fetch_core.py ├── fetch_core_commit.py ├── prep_nightly.py ├── symlink_core.py ├── tag_counter.py ├── unlink_core.py ├── update_changelog.py └── utils.py ├── templates ├── .gitignore ├── article │ ├── README.md │ ├── assets │ │ └── frog.jpg │ ├── publication │ │ └── publication.ptx │ └── source │ │ ├── frontmatter.ptx │ │ ├── introduction.ptx │ │ ├── main.ptx │ │ ├── section-1.ptx │ │ └── section-2.ptx ├── book │ ├── README.md │ ├── publication │ │ └── publication.ptx │ └── source │ │ ├── backmatter.ptx │ │ ├── ch-chapter-title.ptx │ │ ├── docinfo.ptx │ │ ├── frontmatter.ptx │ │ ├── main.ptx │ │ └── sec-section-name.ptx ├── codechat_config.yaml ├── course │ ├── README.md │ ├── project.ptx │ ├── publication │ │ ├── publication-syllabus.ptx │ │ ├── publication.ptx │ │ ├── publication_scorm_syllabus.ptx │ │ └── publication_standalone.ptx │ └── source │ │ ├── activities.ptx │ │ ├── activities │ │ ├── activity-template.ptx │ │ ├── magic-beans.ptx │ │ ├── wkst-eqrel-counting.ptx │ │ └── wkst-relns-digramphs.ptx │ │ ├── docinfo.ptx │ │ ├── frontmatter.ptx │ │ ├── notes.ptx │ │ ├── notes │ │ ├── week01.ptx │ │ └── week02.ptx │ │ └── syllabus.ptx ├── demo │ ├── README.md │ ├── assets │ │ ├── frog.jpg │ │ └── jsxgraph │ │ │ └── infinity.js │ ├── publication │ │ └── publication.ptx │ └── source │ │ ├── backmatter.ptx │ │ ├── ch-empty.ptx │ │ ├── ch-features.ptx │ │ ├── ch-first with spaces.ptx │ │ ├── ch-generate.ptx │ │ ├── docinfo.ptx │ │ ├── ex-first.ptx │ │ ├── fig-asymptote.ptx │ │ ├── fig-sage2d.ptx │ │ ├── fig-sage3d.ptx │ │ ├── fig-tikz.ptx │ │ ├── frontmatter.ptx │ │ ├── images │ │ ├── cflag.asy │ │ ├── sageplot2d.sage │ │ ├── sageplot3d.sage │ │ └── tikz.tex │ │ ├── main.ptx │ │ ├── sec-features.ptx │ │ ├── sec-first-examples.ptx │ │ ├── sec-first-intro.ptx │ │ └── ww.ptx ├── devcontainer.json ├── hello │ ├── README.md │ ├── publication │ │ └── publication.ptx │ └── source │ │ └── main.ptx ├── installLatex.sh ├── installPandoc.sh ├── installPretext.sh ├── installSage.sh ├── pretext-cli.yml ├── pretext-deploy.yml ├── project.ptx ├── publication.ptx ├── slideshow │ ├── project.ptx │ ├── publication │ │ └── publication.ptx │ └── source │ │ └── main.ptx ├── standalone-project.ptx └── standalone-publication.ptx └── tests ├── __init__.py ├── common.py ├── examples └── projects │ ├── custom-wwserver │ ├── project.ptx │ ├── publication │ │ └── publication.ptx │ └── source │ │ └── main.ptx │ ├── custom-xsl │ ├── project.ptx │ ├── publication │ │ └── publication.ptx │ ├── source │ │ └── main.ptx │ └── xsl │ │ ├── custom.xsl │ │ └── custom2.xsl │ ├── graphics │ ├── project.ptx │ ├── publication │ │ └── publication.ptx │ └── source │ │ └── main.ptx │ ├── interactive │ ├── .gitignore │ ├── assets │ │ └── jsxgraph │ │ │ └── infinity.js │ ├── project.ptx │ ├── publication │ │ └── publication.ptx │ └── source │ │ └── main.ptx │ ├── project_refactor │ ├── assets │ │ ├── .gitignore │ │ ├── project.ptx │ │ ├── publication │ │ │ └── publication.ptx │ │ └── source │ │ │ ├── different-than-web.ptx │ │ │ ├── same-as-web.ptx │ │ │ └── web.ptx │ ├── elaborate │ │ ├── .gitignore │ │ ├── customizations │ │ │ └── silly.xsl │ │ ├── dont-touch │ │ │ ├── extras │ │ │ │ └── print.xml │ │ │ └── publication.ptx │ │ ├── executables.ptx │ │ ├── external-things │ │ │ └── foo.txt │ │ ├── my-great-site │ │ │ └── index.html │ │ ├── my_ptx_source │ │ │ ├── book.ptx │ │ │ ├── main.ptx │ │ │ └── para.ptx │ │ └── project.ptx │ ├── legacy │ │ ├── project.ptx │ │ └── publication │ │ │ └── publication.ptx │ ├── legacy_extra │ │ ├── project.ptx │ │ └── publication │ │ │ └── publication.ptx │ ├── simple │ │ ├── .gitignore │ │ ├── assets │ │ │ └── foo.txt │ │ ├── project.ptx │ │ ├── publication │ │ │ └── publication.ptx │ │ └── source │ │ │ └── main.ptx │ ├── simple_extra_attribute │ │ ├── .gitignore │ │ ├── assets │ │ │ └── foo.txt │ │ ├── project.ptx │ │ ├── publication │ │ │ └── publication.ptx │ │ └── source │ │ │ └── main.ptx │ └── simple_extra_element │ │ ├── .gitignore │ │ ├── assets │ │ └── foo.txt │ │ ├── project.ptx │ │ ├── publication │ │ └── publication.ptx │ │ └── source │ │ └── main.ptx │ └── xref │ ├── .gitignore │ ├── project.ptx │ ├── publication │ └── publication.ptx │ └── source │ └── main.ptx ├── test_cli.py ├── test_project.py ├── test_sample_article.py └── test_utils.py /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/python 3 | { 4 | "name": "PreTeXt-CLI-dev", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "oscarlevin/pretext:full", 7 | // Features to add to the dev container. More info: https://containers.dev/features. 8 | // "features": {}, 9 | "features": { 10 | "ghcr.io/devcontainers/features/github-cli:1": {} 11 | }, 12 | // Configure tool-specific properties. 13 | "customizations": { 14 | // Configure properties specific to VS Code. 15 | "codespaces": { 16 | "openFiles": [ 17 | "README.md" 18 | ] 19 | }, 20 | "vscode": { 21 | "settings": { 22 | "editor.snippetSuggestions": "top", 23 | "editor.formatOnSave": true, 24 | "pretext-tools.installPretext": false, 25 | "redhat.telemetry.enabled": false, 26 | "xml.validation.enabled": true, 27 | "[python]": { 28 | "editor.defaultFormatter": "ms-python.python" 29 | }, 30 | "python.formatting.provider": "black", 31 | "python.testing.pytestArgs": [ 32 | "tests" 33 | ], 34 | "python.testing.unittestEnabled": false, 35 | "python.testing.pytestEnabled": true, 36 | "python.analysis.typeCheckingMode": "basic" 37 | }, 38 | "extensions": [ 39 | "oscarlevin.pretext-tools", 40 | "ms-python.python", 41 | "ms-python.flake8", 42 | "ms-python.black-formatter", 43 | "streetsidesoftware.code-spell-checker" 44 | ] 45 | } 46 | }, 47 | // Use 'postCreateCommand' to run commands after the container is created. 48 | "postCreateCommand": "sh ./.devcontainer/postCreateCommand.sh" 49 | } 50 | -------------------------------------------------------------------------------- /.devcontainer/postCreateCommand.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Install Poetry and Python dependencies" 4 | curl -sSL https://install.python-poetry.org | python - 5 | echo 'export PATH="/root/.local/bin:$PATH"' > ~/.bashrc 6 | . ~/.bashrc 7 | # This invocation requires root access, but Poetry isn't in the path. 8 | sudo `which poetry` config virtualenvs.create false 9 | sudo `which poetry` install --with dev 10 | python scripts/fetch_core.py 11 | playwright install-deps 12 | playwright install 13 | # Run mypy once so that it will install any needed type stubs. After this, the VSCode extension will run it automatically. 14 | mypy --install-types --non-interactive -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | # ******************************** 2 | # |docname| - Flake8 configuration 3 | # ******************************** 4 | # See the `docs `_ for more details. 5 | [flake8] 6 | # Although there is a `max-doc-length `_, setting this still produces lots of error about long lines, even if those lines are just a comment. The docs on `max-line-length `_ states that it applies to ALL lines -- including comments -- unless they contain a URL or a string. So, set this to allow long comments. 7 | max-line-length = 50000 8 | 9 | extend-ignore = 10 | # Black formats this differently. 11 | E203 12 | 13 | # Exclude generated files and files from the pretext repo. 14 | exclude = 15 | pretext/core/ 16 | output 17 | .venv 18 | setup.py 19 | build -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Migrate code style to Black 2 | 22f1ab10dda077556215644be494d670982facbe 3 | # Fix: Many flake8 errors. 4 | 649006e380988c0d48c4bbc35d8896d5ced63fad 5 | -------------------------------------------------------------------------------- /.github/workflows/codespace-template.yml: -------------------------------------------------------------------------------- 1 | name: deploy-codespace-template 2 | 3 | on: 4 | # Runs on completion of the deploy-stable workflow 5 | workflow_run: 6 | workflows: ["deploy-stable"] 7 | branches: ["main"] 8 | types: 9 | - completed 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | jobs: 14 | deploy: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/setup-python@v4 18 | with: 19 | python-version: "3.12" 20 | 21 | - name: Checkout codespace 22 | uses: actions/checkout@v4 23 | with: 24 | repository: PreTeXtBook/pretext-codespace 25 | token: ${{ secrets.PUSH_CODESPACES }} 26 | 27 | - name: Install pretext 28 | run: | 29 | python -m ensurepip 30 | python -m pip install --upgrade pip 31 | python -m pip install --upgrade pretext 32 | python -m pretext --version 33 | 34 | - name: pretext new hello 35 | shell: bash 36 | run: | 37 | rm -rf * 38 | rm -rf .devcontainer 39 | rm -rf .gitignore 40 | python -m pretext new hello -d . 41 | 42 | - name: setup git config 43 | run: | 44 | # setup the username and email. 45 | git config user.name ${{ github.actor }} 46 | git config user.email ${{ github.actor }}@users.noreply.github.com 47 | 48 | - name: restore previous files 49 | run: | 50 | git restore README.md 51 | git restore LICENSE 52 | 53 | - name: commit (only .devcontainer and .gitignore files) 54 | run: | 55 | # Stage the file, commit and push 56 | git add .devcontainer/* 57 | git add .gitignore 58 | git commit -m "update to latest `devcontainer files`" || echo "No new commit needed" 59 | git push origin main || echo "All done" 60 | -------------------------------------------------------------------------------- /.github/workflows/deploy-nightly-dev.yml: -------------------------------------------------------------------------------- 1 | name: deploy-nightly 2 | 3 | on: 4 | schedule: 5 | # * is a special character in YAML so you have to quote this string. 6 | - cron: "00 6 * * *" 7 | # Allows you to run this workflow manually from the Actions tab. 8 | workflow_dispatch: 9 | inputs: 10 | core-repo: 11 | description: "The repository to use for the core commit." 12 | required: false 13 | type: choice 14 | default: "PreTeXtbook/pretext" 15 | options: 16 | - "PreTeXtbook/pretext" 17 | - "oscarlevin/pretext" 18 | 19 | jobs: 20 | tests: 21 | name: Run tests 22 | uses: ./.github/workflows/tests.yml 23 | 24 | deploy: 25 | needs: tests 26 | name: Deploy to pypi 27 | runs-on: ubuntu-latest 28 | steps: 29 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it. 30 | - uses: actions/checkout@v4 31 | 32 | # Sets up python3 33 | - uses: actions/setup-python@v4 34 | with: 35 | python-version: 3.8 36 | 37 | # Setup poetry 38 | - name: Install poetry 1.8.4 39 | run: | 40 | python -m pip install --upgrade pip 41 | python -m pip install poetry==1.8.4 42 | 43 | - name: Install build dependencies 44 | run: sudo apt-get -y install libcairo2-dev pkg-config python3-dev 45 | 46 | - name: Install dependencies 47 | shell: bash 48 | run: python -m poetry install --all-extras 49 | 50 | - name: Run prep-nightly script and publish if ready 51 | env: 52 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 53 | run: | 54 | echo "Updating core commit and version; building" 55 | output=$(poetry run python scripts/prep_nightly.py ${{ inputs.core-repo }}) 56 | echo "Finished steps to prep nightly deployment" 57 | if [[ $output == *"Ready to deploy"* ]]; then 58 | poetry config pypi-token.pypi $PYPI_TOKEN 59 | poetry publish --build 60 | echo "Published to pypi" 61 | fi 62 | -------------------------------------------------------------------------------- /.github/workflows/deploy-nightly-old.yml: -------------------------------------------------------------------------------- 1 | name: deploy-nightly 2 | 3 | on: 4 | #schedule: 5 | # # * is a special character in YAML so you have to quote this string. 6 | # - cron: "00 6 * * *" 7 | # Allows you to run this workflow manually from the Actions tab. 8 | workflow_dispatch: 9 | 10 | jobs: 11 | tests: 12 | name: Run tests 13 | uses: ./.github/workflows/tests.yml 14 | 15 | deploy: 16 | needs: tests 17 | name: Deploy to pypi 18 | runs-on: ubuntu-latest 19 | steps: 20 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it. 21 | - uses: actions/checkout@v4 22 | 23 | # Sets up python3 24 | - uses: actions/setup-python@v4 25 | with: 26 | python-version: 3.8 27 | 28 | # Setup poetry 29 | - name: Install poetry 1.8.4 30 | run: | 31 | python -m pip install --upgrade pip 32 | python -m pip install poetry==1.8.4 33 | 34 | - name: Install build dependencies 35 | run: sudo apt-get -y install libcairo2-dev pkg-config python3-dev 36 | 37 | - name: Install dependencies 38 | shell: bash 39 | run: python -m poetry install --all-extras 40 | 41 | - name: Run prep-nightly script and publish if ready 42 | env: 43 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 44 | run: | 45 | echo "Updating core commit and version; building" 46 | output=$(poetry run python scripts/prep_nightly.py) 47 | echo "Finished steps to prep nightly deployment" 48 | if [[ $output == *"Ready to deploy"* ]]; then 49 | poetry config pypi-token.pypi $PYPI_TOKEN 50 | poetry publish --build 51 | echo "Published to pypi" 52 | fi 53 | -------------------------------------------------------------------------------- /.github/workflows/update_core_commit.yml: -------------------------------------------------------------------------------- 1 | name: Update-Core-Commit 2 | 3 | on: 4 | # Currently this workflow only runs when triggered manually. Perhaps we can set it up to run when a tag is pushed. Or when a release is made. Or that it could create a release, on a release it can create a tag? 5 | # Allows you to run this workflow manually from the Actions tab 6 | workflow_dispatch: 7 | inputs: 8 | branch: 9 | description: "Use main branch for regular releases, legacy-support for 1.8x fixes." 10 | required: false 11 | type: choice 12 | default: "main" 13 | options: 14 | - "main" 15 | - "legacy-support" 16 | 17 | jobs: 18 | tasks: 19 | name: Update core commit 20 | runs-on: ubuntu-latest 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - uses: actions/checkout@v4 24 | with: 25 | ref: ${{ inputs.branch }} 26 | 27 | # Sets up python3 28 | - uses: actions/setup-python@v4 29 | with: 30 | python-version: 3.8 31 | 32 | - name: Run bump script 33 | run: | 34 | echo "Updating core commit" 35 | python scripts/fetch_core_commit.py 36 | echo "Finished" 37 | 38 | - name: setup git config 39 | run: | 40 | # setup the username and email. 41 | git config user.name "${{ github.actor }} via GitHub Actions" 42 | git config user.email "${{ github.actor }}@github_actions.no_reply" 43 | 44 | - name: commit core update via pr 45 | run: | 46 | git checkout -b core-commit-update 47 | git add pretext/__init__.py 48 | git commit -m "update to latest core commit" 49 | git push --set-upstream origin core-commit-update 50 | gh pr create --fill 51 | gh pr merge -s -d -t "update to latest core commit" 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # VS Code user settings 7 | .vscode 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 94 | __pypackages__/ 95 | 96 | # Celery stuff 97 | celerybeat-schedule 98 | celerybeat.pid 99 | 100 | # SageMath parsed files 101 | *.sage.py 102 | 103 | # Environments 104 | .env 105 | .venv 106 | env/ 107 | venv/ 108 | ENV/ 109 | env.bak/ 110 | venv.bak/ 111 | 112 | # Spyder project settings 113 | .spyderproject 114 | .spyproject 115 | 116 | # Rope project settings 117 | .ropeproject 118 | 119 | # mkdocs documentation 120 | /site 121 | 122 | # mypy 123 | .mypy_cache/ 124 | .dmypy.json 125 | dmypy.json 126 | 127 | # Pyre type checker 128 | .pyre/ 129 | 130 | # pytype static type analyzer 131 | .pytype/ 132 | 133 | # Cython debug symbols 134 | cython_debug/ 135 | 136 | # Hide PyPI token 137 | .pypitoken 138 | 139 | #pretext-core 140 | pretext/core/pretext.py 141 | pretext/core/braille_format.py 142 | tests/examples/core 143 | #zipped resources 144 | pretext/resources/*.zip 145 | #xml resources (rs_file) 146 | pretext/resources/*.xml 147 | pretext/resources/*.tgz 148 | 149 | #default new pretext project 150 | new-pretext-project 151 | 152 | #poetry 153 | .python-version 154 | 155 | ## Core latex/pdflatex auxiliary files: 156 | *.aux 157 | *.lof 158 | *.log 159 | *.lot 160 | *.fls 161 | *.out 162 | *.toc 163 | *.fmt 164 | *.fot 165 | *.cb 166 | *.cb2 167 | .*.lb 168 | ## Build tool auxiliary files: 169 | *.fdb_latexmk 170 | *.synctex 171 | *.synctex(busy) 172 | *.synctex.gz 173 | *.synctex.gz(busy) 174 | *.pdfsync -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | # Using PreTeXt as a library 2 | 3 | The PreTeXt-CLI includes `Project` and `Target` classes which can be used when this package is imported as a library. 4 | 5 | More details are coming soon. 6 | 7 | ## Logging 8 | 9 | This package uses python's logging library and implements a logger with name `"ptxlogger"`. To get the same messages as the CLI gives (with default level of `INFO`), you can include the following. 10 | 11 | ```python 12 | import logging 13 | from pretext import logger 14 | 15 | log = logging.getLogger("ptxlogger") 16 | logger.add_log_stream_handler() 17 | log.setLevel(logging.INFO) 18 | ``` 19 | 20 | The `logger.add_log_stream_handler()` function simply creates a stream-handler that outputs to stdout. You could set up `log` however you like using the options provided by the `logging` library. If you would like to get spit out the logs to a file as the CLI does, you could include the line 21 | 22 | ```python 23 | logger.add_log_file_handler(path_to_log_directory) 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/core_development.md: -------------------------------------------------------------------------------- 1 | # Using the CLI when developing on core pretext 2 | 3 | The CLI bundles a frozen version of the core python script, as well as the corresponding support files (xsl, css, js, etc). But because of this, it is not possible for the CLI to use a local version of the core python script. This means that if you are developing on the core python script and want to test with the CLI, you will need to install the CLI from source. 4 | 5 | This guide will walk you through the process of installing the CLI from source and linking the core resources to your local version of the pretext repository. 6 | 7 | ## Installing the CLI from source 8 | 9 | We will assume you have a local clone of the pretext repository in a directory parallel to a local clone of the pretext-cli repository. 10 | 11 | If you don't have these yet, you can clone them with the following commands: 12 | 13 | ```bash 14 | git clone https://github.com/PreTeXtBook/pretext-cli.git 15 | git clone https://github.com/PreTeXtBook/pretext.git 16 | ``` 17 | 18 | To install the CLI from source, we follow the same instructions as in the development section of the README. 19 | 20 |
21 | Show instructions 22 | First, navigate to the pretext-cli directory and install the CLI with the following commands: 23 | 24 | ```bash 25 | cd pretext-cli 26 | poetry install 27 | python ./scripts/fetch_core.py 28 | ``` 29 | 30 | You should now be able to test that everything worked by running the following commands: 31 | 32 | ```bash 33 | pretext --version # You should get the version installed with PIP 34 | poetry run pretext --version # You should get the newer version installed with poetry 35 | ``` 36 | 37 | At this point, it is probably easiest to start a `poetry shell` so you don't have to prefix every command with `poetry run`. 38 | 39 | ```bash 40 | poetry shell 41 | ``` 42 | 43 | Now when you run `pretext --version` you should get the version installed with poetry. 44 |
45 | 46 | ## Linking the core resources 47 | 48 | The CLI has a script `script\symlink_core.py` that will create symbolic links from the CLI's `core` directory to the core directory in the pretext repository. This script will also create a `core` directory in the CLI's `pretext` directory and link the core resources there as well. This is necessary because the CLI uses the core resources from the `pretext` directory, not the `core` directory. 49 | 50 | Assuming you have the pretext and pretext-cli repositories in the same directory, you can run the following command to link the core resources: 51 | 52 | ```bash 53 | python ./scripts/symlink_core.py 54 | ``` 55 | 56 | If you have the pretext repository elsewhere, you can specify the path to the pretext repository as an argument to the script: 57 | 58 | ```bash 59 | python ./scripts/symlink_core.py /path/to/pretext 60 | ``` 61 | 62 | Now any changes you make the python script, xsl, css, js, or schema in the pretext repository will be reflected in the CLI (just stay in the `poetry shell`). 63 | 64 | ## Unlinking the core resources 65 | 66 | To go back to using the version of core resources specified in the `CORE_COMMIT` file, you can run the following command: 67 | 68 | ```bash 69 | python ./scripts/unlink_core.py 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/quickref-cli.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/docs/quickref-cli.pdf -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/archives.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - Archives{% endblock %} 4 | 5 | {% block content %} 6 |

Archives for {{ SITENAME }}

7 | 8 |
9 | {% for article in dates %} 10 |
{{ article.locale_date }}
11 |
{{ article.title }}
12 | {% endfor %} 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/article-block.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

5 | {{ article.title }}

7 | {% import 'translations.html' as translations with context %} 8 | {{ translations.translations_for(article) }} 9 |
10 |
11 | {{ article.content }} 12 |
13 |
14 |

Published:

17 | {% if article.modified %} 18 |

Last updated:

21 | {% endif %} 22 | {% if article.authors %} 23 |
24 | By {% for author in article.authors %} 25 | {{ author }} 26 | {% endfor %} 27 |
28 | {% endif %} 29 | {% if article.category %} 30 |

31 | Category: {{ article.category }} 32 |

33 | {% endif %} 34 | {% if article.tags %} 35 |

36 | Tags: 37 | {% for tag in article.tags %} 38 | {{ tag }} 39 | {% endfor %} 40 |

41 | {% endif %} 42 |
43 |
-------------------------------------------------------------------------------- /pelican/ptx-theme/templates/article.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block html_lang %}{{ article.lang }}{% endblock %} 3 | 4 | {% block title %}{{ SITENAME|striptags }} - {{ article.title|striptags }}{% endblock %} 5 | 6 | {% block head %} 7 | {{ super() }} 8 | 9 | {% import 'translations.html' as translations with context %} 10 | {% if translations.entry_hreflang(article) %} 11 | {{ translations.entry_hreflang(article) }} 12 | {% endif %} 13 | 14 | {% if article.description %} 15 | 16 | {% endif %} 17 | 18 | {% for tag in article.tags %} 19 | 20 | {% endfor %} 21 | 22 | {% endblock %} 23 | 24 | {% block content %} 25 | {% include 'article-block.html' %} 26 | {% endblock %} -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/author.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - Articles by {{ author }}{% endblock %} 4 | 5 | 6 | {% block content %} 7 | {% block content_title %} 8 |

Articles by {{ author }}

9 | {% endblock %} 10 | {% if articles_page.object_list %} 11 | {% for article in articles_page.object_list %} 12 | {% include 'article-block.html' %} 13 | {% endfor %} 14 | {% if articles_page.has_other_pages() %} 15 | {% include 'pagination.html' %} 16 | {% endif %} 17 | {% endif %} 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/authors.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - Authors{% endblock %} 4 | 5 | {% block content %} 6 |

Authors on {{ SITENAME }}

7 |
    8 | {% for author, articles in authors|sort %} 9 |
  • {{ author }} ({{ articles|count }})
  • 10 | {% endfor %} 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block head %} 5 | {% block title %}{{ SITENAME|striptags }}{% endblock title %} 6 | 7 | 8 | 9 | 10 | {% if SITESUBTITLE %} 11 | 12 | {% endif %} 13 | {% if FEED_ALL_ATOM %} 14 | 15 | {% endif %} 16 | {% if FEED_ALL_RSS %} 17 | 18 | {% endif %} 19 | {% if FEED_ATOM %} 20 | 21 | {% endif %} 22 | {% if FEED_RSS %} 23 | 24 | {% endif %} 25 | {% if CATEGORY_FEED_ATOM and category %} 26 | 27 | {% endif %} 28 | {% if CATEGORY_FEED_RSS and category %} 29 | 30 | {% endif %} 31 | {% if TAG_FEED_ATOM and tag %} 32 | 33 | {% endif %} 34 | {% if TAG_FEED_RSS and tag %} 35 | 36 | {% endif %} 37 | {% endblock head %} 38 | 39 | 40 | 41 |
42 | 53 |

{{ SITENAME }}

54 | {% if SITESUBTITLE %}

{{ SITESUBTITLE }}

{% endif %} 55 |
56 |
57 | {% block content %} 58 | {% endblock %} 59 |
60 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - Categories{% endblock %} 4 | 5 | {% block content %} 6 |

Categories on {{ SITENAME }}

7 |
    8 | {% for category, articles in categories|sort %} 9 |
  • {{ category }} ({{ articles|count }})
  • 10 | {% endfor %} 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - {{ category }} category{% endblock %} 4 | 5 | 6 | {% block content %} 7 | {% block content_title %} 8 |

Articles in the {{ category }} category

9 | {% endblock %} 10 | {% if articles_page.object_list %} 11 | {% for article in articles_page.object_list %} 12 | {% include 'article-block.html' %} 13 | {% endfor %} 14 | {% if articles_page.has_other_pages() %} 15 | {% include 'pagination.html' %} 16 | {% endif %} 17 | {% endif %} 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | {% if PTX_SITE_DESCRIPTION %} 4 |
{{ PTX_SITE_DESCRIPTION }}
5 | {% endif %} 6 | {% if PTX_SHOW_TARGETS == "yes" %} 7 |

Available online:

8 |
    9 | {% for title, link in PTX_TARGETS %} 10 |
  • {{ title }}
  • 11 | {% endfor %} 12 |
13 | {% endif %} 14 | {% if articles_page.object_list %} 15 | {% block content_title %} 16 |

News and updates

17 | {% endblock %} 18 | {% for article in articles_page.object_list %} 19 | {% include 'article-block.html' %} 20 | {% endfor %} 21 | {% if articles_page.has_other_pages() %} 22 | {% include 'pagination.html' %} 23 | {% endif %} 24 | {% endif %} 25 | 26 | {% endblock content %} 27 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block html_lang %}{{ page.lang }}{% endblock %} 3 | 4 | {% block title %}{{ SITENAME|striptags }} - {{ page.title|striptags }}{%endblock%} 5 | 6 | {% block head %} 7 | {{ super() }} 8 | 9 | {% import 'translations.html' as translations with context %} 10 | {% if translations.entry_hreflang(page) %} 11 | {{ translations.entry_hreflang(page) }} 12 | {% endif %} 13 | {% endblock %} 14 | 15 | {% block content %} 16 |

{{ page.title }}

17 | {% import 'translations.html' as translations with context %} 18 | {{ translations.translations_for(page) }} 19 | 20 | {{ page.content }} 21 | 22 | {% if page.modified %} 23 |
24 |

25 | Last updated: {{ page.locale_modified }} 26 |

27 |
28 | {% endif %} 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/pagination.html: -------------------------------------------------------------------------------- 1 | {% if DEFAULT_PAGINATION %} 2 | {% set first_page = articles_paginator.page(1) %} 3 | {% set last_page = articles_paginator.page(articles_paginator.num_pages) %} 4 | 17 | {% endif %} 18 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/period_archives.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - {{ period | reverse | join(' ') }} archives{% endblock %} 4 | 5 | {% block content %} 6 |

Archives for {{ period | reverse | join(' ') }}

7 | 8 |
9 | {% for article in dates %} 10 |
{{ article.locale_date }}
11 |
{{ article.title }}
12 | {% endfor %} 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - {{ tag }} tag{% endblock %} 4 | 5 | 6 | {% block content %} 7 | {% block content_title %} 8 |

Articles tagged with {{ tag }}

9 | {% endblock %} 10 | {% if articles_page.object_list %} 11 | {% for article in articles_page.object_list %} 12 | {% include 'article-block.html' %} 13 | {% endfor %} 14 | {% if articles_page.has_other_pages() %} 15 | {% include 'pagination.html' %} 16 | {% endif %} 17 | {% endif %} 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/tags.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}{{ SITENAME|striptags }} - Tags{% endblock %} 4 | 5 | {% block content %} 6 |

Tags for {{ SITENAME }}

7 |
    8 | {% for tag, articles in tags|sort %} 9 |
  • {{ tag }} ({{ articles|count }})
  • 10 | {% endfor %} 11 |
12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /pelican/ptx-theme/templates/translations.html: -------------------------------------------------------------------------------- 1 | {% macro translations_for(article) %} 2 | {% if article.translations %} 3 | Translations: 4 | {% for translation in article.translations %} 5 | {{ translation.lang }} 6 | {% endfor %} 7 | {% endif %} 8 | {% endmacro %} 9 | 10 | {% macro entry_hreflang(entry) %} 11 | {% if entry.translations %} 12 | {% for translation in entry.translations %} 13 | 14 | {% endfor %} 15 | {% endif %} 16 | {% endmacro %} 17 | -------------------------------------------------------------------------------- /pelican/sample-source/description.html: -------------------------------------------------------------------------------- 1 | Sample description written in HTML. -------------------------------------------------------------------------------- /pelican/sample-source/pages/home.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sample Page 3 | --- 4 | 5 | Sample content. 6 | -------------------------------------------------------------------------------- /pelican/sample-source/site.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | Custom Site Name 4 | Custome subtitle 5 | 6 | 7 | -------------------------------------------------------------------------------- /pelican/sample-source/updates/20240617.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sample Post 3 | date: 2024-06-14 4 | author: Steven Clontz 5 | --- 6 | 7 | Hello world! 8 | -------------------------------------------------------------------------------- /pretext/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021-2024 Steven Clontz and Oscar Levin 2 | 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | from pathlib import Path 17 | from single_version import get_version 18 | 19 | VERSION = get_version("pretext", Path(__file__).parent.parent) 20 | 21 | CORE_COMMIT = "b31d10bd04eebc7387bb1d55b1e64a603533c3e0" 22 | 23 | 24 | def activate() -> None: 25 | """ 26 | This function was provided by the original `pretext` package 27 | deployed to PyPI by Alex Willmer. Thanks to their generosity, 28 | we were allowed to adopt this namespace as of 1.0, so we raise an error here 29 | to help anyone who might have upgraded from the original package. 30 | """ 31 | raise RuntimeError( 32 | "As of version 1.0, the `pretext` PyPI package has been " 33 | + "transferred to PreTeXtBook.org. Install a <1.0 version to use the " 34 | + "pretext.activate() feature from the original `pretext` package." 35 | ) 36 | -------------------------------------------------------------------------------- /pretext/__main__.py: -------------------------------------------------------------------------------- 1 | from .cli import main 2 | 3 | if __name__ == "__main__": 4 | main() 5 | -------------------------------------------------------------------------------- /pretext/core/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from .pretext import * 3 | from . import pretext 4 | 5 | # from .braille_format import * 6 | # from . import braille_format 7 | except ImportError as e: 8 | raise ImportError( 9 | "Failed to import the core pretext.py file. Perhaps the file is unavailable? " 10 | "Run `scripts/fetch_core.py` to grab a copy of pretex core.\n" 11 | "The original error message is: " + e.msg 12 | ) 13 | from .. import resources 14 | from .. import CORE_COMMIT, VERSION 15 | 16 | set_ptx_path(resources.resource_base_path() / "core") 17 | 18 | 19 | def cli_build_message() -> str: 20 | """ 21 | Override the build_info_message function of core to report that the CLI was used to build. 22 | """ 23 | return ( 24 | f"built with the PreTeXt-CLI, version {VERSION} using core commit {CORE_COMMIT}" 25 | ) 26 | 27 | 28 | pretext.build_info_message = cli_build_message 29 | -------------------------------------------------------------------------------- /pretext/logger.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from pathlib import Path 3 | import sys 4 | import logging 5 | import click_log 6 | 7 | log = logging.getLogger("ptxlogger") 8 | 9 | 10 | def add_log_stream_handler() -> None: 11 | # Set up logging: 12 | # click_handler logs all messages to stdout as the CLI runs 13 | click_handler = logging.StreamHandler(sys.stdout) 14 | click_handler.setFormatter(click_log.ColorFormatter()) 15 | log.addHandler(click_handler) 16 | 17 | 18 | def get_log_error_flush_handler() -> logging.handlers.MemoryHandler: 19 | # error_flush_handler captures error/critical logs for flushing to stderr at the end of a CLI run 20 | sh = logging.StreamHandler(sys.stderr) 21 | sh.setFormatter(click_log.ColorFormatter()) 22 | sh.setLevel(logging.ERROR) 23 | error_flush_handler = logging.handlers.MemoryHandler( 24 | capacity=1024 * 100, 25 | flushLevel=100, 26 | target=sh, 27 | flushOnClose=False, 28 | ) 29 | error_flush_handler.setLevel(logging.ERROR) 30 | log.addHandler(error_flush_handler) 31 | return error_flush_handler 32 | 33 | 34 | def add_log_file_handler(log_folder_path: Path) -> None: 35 | # create file handler which logs even debug messages 36 | log_folder_path.mkdir(exist_ok=True) 37 | logfile = ( 38 | log_folder_path / f"{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}.log" 39 | ) 40 | fh = logging.FileHandler(logfile, mode="w") 41 | fh.setLevel(logging.DEBUG) 42 | file_log_format = logging.Formatter("{levelname:<8}: {message}", style="{") 43 | fh.setFormatter(file_log_format) 44 | log.addHandler(fh) 45 | -------------------------------------------------------------------------------- /pretext/plastex/Alignment.jinja2s: -------------------------------------------------------------------------------- 1 | name: center centering centerline 2 | 3 | {{ obj }} 4 | 5 | {# #} 6 | 7 | name: flushleft raggedright leftline 8 | 9 | {{ obj }} 10 | 11 | {# #} 12 | 13 | 14 | name: raggedleft flushright llap 15 | 16 | {{ obj }} 17 | 18 | {# #} 19 | 20 | name: raggedbottom 21 | 22 | {{ obj }} 23 | 24 | {# #} 25 | -------------------------------------------------------------------------------- /pretext/plastex/Arrays.jinja2s: -------------------------------------------------------------------------------- 1 | name: tabular array tabular* tabularx 2 | 3 | {% for row in obj %} 4 | 5 | {% for cell in row %} 6 | {{ cell }} 7 | {% endfor %} 8 | 9 | {% endfor %} 10 | 11 | 12 | name: multicolumn 13 | {{ obj }} 14 | 15 | name: cline toprule bottomrule midrule cmidrule morecmidrules addlinespace specialrule 16 | -------------------------------------------------------------------------------- /pretext/plastex/Bibliography.jinja2s: -------------------------------------------------------------------------------- 1 | name: thebibliography 2 | 3 | {% for item in obj %} 4 | {{ item }} 5 | {% endfor %} 6 | 7 | 8 | name: bibliography 9 | 10 | 11 | {{ obj }} 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /pretext/plastex/Boxes.jinja2s: -------------------------------------------------------------------------------- 1 | name: mbox makebox 2 | {{ obj }} 3 | 4 | name: fbox framebox 5 | {{ obj }} 6 | 7 | name: parbox 8 | {{ obj }} 9 | 10 | name: minipage 11 | {{ obj }} 12 | 13 | name: raisebox rule 14 | -------------------------------------------------------------------------------- /pretext/plastex/Breaking.jinja2s: -------------------------------------------------------------------------------- 1 | name: linebreak \ newline pagebreak newpage clearpage cleardoublepage 2 | 3 | -------------------------------------------------------------------------------- /pretext/plastex/Crossref.jinja2s: -------------------------------------------------------------------------------- 1 | name: ref 2 | {% if 'label' in obj.idref and obj.idref.label.ref %}{{obj.idref.label.ref}}{% else %}??{% endif %} 3 | 4 | name: eqref 5 | {% if 'label' in obj.idref and obj.idref.label.ref %}{{obj.idref.label.ref}}{% else %}??{% endif %} 6 | 7 | name: cref Cref 8 | {% if 'label' in obj.idref and obj.idref.label.ref %}{{ obj.refname() }} {{obj.idref.label.ref}}{% else %}??{% endif %} 9 | 10 | name: pageref 11 | {% if 'label' in obj.idref and obj.idref.label.ref %}{% else %}??{% endif %} 12 | 13 | name: label 14 | -------------------------------------------------------------------------------- /pretext/plastex/Floats.jinja2s: -------------------------------------------------------------------------------- 1 | name: figure figure* 2 |
3 | {{ obj }} 4 |
5 | 6 | name: table table* 7 | 8 | {{ obj }} 9 |
10 | 11 | name: marginpar 12 | 13 | 14 | name: caption 15 | 16 | {{ obj }} 17 | 18 | -------------------------------------------------------------------------------- /pretext/plastex/FontSelection.jinja2s: -------------------------------------------------------------------------------- 1 | name: mdseries textmd 2 | {{ obj }} 3 | 4 | name: bfseries textbf 5 | {{ obj }} 6 | 7 | name: rmfamily textrm 8 | {{ obj }} 9 | 10 | name: sffamily textsf 11 | {{ obj }} 12 | 13 | name: ttfamily texttt 14 | {{ obj }} 15 | 16 | name: upshape textup 17 | {{ obj }} 18 | 19 | name: itshape textit 20 | {{ obj }} 21 | 22 | name: slshape textsl 23 | {{ obj }} 24 | 25 | name: scshape textsc 26 | {{ obj }} 27 | 28 | name: textnormal 29 | {{ obj }} 30 | 31 | name: rm 32 | {{ obj }} 33 | 34 | name: cal 35 | {{ obj }} 36 | 37 | name: it 38 | {{ obj }} 39 | 40 | name: sl 41 | {{ obj }} 42 | 43 | name: bf 44 | {{ obj }} 45 | 46 | name: tt 47 | {{ obj }} 48 | 49 | name: sc 50 | {{ obj }} 51 | 52 | 53 | name: tiny 54 | {{ obj }} 55 | 56 | 57 | name: scriptsize 58 | {{ obj }} 59 | 60 | name: footnotesize 61 | {{ obj }} 62 | 63 | name: small 64 | {{ obj }} 65 | 66 | name: normalsize 67 | {{ obj }} 68 | 69 | name: large 70 | {{ obj }} 71 | 72 | name: Large 73 | {{ obj }} 74 | 75 | name: LARGE 76 | {{ obj }} 77 | 78 | name: huge 79 | {{ obj }} 80 | 81 | name: Huge 82 | {{ obj }} 83 | 84 | 85 | name: symbol 86 | {{obj}} 87 | 88 | -------------------------------------------------------------------------------- /pretext/plastex/Footnotes.jinja2s: -------------------------------------------------------------------------------- 1 | name: footnote 2 | {{ obj }} 3 | 4 | name: footnotemark 5 | {{ obj }} 6 | 7 | name: footnotetext 8 | -------------------------------------------------------------------------------- /pretext/plastex/Index.jinja2s: -------------------------------------------------------------------------------- 1 | name: theindex printindex 2 | 3 | Index 4 | 5 | 6 | 7 | name: index 8 | {{obj.argSource[1:-1]}} 9 | 10 | name: see seealso 11 | {{ obj.captionName }} 12 | -------------------------------------------------------------------------------- /pretext/plastex/Lists.jinja2s: -------------------------------------------------------------------------------- 1 | name: itemize 2 |
    3 | {% for item in obj %} 4 |
  • {{ item }}
  • 5 | {% endfor %} 6 |
7 | 8 | name: enumerate 9 |
    10 | {% for item in obj %} 11 |
  1. {{ item }}
  2. 12 | {% endfor %} 13 |
14 | 15 | name: list trivlist description 16 |
17 | {% for item in obj %} 18 | {{ item.attributes.term or obj.attributes.defaultlabel }} 19 |
  • {{ item }}
  • 20 | {% endfor %} 21 |
    22 | -------------------------------------------------------------------------------- /pretext/plastex/Pictures.jinja2s: -------------------------------------------------------------------------------- 1 | name: picture 2 | {{ obj.source }} 3 | 4 | {{ obj.source }} 5 | 6 | 7 | -------------------------------------------------------------------------------- /pretext/plastex/Quotations.jinja2s: -------------------------------------------------------------------------------- 1 | name: quote 2 |
    3 | {{ obj }} 4 |
    5 | 6 | name: quotation 7 |
    8 | {{ obj }} 9 |
    10 | 11 | name: verse 12 | 13 | {{ obj }} 14 | 15 | -------------------------------------------------------------------------------- /pretext/plastex/Sectioning.jinja2s: -------------------------------------------------------------------------------- 1 | name: abstract 2 | 3 | {{ obj }} 4 | 5 | 6 | name: title 7 | {{ obj }} 8 | 9 | 10 | name: author 11 | 12 | {{ obj }} 13 | 14 | 15 | 16 | name: date 17 | 18 | {{ obj }} 19 | 20 | 21 | name: thanks 22 | 23 | {{ obj }} 24 | 25 | 26 | name: maketitle 27 | {% set metadata=obj.ownerDocument.userdata %} 28 | 29 | 30 | {{ metadata.title }} 31 | {% if metadata.author %} 32 | {%for author in metadata.author %} 33 | {{ author }} 34 | {% endfor %} 35 | {% endif %} 36 | {% if metadata.date %} 37 | {{ metadata.date }} 38 | {% endif %} 39 | {% if metadata.thanks %} 40 | {{ metadata.thanks }} 41 | {% endif %} 42 | 43 | 44 | 45 | 46 | name: document 47 | {{ obj }} 48 | 49 | 50 | name: part 51 | 52 | {{ obj.title }} 53 | 54 | {% if obj.links.child and obj.childNodes[0].nodeName == "par" %} 55 | 56 | {{ obj }} 57 | 58 | {%- else -%} 59 | {{ obj }} 60 | {%- endif %} 61 | 62 | {% for section in obj.tableofcontents recursive %} 63 | 64 | {% endfor %} 65 | 66 | {# #} 67 | 68 | 69 | name: chapter 70 | 71 | {{ obj.title }} 72 | 73 | {% if obj.links.child and obj.childNodes[0].nodeName == "par" %} 74 | 75 | {{ obj }} 76 | 77 | {%- else -%} 78 | {{ obj }} 79 | {%- endif %} 80 | 81 | {% for section in obj.tableofcontents recursive %} 82 | 83 | {% endfor %} 84 | 85 | {# #} 86 | 87 | 88 | name: section 89 |
    90 | {{ obj.title }} 91 | 92 | {{ obj }} 93 | 94 |
    95 | 96 | 97 | 98 | name: subsection 99 | 100 | {{ obj.title }} 101 | 102 | {{ obj }} 103 | 104 | 105 | {# #} 106 | 107 | 108 | name: subsubsection 109 | 110 | {{ obj.title }} 114 | {# #} 115 | 116 | 117 | name: paragraph 118 | 119 | {{ obj.title }} 120 | 121 | {{ obj }} 122 | 123 | {# #} 124 | -------------------------------------------------------------------------------- /pretext/plastex/Sentences.jinja2s: -------------------------------------------------------------------------------- 1 | name: $ 2 | $ 3 | 4 | name: % 5 | % 6 | 7 | name: { 8 | { 9 | 10 | name: } 11 | } 12 | 13 | name: _ 14 | _ 15 | 16 | name: & 17 | & 18 | 19 | name: # 20 | # 21 | 22 | 23 | name: LaTeX 24 | {{""}} 25 | 26 | 27 | name: TeX 28 | type: xml 29 | {{""}} 30 | 31 | name: emph em 32 | {{ obj }} 33 | 34 | name: active::~ 35 |   36 | 37 | name: enspace enskip 38 | comment:   39 | 40 | name: quad 41 | 42 | 43 | name: qquad 44 | 45 | 46 | name: thinspace / 47 | comment:   48 | 49 | name: underbar 50 | {{ obj }} 51 | 52 | name: textsuperscript 53 | 54 | 55 | name: textsubscript 56 | 57 | -------------------------------------------------------------------------------- /pretext/plastex/Space.jinja2s: -------------------------------------------------------------------------------- 1 | name: -hspace 2 |   3 | 4 | name: -vspace 5 |
     
    6 | 7 | 8 | 9 | name: -bigskip 10 |
    11 | 12 | name: -medskip 13 |
    14 | 15 | name: -smallskip 16 |
    17 | 18 | -------------------------------------------------------------------------------- /pretext/plastex/Tabbing.jinja2s: -------------------------------------------------------------------------------- 1 | name: tabbing 2 | 5 | 6 | -------------------------------------------------------------------------------- /pretext/plastex/Themes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/pretext/plastex/Themes/__init__.py -------------------------------------------------------------------------------- /pretext/plastex/Themes/default/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/pretext/plastex/Themes/default/__init__.py -------------------------------------------------------------------------------- /pretext/plastex/Themes/default/default-layout.jinja2: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ obj }} 4 | 5 | -------------------------------------------------------------------------------- /pretext/plastex/Themes/default/document-layout.jinja2: -------------------------------------------------------------------------------- 1 | {% set links = obj.links %} 2 | {% set doc = obj.ownerDocument.getElementsByTagName('document')[0] %} 3 | {% set type = obj.ownerDocument.getElementsByTagName('documentclass')[0].attributes['name'] %} 4 | {% set toc = obj.tableofcontents %} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% if type == 'article' %} 12 |
    13 | {{ obj.title }} 14 | {{ obj }} 15 | {% for section in toc recursive %} 16 | 17 | {% endfor %} 18 |
    19 | {% else %} 20 | 21 | {{ obj.title }} 22 | 23 | 24 | 25 | 26 | {{ obj }} 27 | 28 | {% for section in toc recursive %} 29 | 30 | {% endfor %} 31 | 32 | 33 | 34 | 35 | 36 | {% endif %} 37 |
    38 | 39 | -------------------------------------------------------------------------------- /pretext/plastex/Thms.jinja2s: -------------------------------------------------------------------------------- 1 | name: thmenv 2 | <{{ obj.thmName }}> 3 | {% if obj.title %} 4 | {{ obj.title }} 5 | {% endif %} 6 | 7 | {{ obj }} 8 | 9 | 10 | 11 | 12 | name: proof 13 | 14 | {{ obj }} 15 | 16 | 17 | name: qedhere qed 18 | 19 | -------------------------------------------------------------------------------- /pretext/plastex/Verbatim.jinja2s: -------------------------------------------------------------------------------- 1 | name: verbatim 2 |
    {{ obj }}
    3 | 4 | name: verb 5 | {{ obj }} 6 | -------------------------------------------------------------------------------- /pretext/plastex/__init__.py: -------------------------------------------------------------------------------- 1 | from plasTeX.Renderers.PageTemplate import Renderer as _Renderer 2 | from plasTeX.TeX import TeX 3 | from pathlib import Path 4 | import re 5 | import logging 6 | 7 | log = logging.getLogger("ptxlogger") 8 | 9 | 10 | class Pretext(_Renderer): 11 | """Renderer for the PreTeXt XML format""" 12 | 13 | fileExtension = ".ptx" # noqa: N815 14 | 15 | def processFileContent(self, document: str, s: str) -> str: # noqa: N802 16 | s = _Renderer.processFileContent(self, document, s) 17 | 18 | # Remove empty paragraphs 19 | s = re.compile(r"

    \s*

    ", re.I).sub(r"", s) 20 | 21 | # Fix fancy quotes 22 | s = re.compile(r"“(.*?)”", re.I).sub(r"\1", s) 23 | s = re.compile(r"‘(.*?)’", re.I).sub(r"\1", s) 24 | 25 | # Fix strange apostrophes 26 | s = s.replace("’", "'") 27 | 28 | return s 29 | 30 | 31 | Renderer = Pretext 32 | 33 | 34 | def convert(input_file: Path, output: Path) -> None: 35 | log.info(f"Converting {input_file} to {output}") 36 | 37 | input_file_dir = input_file.parent 38 | 39 | def getLines(input_file: Path) -> str: # noqa: N802 40 | with open(input_file, "r") as f: 41 | lines = str() 42 | line = f.readline() 43 | while line: 44 | if line.strip().startswith("\\input{") or line.strip().startswith( 45 | "\\include{" 46 | ): 47 | inner_file = ( 48 | input_file_dir / line[line.find("{") + 1 : line.find("}")] 49 | ) 50 | # ensure inner_file has file extension: 51 | if not inner_file.suffix: 52 | inner_file = inner_file.with_suffix(".tex") 53 | log.debug(f"Adding .tex extension to {inner_file}") 54 | lines = lines + "\n" + getLines(inner_file) + "\n" 55 | else: 56 | lines += line 57 | line = f.readline() 58 | return lines 59 | 60 | tex = TeX() 61 | tex.input(getLines(input_file)) 62 | doc = tex.parse() 63 | log.debug("Done reading input file.") 64 | 65 | tex.ownerDocument.config["files"]["split-level"] = 1 66 | tex.ownerDocument.config["files"][ 67 | "filename" 68 | ] = "main $name-[$id, $title, $ref, sect$num(4)]" 69 | # Disable image generation 70 | tex.ownerDocument.config["images"]["enabled"] = "no" 71 | tex.ownerDocument.config["images"]["imager"] = "none" 72 | tex.ownerDocument.config["images"]["vector-imager"] = "none" 73 | 74 | renderer = Renderer() 75 | renderer.render(doc) 76 | 77 | # shutil.move('test.xml', output) 78 | log.info("\nConversion complete") 79 | -------------------------------------------------------------------------------- /pretext/plastex/babel.jinja2s: -------------------------------------------------------------------------------- 1 | name: foreignlanguage otherlanguage 2 | {{ obj }} 3 | 4 | -------------------------------------------------------------------------------- /pretext/plastex/graphicx.jinja2s: -------------------------------------------------------------------------------- 1 | name: includegraphics rotatebox scalebox reflectbox resizebox 2 | {% set image = obj.image %} 3 | 4 | 5 | {{ obj.source }} 6 | 7 | 8 | 9 | name: DeclareGraphicsExtensions graphicspath 10 | -------------------------------------------------------------------------------- /pretext/plastex/hyperref.jinja2s: -------------------------------------------------------------------------------- 1 | name: href 2 | {{ obj }} 3 | 4 | name: url 5 | 6 | 7 | name: nolinkurl 8 | {{ obj.attributes.url }} 9 | 10 | 11 | name: hyperimage 12 | 13 | 14 | name: hyperdef 15 | 16 | 17 | name: hyperref 18 | 19 | 20 | name: hyperlink 21 | 22 | 23 | name: hypertarget 24 | 25 | 26 | name: phantomsection 27 | 28 | 29 | -------------------------------------------------------------------------------- /pretext/plastex/lipsum.jinja2s: -------------------------------------------------------------------------------- 1 | name:lipsum 2 | {{ obj.text }} 3 | -------------------------------------------------------------------------------- /pretext/plastex/longtable.jinja2s: -------------------------------------------------------------------------------- 1 | name: longtable 2 | 3 | {% if obj.title %} 4 | {{ obj.title }} 5 | {% endif %} 6 | 7 | {% for row in obj %} 8 | 9 | {% for cell in row %} 10 | 11 | {% endfor %} 12 | 13 | {% endfor %} 14 | 15 |
    16 | -------------------------------------------------------------------------------- /pretext/plastex/math.jinja2s: -------------------------------------------------------------------------------- 1 | name: math ensuremath 2 | {{ obj.mathjax_source[2:-2].replace(" _","_").replace(" ^","^") }}{# -#} 3 | 4 | name: displaymath equation* eqnarray eqnarray* align align* gather gather* flalign flalign* multline multline* alignat alignat* split 5 | 6 | {{ obj.mathjax_source[2:-2].replace(" _","_").replace(" ^","^") }} 7 | 8 | 9 | name: equation 10 | 11 | {{ obj.mathjax_source[2:-2].replace(" _","_").replace(" ^","^") }} 12 | -------------------------------------------------------------------------------- /pretext/plastex/misc.jinja2s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/pretext/plastex/misc.jinja2s -------------------------------------------------------------------------------- /pretext/plastex/natbib.jinja2s: -------------------------------------------------------------------------------- 1 | name: cite citet citep citealt citealp citeauthor citeyear citeyearpar \ 2 | Cite Citet Citep Citealt Citealp Citeauthor citefullauthor citetalias \ 3 | citepalias 4 | 5 | 6 | name: citetext 7 | {{ obj }} 8 | 9 | name: newblock nocite defcitealias 10 | -------------------------------------------------------------------------------- /pretext/plastex/p.jinja2s: -------------------------------------------------------------------------------- 1 | name: par 2 | {% if obj.blockType %} 3 | {{ obj }} 4 | {% else %} 5 |

    6 | {{ obj }} 7 |

    8 | {% endif %} -------------------------------------------------------------------------------- /pretext/plastex/subfig.jinja2s: -------------------------------------------------------------------------------- 1 | name: subfloat subfig subfigure subtable 2 | 19 | 20 | name: subref subref* 21 | 26 | 27 | 28 | name: newsubfloat DeclareCaptionListOfFormat listsubcaptions captionsetup clearcaptionsetup ContinuedFloat 29 | -------------------------------------------------------------------------------- /pretext/plastex/textcomp.jinja2s: -------------------------------------------------------------------------------- 1 | name: newtie capitaltie capitaldieresis capitalbreve capitalnewtie \ 2 | capitalgrave capitaldotaccent capitalcedilla 3 | alias: . 4 | -------------------------------------------------------------------------------- /pretext/plastex/tikzcd.jinja2: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ obj.source|e }} 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /pretext/plastex/tikzpicture.jinja2: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ obj.source|e }} 4 | 5 | 6 | -------------------------------------------------------------------------------- /pretext/plastex/url.jinja2s: -------------------------------------------------------------------------------- 1 | name: url path 2 | 3 | 4 | name: email 5 | {{ obj.attributes.url }} 6 | 7 | 8 | name: urldef urlstyle DeclareUrlCommand 9 | -------------------------------------------------------------------------------- /pretext/plastex/wrapfig.jinja2s: -------------------------------------------------------------------------------- 1 | name: wrapfigure wraptable 2 | 3 | -------------------------------------------------------------------------------- /pretext/project/xml.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import shutil 3 | import typing as t 4 | from enum import Enum 5 | from pydantic import ConfigDict 6 | import pydantic_xml as pxml 7 | from pydantic_xml.element.element import SearchMode 8 | 9 | 10 | # To prevent circular imports, put this here instead of in `__init__`; however, it's not used in this file. 11 | class Executables(pxml.BaseXmlModel, tag="executables"): 12 | model_config = ConfigDict(extra="forbid") 13 | latex: str = pxml.attr(default="latex") 14 | pdflatex: str = pxml.attr(default="pdflatex") 15 | xelatex: str = pxml.attr(default="xelatex") 16 | pdfsvg: t.Optional[str] = pxml.attr(default="pdf2svg") 17 | # If not specified, use a local executable if it exists; if it doesn't exist, choose `None`, which allows the generation logic to use the server instead. 18 | asy: t.Optional[str] = pxml.attr(default=shutil.which("asy")) 19 | # No sage server, so we don't do the same for sage. 20 | sage: t.Optional[str] = pxml.attr(default="sage") 21 | mermaid: str = pxml.attr(default="mmdc") 22 | pdfpng: t.Optional[str] = pxml.attr(default="convert") 23 | pdfeps: str = pxml.attr(default="pdftops") 24 | node: str = pxml.attr(default="node") 25 | liblouis: str = pxml.attr(default="file2brl") 26 | 27 | 28 | class LegacyFormat(str, Enum): 29 | HTML = "html" 30 | HTML_ZIP = "html-zip" 31 | LATEX = "latex" 32 | PDF = "pdf" 33 | EPUB = "epub" 34 | KINDLE = "kindle" 35 | BRAILLE_ELECTRONIC = "braille-electronic" 36 | BRAILLE_EMBOSS = "braille-emboss" 37 | WEBWORK = "webwork-sets" 38 | WEBWORK_ZIPPED = "webwork-sets-zipped" 39 | CUSTOM = "custom" 40 | 41 | 42 | class LatexEngine(str, Enum): 43 | XELATEX = "xelatex" 44 | LATEX = "latex" 45 | PDFLATEX = "pdflatex" 46 | 47 | 48 | class LegacyStringParam(pxml.BaseXmlModel): 49 | model_config = ConfigDict() 50 | key: str = pxml.attr() 51 | value: str = pxml.attr() 52 | 53 | 54 | class LegacyTarget(pxml.BaseXmlModel, tag="target", search_mode=SearchMode.UNORDERED): 55 | model_config = ConfigDict(str_strip_whitespace=True) 56 | name: str = pxml.attr() 57 | latex_engine: t.Optional[LatexEngine] = pxml.attr(name="pdf-method", default=None) 58 | format: LegacyFormat = pxml.element() 59 | source: str = pxml.element() 60 | publication: str = pxml.element() 61 | output_dir: Path = pxml.element(tag="output-dir") 62 | output_filename: t.Optional[str] = pxml.element(tag="output-filename", default=None) 63 | # The v1 file called this `deploy-dir`; the v2 file uses `site`. 64 | deploy_dir: t.Optional[str] = pxml.element(tag="deploy-dir", default=None) 65 | xsl: t.Optional[str] = pxml.element(default=None) 66 | asy_method: t.Optional[str] = pxml.element(tag="asy-method", default="server") 67 | stringparams: t.List[LegacyStringParam] = pxml.element( 68 | tag="stringparam", default=[] 69 | ) 70 | 71 | 72 | class LegacyExecutables( 73 | pxml.BaseXmlModel, tag="executables", search_mode=SearchMode.UNORDERED 74 | ): 75 | model_config = ConfigDict(str_strip_whitespace=True) 76 | latex: str = pxml.element() 77 | pdflatex: str = pxml.element() 78 | xelatex: str = pxml.element() 79 | pdfsvg: t.Optional[str] = pxml.element(default=None) 80 | asy: str = pxml.element() 81 | sage: str = pxml.element() 82 | pdfpng: t.Optional[str] = pxml.element(default=None) 83 | pdfeps: str = pxml.element() 84 | node: str = pxml.element() 85 | liblouis: str = pxml.element() 86 | 87 | 88 | class LegacyProject(pxml.BaseXmlModel, tag="project", search_mode=SearchMode.UNORDERED): 89 | model_config = ConfigDict() 90 | targets: t.List[LegacyTarget] = pxml.wrapped("targets", pxml.element(tag="target")) 91 | executables: LegacyExecutables = pxml.element() 92 | -------------------------------------------------------------------------------- /pretext/resources/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib.resources 2 | import json 3 | import logging 4 | from pathlib import Path 5 | import shutil 6 | import zipfile 7 | 8 | from .. import VERSION, CORE_COMMIT 9 | 10 | log = logging.getLogger("ptxlogger") 11 | 12 | _RESOURCE_BASE_PATH = Path.home() / ".ptx" / VERSION 13 | 14 | 15 | def install(reinstall: bool = False) -> None: 16 | if _RESOURCE_BASE_PATH.exists(): 17 | if reinstall: 18 | log.info(f"Deleting existing resources at {_RESOURCE_BASE_PATH}") 19 | shutil.rmtree(_RESOURCE_BASE_PATH) 20 | else: 21 | log.warning(f"Resources are already installed at {_RESOURCE_BASE_PATH}") 22 | return 23 | _RESOURCE_BASE_PATH.mkdir(parents=True) 24 | 25 | log.info("Installing core resources") 26 | with importlib.resources.path("pretext.resources", "core.zip") as static_zip: 27 | with zipfile.ZipFile(static_zip, "r") as zip: 28 | zip.extractall(path=_RESOURCE_BASE_PATH) 29 | (_RESOURCE_BASE_PATH / f"pretext-{CORE_COMMIT}").rename( 30 | _RESOURCE_BASE_PATH / "core" 31 | ) 32 | 33 | log.info("Installing templates") 34 | (_RESOURCE_BASE_PATH / "templates").mkdir() 35 | with importlib.resources.path("pretext.resources", "templates.zip") as static_zip: 36 | with zipfile.ZipFile(static_zip, "r") as zip: 37 | zip.extractall(path=_RESOURCE_BASE_PATH / "templates") 38 | shutil.copy2( 39 | _RESOURCE_BASE_PATH / "templates" / "standalone-project.ptx", 40 | _RESOURCE_BASE_PATH / "project.ptx", 41 | ) 42 | shutil.copy2( 43 | _RESOURCE_BASE_PATH / "templates" / "standalone-publication.ptx", 44 | _RESOURCE_BASE_PATH / "publication.ptx", 45 | ) 46 | 47 | log.info("Installing rs_cache files") 48 | (_RESOURCE_BASE_PATH / "rs_cache").mkdir() 49 | with importlib.resources.path("pretext.resources", "rs_cache.zip") as static_zip: 50 | with zipfile.ZipFile(static_zip, "r") as zip: 51 | zip.extractall(path=_RESOURCE_BASE_PATH / "rs_cache") 52 | 53 | log.info("Installing pelican files") 54 | (_RESOURCE_BASE_PATH / "pelican").mkdir() 55 | with importlib.resources.path("pretext.resources", "pelican.zip") as static_zip: 56 | with zipfile.ZipFile(static_zip, "r") as zip: 57 | zip.extractall(path=_RESOURCE_BASE_PATH / "pelican") 58 | 59 | 60 | def resource_base_path() -> Path: 61 | if not _RESOURCE_BASE_PATH.exists(): 62 | log.info(f"Installing resources to {_RESOURCE_BASE_PATH}") 63 | install() 64 | return _RESOURCE_BASE_PATH 65 | 66 | 67 | def get_resource_hash_table() -> dict: 68 | with importlib.resources.path( 69 | "pretext.resources", "resource_hash_table.json" 70 | ) as hash_table: 71 | return json.load(hash_table.open()) 72 | -------------------------------------------------------------------------------- /pretext/types.py: -------------------------------------------------------------------------------- 1 | import typing as t 2 | 3 | # AssetTable is a dictionary of asset types mapped to dictionaries of xml:ids to hashes of the source of that xml:id. 4 | AssetTable = t.Dict[str, str] 5 | -------------------------------------------------------------------------------- /schema/README.md: -------------------------------------------------------------------------------- 1 | This directory will contain the RelaxNG schema for the project manifest `project.ptx`. 2 | 3 | There are two versions, a compact syntax (`.rnc`) and XML (`.rng`). Edits should be made to the `.rnc` file which can then be converted to the `.rng` version using [trang](https://github.com/relaxng/jing-trang) via 4 | ``` 5 | > trang project-ptx.rnc project-ptx.rng 6 | ``` 7 | 8 | You can then use [jing](https://github.com/relaxng/jing-trang) to test 9 | whether a `project.ptx` file conforms to the schema. 10 | ``` 11 | > jing project-ptx.rng path/to/project.ptx 12 | ``` 13 | 14 | If you are running these commands directly from Java `.jar` files, you will 15 | instead run 16 | ``` 17 | > java -jar path/to/jing.jar [...other arguments...] 18 | ``` -------------------------------------------------------------------------------- /schema/project-ptx.rnc: -------------------------------------------------------------------------------- 1 | # Relax-ng grammar for `project.ptx` files. 2 | # To use this grammar, it must first be converted from 3 | # "compact" form (the `.rnc` file) into XML (the `.rng` file). 4 | # This conversion is accomplished with [trang](https://github.com/relaxng/jing-trang) via 5 | # ``` 6 | # > trang project-ptx.rnc project-ptx.rng 7 | # ``` 8 | # You can then use [jing](https://github.com/relaxng/jing-trang) to test 9 | # whether a `project.ptx` file conforms to the schema. 10 | # ``` 11 | # > jing project-ptx.rng path/to/project.ptx 12 | # ``` 13 | # 14 | # If you are running these commands directly from Java `.jar` files, you will 15 | # instead run 16 | # ``` 17 | # > java -jar path/to/jing.jar [...other arguments...] 18 | # ``` 19 | 20 | grammar { 21 | 22 | start = Project 23 | 24 | Project = element project { 25 | ProjectReqAttributes, 26 | ProjectOptAttributes, 27 | Targets 28 | } 29 | 30 | ProjectReqAttributes = attribute ptx-version { "2" } 31 | 32 | ProjectOptAttributes = ( 33 | attribute source { text }?, 34 | attribute publication { text }?, 35 | attribute output-dir { text }?, 36 | attribute site {text}?, 37 | attribute xsl { text }?, 38 | attribute asy-method { "server" | "local" }? 39 | ) 40 | 41 | Targets = element targets { Target+ } 42 | 43 | Target = element target { 44 | ## Unique identifier for this build target. This is the name you pass on the 45 | ## command line when building via the `pretext` CLI. 46 | attribute name { text }, 47 | ## the required format can be `html`, `pdf`, `latex`, `epub`, `kindle`, `braille`, `revealjs`, `webwork`, or `custom`. 48 | ( 49 | HtmlAttributes 50 | | PdfAttributes 51 | | LatexAttributes 52 | | EpubAttributes 53 | | BrailleAttributes 54 | | RevealjsAttributes 55 | | WebworkAttributes 56 | | CustomAttributes 57 | ), 58 | CommonAttributes, 59 | ## Parameters that get passed directly to the XSL processing backend. 60 | ## These parameters are rarely used by content authors. 61 | Stringparams* 62 | } 63 | 64 | CommonAttributes = ( 65 | attribute source { text }?, 66 | attribute publication { text }?, 67 | attribute output-dir { text }?, 68 | attribute deploy-dir { text }?, 69 | attribute site {text}?, 70 | attribute xsl { text }?, 71 | attribute asy-method { "server" | "local" }?, 72 | attribute standalone { "yes" | "no" }? 73 | ) 74 | 75 | HtmlAttributes = ( 76 | attribute format { "html" }, 77 | (attribute platform { "runestone" }? 78 | | (attribute compression { "zip" | "scorm" }?, 79 | attribute output-filename { text }?)) 80 | ) 81 | 82 | PdfAttributes = ( 83 | attribute format { "pdf" }, 84 | attribute latex-engine { "xelatex" | "pdflatex" | "latex" }?, 85 | attribute output-filename { text }? 86 | ) 87 | 88 | LatexAttributes = ( 89 | attribute format { "latex" }, 90 | attribute output-filename { text }? 91 | ) 92 | 93 | EpubAttributes = ( 94 | attribute format { "epub"|"kindle" }, 95 | attribute output-filename { text }? 96 | ) 97 | 98 | BrailleAttributes = ( 99 | attribute format { "braille" }, 100 | attribute braille-mode { "emboss" | "electronic" }? 101 | ) 102 | 103 | RevealjsAttributes = ( 104 | attribute format { "revealjs" }, 105 | attribute output-filename { text }? 106 | ) 107 | 108 | WebworkAttributes = ( 109 | attribute format { "webwork" }, 110 | attribute compression { "zip" }? 111 | ) 112 | 113 | CustomAttributes = ( 114 | attribute format { "custom" } 115 | ) 116 | 117 | 118 | Stringparams = element stringparams { 119 | # Attributes are the name of the string-param and the value is the value of the string-param. 120 | attribute debug.datedfiles {"yes"|"no"}?, 121 | attribute debug.mathjax4 { "yes" | "no" }?, 122 | attribute debug.react.local { "yes" | "no" }?, 123 | attribute debug.react.global { "yes" | "no" }?, 124 | attribute debug.html.annotate { "yes" | "no" }?, 125 | attribute debug.skip-knowls { "yes" | "no" }?, 126 | attribute author.tools { "yes" | "no" }?, 127 | attribute html.css.extra { text }? 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/scripts/__init__.py -------------------------------------------------------------------------------- /scripts/build_package.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import fetch_core 4 | 5 | 6 | def main() -> None: 7 | import pretext 8 | 9 | arguments = sys.argv[1:] 10 | print(f"Building package for version {pretext.VERSION}.") 11 | # ensure up-to-date "static" resources 12 | fetch_core.main(arguments) 13 | 14 | # Build package 15 | subprocess.run(["poetry", "build"], shell=True) 16 | print("Completed poetry build of pretext") 17 | 18 | 19 | if __name__ == "__main__": 20 | main() 21 | -------------------------------------------------------------------------------- /scripts/bundle_resources.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import shutil 3 | import re 4 | import json 5 | from pathlib import Path 6 | from pretext import VERSION 7 | from pretext.constants import PROJECT_RESOURCES 8 | 9 | 10 | def resource_hashes() -> None: 11 | # Load current hash table 12 | if (Path("pretext") / "resources" / "resource_hash_table.json").exists(): 13 | with open(Path("pretext") / "resources" / "resource_hash_table.json", "r") as f: 14 | saved_hash_table = json.load(f) 15 | print( 16 | f"Loaded hash table from {Path('pretext') / 'resources' / 'resource_hash_table.json'}" 17 | ) 18 | else: 19 | saved_hash_table = {} 20 | # Set up a dictionary for the hash of this version's files: 21 | resource_hash_table = {} 22 | # Update version generation dates in project resources 23 | for resource in PROJECT_RESOURCES: 24 | if resource == "requirements.txt": 25 | # Special case: requirements.txt is not a template 26 | continue 27 | with open(Path("templates") / resource, "r") as f: 28 | lines = f.readlines() 29 | with open(Path("templates") / resource, "w") as f: 30 | for line in lines: 31 | if "This file was automatically generated" in line: 32 | # replace the version number with {VERSION}: 33 | new_line = re.sub( 34 | r"PreTeXt \d+\.\d+\.\d+", f"PreTeXt {VERSION}", line 35 | ) 36 | f.write(new_line) 37 | else: 38 | f.write(line) 39 | # Now hash the updated file to add to a hash-table for this version 40 | with open(Path("templates") / resource, "rb") as f: 41 | # Create SHA256 hash of file contents 42 | sha256_hash = hashlib.sha256() 43 | # Read the file and update the hash 44 | sha256_hash.update(f.read()) 45 | resource_hash_table[resource] = sha256_hash.hexdigest() 46 | 47 | # Finally update the hash table and save it 48 | saved_hash_table[VERSION] = resource_hash_table 49 | with open(Path("pretext") / "resources" / "resource_hash_table.json", "w") as f: 50 | json.dump(saved_hash_table, f, indent=2) 51 | print( 52 | f"Hash table saved to {Path('pretext') / 'resources' / 'resource_hash_table.json'}" 53 | ) 54 | 55 | 56 | def main() -> None: 57 | # Take care of boilerplate files and their hashes 58 | resource_hashes() 59 | 60 | # Zip the templates and pelican resources 61 | shutil.make_archive( 62 | str(Path("pretext") / "resources" / "templates"), "zip", Path("templates") 63 | ) 64 | print("Templates successfully zipped.") 65 | shutil.make_archive( 66 | str(Path("pretext") / "resources" / "pelican"), "zip", Path("pelican") 67 | ) 68 | print("Pelican resources successfully zipped.") 69 | 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /scripts/copy_cdn_files.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from pathlib import Path 4 | import tarfile 5 | import shutil 6 | import tempfile 7 | import zipfile 8 | 9 | from pretext import CORE_COMMIT 10 | 11 | import fetch_core 12 | 13 | 14 | def main(args=None) -> None: 15 | if args: 16 | dist_path = Path(args[0]).resolve() 17 | print(f"Using dist location as: {args}") 18 | else: 19 | dist_path = Path("dist").resolve() 20 | 21 | static_dir = dist_path / "_static" 22 | # Make the _static directory inside dist_path if it doesn't exist 23 | if not static_dir.exists(): 24 | os.makedirs(static_dir) 25 | 26 | # run fetch_core 27 | fetch_core.main() 28 | 29 | with tempfile.TemporaryDirectory(prefix="ptxcli_") as tmpdirname: 30 | # expand rs_services.zip 31 | with zipfile.ZipFile( 32 | Path("pretext").resolve() / "resources" / "rs_cache.zip", "r" 33 | ) as zip_ref: 34 | zip_ref.extractall(tmpdirname) 35 | # expand core.zip 36 | with zipfile.ZipFile( 37 | Path("pretext").resolve() / "resources" / "core.zip", "r" 38 | ) as zip_ref: 39 | zip_ref.extractall(tmpdirname) 40 | 41 | # Find dist-* file inside "rs_cache" directory 42 | rs_cache_dir = Path(tmpdirname) 43 | rs_cache_files = os.listdir(rs_cache_dir) 44 | rs_cache_files = [f for f in rs_cache_files if f.startswith("dist-")] 45 | if len(rs_cache_files) == 0: 46 | raise FileNotFoundError("No dist-* file found in rs_cache directory.") 47 | elif len(rs_cache_files) > 1: 48 | raise FileNotFoundError( 49 | "Multiple dist-* files found in rs_cache directory." 50 | ) 51 | rs_cache_file = rs_cache_files[0] 52 | 53 | # expand tarfile and place in _static directory 54 | with tarfile.open(Path(tmpdirname) / rs_cache_file, "r") as tgz_ref: 55 | tgz_ref.extractall(static_dir, filter="fully_trusted") 56 | shutil.copy2( 57 | Path(tmpdirname) / "runestone_services.xml", 58 | static_dir / "runestone_services.xml", 59 | ) 60 | 61 | # copy core files to _static directory 62 | shutil.copytree( 63 | Path(tmpdirname) / f"pretext-{CORE_COMMIT}" / "css" / "dist", 64 | static_dir / "pretext" / "css", 65 | dirs_exist_ok=True, 66 | ) 67 | shutil.copytree( 68 | Path(tmpdirname) / f"pretext-{CORE_COMMIT}" / "js", 69 | static_dir / "pretext" / "js", 70 | dirs_exist_ok=True, 71 | ) 72 | shutil.copytree( 73 | Path(tmpdirname) / f"pretext-{CORE_COMMIT}" / "js_lib", 74 | static_dir / "pretext" / "js" / "lib", 75 | dirs_exist_ok=True, 76 | ) 77 | 78 | 79 | if __name__ == "__main__": 80 | main(sys.argv[1:]) 81 | -------------------------------------------------------------------------------- /scripts/fetch_core_commit.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from urllib.request import urlopen 3 | import json 4 | from datetime import datetime 5 | import fileinput 6 | from typing import Any, Dict 7 | 8 | 9 | def commit_data(repo: str) -> Dict[str, Any]: 10 | """ 11 | Returns a dictionary containing the date and commit sha from the most recent commit to `repo` 12 | """ 13 | lastcommit = {} 14 | url = f"https://api.github.com/repos/pretextbook/{repo}/commits" 15 | response = urlopen(url) 16 | data = json.loads(response.read()) 17 | lastcommit["date"] = datetime.strptime( 18 | data[0]["commit"]["committer"]["date"], "%Y-%m-%dT%H:%M:%SZ" 19 | ) 20 | lastcommit["sha"] = data[0]["sha"] 21 | return lastcommit 22 | 23 | 24 | def main() -> None: 25 | last_core_commit = commit_data("pretext") 26 | 27 | # Update core commit: 28 | for line in fileinput.input( 29 | Path(__file__).parent.parent / "pretext/__init__.py", inplace=True 30 | ): 31 | if "CORE_COMMIT" in line: 32 | print( 33 | line.replace( 34 | line, f"CORE_COMMIT = \"{last_core_commit['sha']}\"".rstrip() 35 | ) 36 | ) 37 | else: 38 | print(line.rstrip()) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /scripts/prep_nightly.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import sys 3 | from urllib.request import urlopen 4 | import json 5 | from datetime import datetime 6 | import fileinput 7 | from typing import Any, Dict 8 | 9 | 10 | def commit_data(repo: str) -> Dict[str, Any]: 11 | lastcommit = {} 12 | url = f"https://api.github.com/repos/pretextbook/{repo}/commits" 13 | response = urlopen(url) 14 | data = json.loads(response.read()) 15 | lastcommit["date"] = datetime.strptime( 16 | data[0]["commit"]["committer"]["date"], "%Y-%m-%dT%H:%M:%SZ" 17 | ) 18 | lastcommit["sha"] = data[0]["sha"] 19 | return lastcommit 20 | 21 | 22 | def should_release(coredate: datetime, clidate: datetime) -> bool: 23 | if (datetime.now() - coredate).days < 1: 24 | print( 25 | f"There has been an update to core pretext in the last 24 hours, at {coredate}" 26 | ) 27 | return True 28 | elif (datetime.now() - clidate).days < 1: 29 | print(f"There has been an update to the CLI in the last 24 hours, at {clidate}") 30 | return True 31 | else: 32 | return False 33 | 34 | 35 | def main(args: str = None) -> None: 36 | last_core_commit = commit_data("pretext") 37 | last_cli_commit = commit_data("pretext-cli") 38 | 39 | # Check to see if there is nothing new to build and stop script if so. 40 | if not (should_release(last_core_commit["date"], last_cli_commit["date"])): 41 | print( 42 | "No recent commits to pretext core or the CLI. No nightly will be built." 43 | ) 44 | return 45 | 46 | # Update core commit (temporarily): 47 | for line in fileinput.input( 48 | Path(__file__).parent.parent / "pretext/__init__.py", inplace=True 49 | ): 50 | if "CORE_COMMIT" in line: 51 | print( 52 | line.replace( 53 | line, f"CORE_COMMIT = '{last_core_commit['sha']}'".rstrip() 54 | ) 55 | ) 56 | else: 57 | print(line.rstrip()) 58 | 59 | # Update version (temporarily) in pyproject.toml: 60 | for line in fileinput.input( 61 | Path(__file__).parent.parent / "pyproject.toml", inplace=True 62 | ): 63 | if line.startswith("version"): 64 | version = str(line.split('"')[1]) 65 | newversion = version + ".dev" + datetime.now().strftime("%Y%m%d%H%M%S") 66 | print(line.replace(line, f'version = "{newversion}"'.rstrip())) 67 | else: 68 | print(line.rstrip()) 69 | 70 | # Need to wait to import build_package until now so it gets the updated version CORE_COMMIT and version. 71 | import build_package 72 | 73 | build_package.main() 74 | print("Ready to deploy") 75 | 76 | 77 | if __name__ == "__main__": 78 | main(sys.argv[1:]) 79 | -------------------------------------------------------------------------------- /scripts/symlink_core.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | import pretext.resources 4 | from scripts import utils 5 | 6 | 7 | # This will redirect the static resources for pretext, including the core python script, xsl, css, etc to a local directory of your choosing that contains the clone of the pretext repository. This is useful for development purposes, as it allows you to make changes to the core python script and test with the CLI as you normally would. 8 | def main(core_path: Path = Path("../pretext")) -> None: 9 | # ensure resources are installed 10 | pretext.resources.install() 11 | core_path = core_path.resolve() 12 | link_path = pretext.resources.resource_base_path() / "core" 13 | # Remove the current link or directory 14 | utils.remove_path(link_path) 15 | # Create a symlink to the core directory 16 | link_path.symlink_to(core_path) 17 | 18 | # Remove the current pretext/core/pretext.py file 19 | script_link_path = Path("pretext").resolve() / "core" / "pretext.py" 20 | script_core_path = core_path / "pretext" / "lib" / "pretext.py" 21 | utils.remove_path(script_link_path) 22 | # Link to the local core python script 23 | script_link_path.symlink_to(script_core_path) 24 | 25 | # Repeat for braille_format the current pretext/core/pretext.py file 26 | script_link_path = Path("pretext").resolve() / "core" / "braille_format.py" 27 | script_core_path = core_path / "pretext" / "lib" / "braille_format.py" 28 | utils.remove_path(script_link_path) 29 | # Link to the local core python script 30 | script_link_path.symlink_to(script_core_path) 31 | print(f"Linked local core pretext directory `{core_path}`") 32 | 33 | 34 | if __name__ == "__main__": 35 | try: 36 | core_path = Path(sys.argv[1]) 37 | except IndexError: 38 | core_path = Path("../pretext") 39 | main(core_path) 40 | -------------------------------------------------------------------------------- /scripts/tag_counter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import re 4 | 5 | 6 | # Simple utility for finding all pretext elements (tags) in an inputed project and reporting their frequency 7 | def main(project_path) -> None: 8 | tag_counts = {} 9 | 10 | # Walk through the directory and subdirectories 11 | for root, _, files in os.walk(project_path): 12 | for file in files: 13 | if file.endswith((".xml", ".ptx")) and not file.startswith("."): 14 | file_path = os.path.join(root, file) 15 | try: 16 | with open(file_path, "r", encoding="utf-8") as f: 17 | content = f.read() 18 | # Count tags in the file 19 | for line in content.splitlines(): 20 | line = line.strip() 21 | tags = re.findall(r"<([\w\-]+)", line) 22 | for tag in tags: 23 | tag_counts[tag] = tag_counts.get(tag, 0) + 1 24 | except Exception as e: 25 | print(f"Error reading file {file_path}: {e}") 26 | 27 | # Print the tag counts 28 | for tag, count in sorted( 29 | tag_counts.items(), key=lambda item: item[1], reverse=True 30 | ): 31 | print(f"{tag}: {count}") 32 | 33 | 34 | if __name__ == "__main__": 35 | if len(sys.argv) != 2: 36 | print("Usage: python tag_counter.py ") 37 | sys.exit(1) 38 | file_path = sys.argv[1] 39 | main(file_path) 40 | -------------------------------------------------------------------------------- /scripts/unlink_core.py: -------------------------------------------------------------------------------- 1 | import pretext.resources 2 | from scripts import fetch_core, utils 3 | 4 | 5 | # Restore the original core directory and reinstall core resources into home/.ptx appropriately 6 | def main() -> None: 7 | link_path = pretext.resources.resource_base_path() / "core" 8 | utils.remove_path(link_path) 9 | 10 | # fetch core resources to replace the symlinked core pretext script 11 | fetch_core.main() 12 | print("Restored original core directory and reinstalled core resources.") 13 | pretext.resources.install(reinstall=True) 14 | print("Finished unlinking core resources.") 15 | 16 | 17 | if __name__ == "__main__": 18 | main() 19 | -------------------------------------------------------------------------------- /scripts/update_changelog.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pretext import CORE_COMMIT 4 | from pretext import VERSION 5 | 6 | 7 | def main() -> None: 8 | insert_lines = [ 9 | "\n", 10 | f"## [{VERSION}] - {date.today()}\n", 11 | "\n", 12 | f"Includes updates to core through commit: [{CORE_COMMIT[:7]}](https://github.com/PreTeXtBook/pretext/commit/{CORE_COMMIT})\n", 13 | ] 14 | 15 | new_changelog = [] 16 | with open("CHANGELOG.md", "r") as f: 17 | # Read entire file into a list of lines 18 | changelog = f.readlines() 19 | for line in changelog: 20 | if line.startswith("## [Unreleased]"): 21 | new_changelog.append("## [Unreleased]\n") 22 | new_changelog += insert_lines 23 | else: 24 | new_changelog.append(line) 25 | with open("CHANGELOG.md", "w") as f: 26 | f.writelines(new_changelog) 27 | 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /scripts/utils.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | from pathlib import Path 3 | 4 | 5 | def remove_path(path: Path) -> None: 6 | if path.is_file() or path.is_symlink(): 7 | path.unlink() # remove the file 8 | elif path.is_dir(): 9 | shutil.rmtree(path) # remove dir and all it contains 10 | -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | # This file was automatically generated with PreTeXt 2.18.4. 2 | # If you modify this file, PreTeXt will no longer automatically update it. 3 | # 4 | # Boilerplate list of files in a PreTeXt project for git to ignore 5 | # ensure this file is tracked 6 | !.gitignore 7 | 8 | # don't track unpublished builds or stage (note: Runestone uses `published`) 9 | output 10 | published 11 | 12 | # don't track assets generated from source 13 | generated-assets 14 | .cache 15 | 16 | # don't track the executables.ptx file 17 | executables.ptx 18 | 19 | # don't track node packages 20 | node_modules 21 | 22 | # don't track error logs 23 | .error_schema.log 24 | logs 25 | 26 | # don't track OS related files (windows/macos/linux) 27 | .DS_Store 28 | .DS_Store? 29 | ._* 30 | .AppleDouble 31 | .LSOverride 32 | .Spotlight-V100 33 | .Trashes 34 | Icon 35 | .AppleDB 36 | .AppleDesktop 37 | Network Trash Folder 38 | Temporary Items 39 | .apdisk 40 | Thumbs.db 41 | Thumbs.db:encryptable 42 | ehthumbs.db 43 | ehthumbs_vista.db 44 | *.stackdump 45 | *.lnk 46 | *.cab 47 | *.msi 48 | *.msix 49 | *.msm 50 | *.msp 51 | [Dd]esktop.ini 52 | .directory 53 | .fuse_hidden* 54 | .Trash-* 55 | .nfs* 56 | 57 | # Don't include VSCode generated files 58 | .vscode 59 | *.code-workspace 60 | 61 | # Don't inlucde SublimeText files 62 | # Cache files for Sublime Text 63 | *.tmlanguage.cache 64 | *.tmPreferences.cache 65 | *.stTheme.cache 66 | 67 | # Workspace files are user-specific 68 | *.sublime-workspace 69 | 70 | # Project files should be checked into the repository, unless a significant 71 | # proportion of contributors will probably not be using Sublime Text 72 | *.sublime-project 73 | 74 | # SFTP configuration file 75 | sftp-config.json 76 | sftp-config-alt*.json 77 | 78 | # Package control specific files 79 | Package Control.last-run 80 | Package Control.ca-list 81 | Package Control.ca-bundle 82 | Package Control.system-ca-bundle 83 | Package Control.cache/ 84 | Package Control.ca-certs/ 85 | Package Control.merged-ca-bundle 86 | Package Control.user-ca-bundle 87 | oscrypto-ca-bundle.crt 88 | bh_unicode_properties.cache 89 | 90 | # Sublime-github package stores a github token in this file 91 | # https://packagecontrol.io/packages/sublime-github 92 | GitHub.sublime-settings 93 | 94 | # Don't track common virtual environment directories 95 | venv/ 96 | 97 | # Don't include Dropbox settings and caches 98 | .dropbox 99 | .dropbox.attr 100 | .dropbox.cache 101 | 102 | # Don't track codechat config (will be generated automatically) 103 | codechat_config.yaml 104 | 105 | # Don't track deprecated workflows 106 | .github/workflows/deploy.yml 107 | .github/workflows/test-build.yml 108 | -------------------------------------------------------------------------------- /templates/article/assets/frog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/templates/article/assets/frog.jpg -------------------------------------------------------------------------------- /templates/article/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/article/source/frontmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Author X. Lastname 6 | 7 | 8 | 9 | 10 |

    11 | This is the abstract. 12 |

    13 |
    14 |
    15 | 16 | -------------------------------------------------------------------------------- /templates/article/source/introduction.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    Some words before the first section of the paper

    4 |

    Some more words.

    5 |
    6 | -------------------------------------------------------------------------------- /templates/article/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | authorslastnamelowercase-ShortTitleCamelCase 7 | 8 | \newcommand{\foo}{b^{ar}} 9 | \usepackage{tikz} 10 | 11 | 12 |
    13 | The title of my groundbreaking paper 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 | 22 |
    23 | -------------------------------------------------------------------------------- /templates/article/source/section-1.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | My First Section 4 | 5 |

    Some words

    6 |
    7 | 8 | My First Subsection 9 |

    Some more words

    10 |

    foo

    11 |
    12 | A frog 13 | 14 | A nice-looking frog with a longish description. 15 | 16 |
    17 |

    Bar: \foo

    18 |
    19 |
    20 | -------------------------------------------------------------------------------- /templates/article/source/section-2.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | My Additional Section 4 |

    foo

    5 |
    6 | The graph C_5 made by TikZ 7 | 8 | A 5-cycle 9 | \begin{tikzpicture} \coordinate (A) at (90+360/5:1); \coordinate (B) at (90+2*360/5:1); \coordinate (C) at (90+3*360/5:1); \coordinate (D) at (90+4*360/5:1); \coordinate (E) at (90:1); \draw (A) -- (B) -- (C) -- (D) -- (E) -- (A); \foreach \x in {(A), (B), (C), (D), (E)}{ \fill \x circle (2pt); } \end{tikzpicture} 10 | 11 |
    12 |

    bar

    13 |
    14 | -------------------------------------------------------------------------------- /templates/book/README.md: -------------------------------------------------------------------------------- 1 | # My PreTeXt Book 2 | 3 | This README was generated by running `pretext new book`. You should feel free to edit this to describe your project. 4 | 5 | 6 | The main source file is `source/main.ptx`. This includes the other chapters of the book. 7 | 8 | To compile the book as an accessible website, run `pretext build web` in a terminal from any directory of this project. 9 | 10 | To preview your output, run `pretext view web`. 11 | 12 | To deploy your output to GitHub pages, run `pretext deploy`. 13 | 14 | To compile a pdf, run `pretext build print`. 15 | 16 | --- 17 | 18 | Below you will find some advice for working with PreTeXt, including help with using the [PreTeXt Codespace](https://github.com/PreTeXtBook/pretext-codespace) online editor through GitHub if you don't want to install the required software on your own computer. 19 | 20 | 21 | ## Learning PreTeXt 22 | 23 | See the [PreTeXt documentation](https://pretextbook.org/documentation.html) for links to a variety of resources. 24 | 25 | We also recommend browsing through the [annotated sample article](https://pretextbook.org/examples/sample-article/annotated) and [annotated sample book](https://pretextbook.org/examples/sample-book/annotated/) if you want to find examples and see the PreTeXt source for those examples quickly. 26 | 27 | ## Using GitHub Codespaces 28 | 29 | GitHub Codespaces are a way to set up your whole authoring system entirely in your browser. In case you are not already reading this inside a codespace, you can create one specifically designed for authoring in PreTeXt by using [this template](https://github.com/PreTeXtBook/pretext-codespace). 30 | 31 | ### Important: how to save your files 32 | 33 | The most important thing to remember when authoring in a codespace is that you are making all your edits on a *virtual machine* off in some remote server farm. This means there is an extra step to save your files. You can save files in the editor (in your browser), but this just saves them to that virtual machine. To make sure you can access these files, even if the virtual machine goes away, you need to sync them to github.com. This is done by *committing* your changes and then *pushing* those commits (or "syncing" them). You might see a warning when you restart your codespace that you have "uncommitted changes" -- make sure you commit them when you are done working. 34 | 35 | ### Troubleshooting: Latex-images and pdfs 36 | 37 | We have tried to keep the codespace small (so it starts up quickly and doesn't eat through your monthly storage allotment), so we do not include a full TeXLive distribution. We have tried to include most packages and fonts you are likely to need to generate images using `` elements, and to generate PDF print output. However, if you run into a situation where the LaTeX gives errors about packages missing (like it cannot find a `mypackage.sty` file), here is what you should do. 38 | 39 | 1. To quickly resolve the issue yourself, open a terminal (``Ctrl+Shift+` ``) and use the TeXLive Package Manager to install the missing package. 40 | a. If you know that the package is called `mypackage` then enter the following two lines: 41 | 42 | ```bash 43 | tlmgr install mypackage 44 | tlmgr path add 45 | ``` 46 | b. If you don't know the name of the package, but know it should contain `mypackage.sty`, then you can search using 47 | 48 | ```bash 49 | tlmgr search --global --all "mypackage.sty" 50 | ``` 51 | 52 | 2. To ensure that you don't have to repeat this step every time you recreate the codespace, add the package name to the list of installs inside the file `.devcontainer/installLatex.sh` which gets run every time a codespace is created. 53 | 54 | 3. Better yet, post the name of the missing package to this [GitHub issue](https://github.com/PreTeXtBook/pretext-codespace/issues/21) and we will add it to the devcontainer. This has the advantage that you will still get updates that other authors submit (if you edit the `installLatex.sh` file, then it won't be updated when you run `pretext update`). 55 | 56 | ### Troubleshooting: sageplot images 57 | 58 | By far the largest space-hog in a PreTeXt authoring environment is SageMath, which is only required if you generate images using sageplots. By default, SageMath is not installed in a PreTeXt codespace, but it should be easy to install if you need it. 59 | 60 | Just open the command palette (`Ctrl+Shift+P` of `F1`) and search for "PreTeXt: Install SageMath". This will also update the `.devcontainer/devcontainer.json` file so that the next time you create a codespace for this project, it should install automatically. -------------------------------------------------------------------------------- /templates/book/source/backmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Backmatter 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

    This book was authored in .

    21 |
    22 |
    23 | 24 | -------------------------------------------------------------------------------- /templates/book/source/ch-chapter-title.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Chapter Title 5 | 6 | 7 |

    Text before the first section.

    8 |
    9 | 10 | 11 | 12 | 13 |
    -------------------------------------------------------------------------------- /templates/book/source/docinfo.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | changeme 9 | 10 | A simple string (no markup is allowed) to describe your book. 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | \newcommand{\N}{\mathbb N} \newcommand{\Z}{\mathbb Z} \newcommand{\Q}{\mathbb Q} \newcommand{\R}{\mathbb R} 23 | 24 | 25 | 26 | \usepackage{tikz, pgfplots} \usetikzlibrary{positioning,matrix,arrows} \usetikzlibrary{shapes,decorations,shadows,fadings,patterns} \usetikzlibrary{decorations.markings} 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/book/source/frontmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | You 11 | Your department 12 | Your institution 13 | 14 | 15 | 16 | 17 | 18 | 19 | My Website 20 | 21 | 22 | 23 | 20202024 24 | You 25 | This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit CreativeCommons.org 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /templates/book/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | My Great Book 9 | An example to get you started 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /templates/book/source/sec-section-name.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Section Title 5 | 6 |

    Text of section.

    7 | 8 |
    -------------------------------------------------------------------------------- /templates/codechat_config.yaml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated with PreTeXt 2.18.4. 2 | # If you modify this file, PreTeXt will no longer automatically update it. 3 | # 4 | ############################################################# 5 | # 6 | # This file allows the use of the CodeChat previewer for PreTeXt. 7 | # Generally, there is no need to modify this file. 8 | # It will be automatically generated by PreTeXt with the latest 9 | # updates unless you remove the first comment line above. 10 | # 11 | ############################################################ 12 | # 13 | # .. Copyright (C) 2012-2023 Bryan A. Jones. 14 | # 15 | # This file is part of the CodeChat System. 16 | # 17 | # The CodeChat System is free software: you can redistribute it and/or 18 | # modify it under the terms of the GNU General Public License as 19 | # published by the Free Software Foundation, either version 3 of the 20 | # License, or (at your option) any later version. 21 | # 22 | # The CodeChat System is distributed in the hope that it will be 23 | # useful, but WITHOUT ANY WARRANTY; without even the implied warranty 24 | # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 | # General Public License for more details. 26 | # 27 | # You should have received a copy of the GNU General Public License 28 | # along with the CodeChat System. If not, see 29 | # . 30 | # 31 | # ************************************************ 32 | # |docname| - Configuration for a CodeChat project 33 | # ************************************************ 34 | # This file defines the configuration for a CodeChat project. It contains a working `PreTeXt `_ configuration. 35 | # 36 | # ``source_path``: optional; defaults to ``.`` (the current directory). A path to the root of the source tree. Relative paths are rooted in the directory containing this configuration file. 37 | source_path: source 38 | 39 | # ``output_path``: required. A path to the root of the HTML output produced by this renderer. Relative paths are rooted in the directory containing this configuration file. 40 | output_path: output/web 41 | 42 | # ``args``: required string or sequence of strings. This provides the arguments to invoke the renderer. These strings may optionally contain the following replacement values: 43 | # 44 | # - ``{project_path}``: an absolute path to the directory containing this file. 45 | # - ``{source_path}``: the ``source_path`` above, but as an absolute path. 46 | # - ``{output_path}``: the ``output_path`` above, but as an absolute path. 47 | # - ``{sys_executable}``: the value of the running Python's `sys.executable `_. 48 | # - ``{xml_id}``: The value of the the first ``xml:id`` attribute in the currently open file. 49 | args: "{sys_executable} -m pretext build web --xmlid {xml_id} --no-knowls" 50 | 51 | # ``html_ext``: optional; defaults to ``.html``. The extension used by this renderer when generating HTML files. 52 | #html_ext: .html 53 | 54 | # ``project_type``: optional; defaults to ``general``. Define the project type, which enables special processing based on the type. Valid values are ``general`` (no special processing), ``Doxygen``, and ``PreTeXt``. 55 | project_type: PreTeXt 56 | -------------------------------------------------------------------------------- /templates/course/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 10 | 12 | 13 | 15 | 17 | 18 | 20 | 22 | 23 | 24 | 25 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/course/source/activities.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 | In-Class Activities 6 | 7 | 8 | 9 |

    10 | These activities are designed to be used in class to help students understand the material. They are not graded, but students are encouraged to work on them in groups and ask the instructor for help when needed. 11 |

    12 |
    13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 |
    -------------------------------------------------------------------------------- /templates/course/source/activities/activity-template.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 | 6 | 7 | 8 | Activity Title 9 | 10 | 11 |

    12 | This is the introduction to the activity. 13 |

    14 |
    15 | 16 | 17 | 18 |

    19 | This is the first exercise. 20 |

    21 |
    22 |
    23 |
    24 |
    25 |
    26 | -------------------------------------------------------------------------------- /templates/course/source/activities/magic-beans.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 | 6 | Magic Beans 7 | 8 |

    9 | You have traded your cow for 5 magic chocolate covered espresso beans. 10 | Each night at midnight, each bean splits into three beans. 11 | To take advantage of this, you eat 8 beans each morning for breakfast. 12 | You wonder how many beans you will have after breakfast 30 days after you traded your cow. 13 |

    14 | 15 |

    16 | Let (b_n)_{n\ge 0} be the sequence of number of beans you have n days after trading your cow, (after breakfast, before midnight; take b_0 = 5). 17 |

    18 |
    19 | 20 | 21 | 22 | 23 | 24 |

    25 | Write out the first few terms of the sequence. 26 | Then give a recursive definition for the sequence and explain how you know it is correct. 27 |

    28 |
    29 |
    30 | 31 | 32 | 33 |

    34 | What do you notice about all elements of the sequence? Will they all be ...? Prove your conjecture by mathematical induction. 35 |

    36 |
    37 |
    38 |
    39 | 40 | 41 | 42 | 43 | 44 |

    45 | Find a closed formula for b_n and prove it is correct using induction. 46 |

    47 |
    48 |
    49 |
    50 |
    51 | 52 | 53 |
    54 |
    -------------------------------------------------------------------------------- /templates/course/source/docinfo.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | \newcommand{\N}{\mathbb N} 22 | \newcommand{\Z}{\mathbb Z} 23 | \newcommand{\Q}{\mathbb Q} 24 | \newcommand{\R}{\mathbb R} 25 | 26 | 27 | 28 | 29 | 30 | \usepackage{tikz, pgfplots} 31 | \usetikzlibrary{positioning,matrix,arrows} 32 | \usetikzlibrary{shapes,decorations,shadows,fadings,patterns} 33 | \usetikzlibrary{decorations.markings} 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /templates/course/source/frontmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Instructor Lastname 10 | Mathematical Sciences 11 | University of Templates 12 | 13 | 14 | Last Updated: 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /templates/course/source/notes.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 | Course Notes 6 | 7 | 8 |

    9 | The following notes are intended to remind you what we covered each week. They are not a substitute for attending class and not a substitute for reading the textbook. 10 |

    11 |
    12 | 13 | 14 | 15 | 16 | 17 |
    18 |
    -------------------------------------------------------------------------------- /templates/course/source/notes/week01.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
    6 | Week 1 7 |

    8 | This week we covered the following topics: 9 |

    10 | 11 |
    12 |
    13 |
    -------------------------------------------------------------------------------- /templates/course/source/notes/week02.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
    6 | Week 2 7 |

    8 | This week we covered the following topics in the second week. 9 |

    10 | 11 |
    12 |
    13 |
    -------------------------------------------------------------------------------- /templates/demo/assets/frog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/templates/demo/assets/frog.jpg -------------------------------------------------------------------------------- /templates/demo/assets/jsxgraph/infinity.js: -------------------------------------------------------------------------------- 1 | /* http://jsxgraph.uni-bayreuth.de/showcase/infinity.html */ 2 | /* Accessed January 2017 */ 3 | 4 | JXG.Options.renderer = 'canvas'; 5 | var board = JXG.JSXGraph.initBoard('jsxgraph-infinity', { 6 | boundingbox: [-9, 8, 9, -10], 7 | keepaspectreatio: true, 8 | axis: false, 9 | grid: false, 10 | shownavigation: false 11 | }); 12 | 13 | // construction 14 | board.suspendUpdate(); 15 | var S = board.create('slider', [[-5,-6],[5,-6],[0,0.85,1]], { 16 | name:'Whirl' 17 | }); 18 | var hue = board.create('slider', [[-5,-7],[5,-7],[0,20.5,36]], { 19 | name:'Colors' 20 | }); 21 | 22 | var points = new Array(); 23 | points[0] = board.create('point',[5, 5], {name:' '}); 24 | points[1] = board.create('point',[-5, 5], {name:' '}); 25 | points[2] = board.create('point',[-5, -5], {name:' '}); 26 | points[3] = board.create('point',[5, -5], {name:' '}); 27 | 28 | function quadrangle(pt, n) { 29 | var col; 30 | var arr = new Array(); 31 | for(var i = 0; i < 4; i++) { 32 | arr[i] = board.create('point', 33 | [function(t) { 34 | return function () {var x = pt[t].X(); 35 | var x1 = pt[(t+1)%4].X(); 36 | var s = S.Value(); 37 | return x+(x1-x)*s; 38 | }}(i), 39 | function(t) { 40 | return function () {var y = pt[t].Y(); 41 | var y1 = pt[(t+1)%4].Y(); 42 | var s = S.Value(); 43 | return y+(y1-y)*s; 44 | }}(i) 45 | ], 46 | {size:1, name: "", withLabel: false, visible: false}); 47 | } 48 | col = function(){return JXG.hsv2rgb(hue.Value()*n,0.7,0.9);}; 49 | board.create('polygon',pt, {fillColor:col}); 50 | if(n>0) 51 | quadrangle(arr, --n); 52 | } 53 | quadrangle(points,30); 54 | 55 | board.unsuspendUpdate(); -------------------------------------------------------------------------------- /templates/demo/source/backmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Backmatter 10 | 11 | 12 | Selected Hints 13 | 14 | 15 | 16 | Selected Solutions 17 | 18 | 19 | 20 | List of Symbols 21 | 22 | 23 | 24 | 25 | Index 26 | 27 | 28 | 29 | 30 |

    31 | This book was authored in . 32 |

    33 |
    34 |
    35 | 36 | -------------------------------------------------------------------------------- /templates/demo/source/ch-empty.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | (No title) 5 |

    Try adding your own content here! This chapter doesn't have sections.

    6 |
    7 | -------------------------------------------------------------------------------- /templates/demo/source/ch-features.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Features 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/demo/source/ch-first with spaces.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | My First Chapter 9 | 10 | 11 | 12 |

    This is the introduction to the chapter

    13 |
    14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
    25 | -------------------------------------------------------------------------------- /templates/demo/source/ch-generate.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | <pretext /> features that require generation 4 | 5 |

    6 | Here we demonstrate various kinds of assets. 7 |

    8 |
    9 | 10 |
    11 | LaTeX-Image Example 12 | 13 |
    14 | 15 |
    16 | SagePlot Examples 17 | 18 | 19 |
    20 | 21 |
    22 | Asymptote Example 23 | 24 |
    25 | 26 |
    27 | <webwork /> Example 28 | 29 | 30 | 31 |
    32 | 33 |
    34 | MyOpenMath 35 | 36 | 37 |

    38 | Here is a problem from MyOpenMath. 39 |

    40 |
    41 | 42 |
    43 |
    44 | 45 |
    46 | YouTube Example 47 |
    49 | 50 |
    51 | Interactive Example 52 | 53 |
    54 | Infinity, from the JSXGraph Showcase 55 | 57 | 58 | 59 |

    60 | Drag the sliders to change the pattern, and drag any of the four red corners to change 61 | the overall shape. 62 |

    63 |
    64 |
    65 |
    66 |
    67 | 68 |
    69 | Codelens 70 | Example 71 | 72 | Finding primes 73 | 74 | 98 | 99 | 100 |
    101 |
    102 | -------------------------------------------------------------------------------- /templates/demo/source/docinfo.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | changeme 17 | 23 | 24 | A simple string (no markup is allowed) to describe your book. 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | \newcommand{\N}{\mathbb N} 38 | \newcommand{\Z}{\mathbb Z} 39 | \newcommand{\Q}{\mathbb Q} 40 | \newcommand{\R}{\mathbb R} 41 | 42 | 43 | 44 | 45 | 46 | \usepackage{tikz, pgfplots} 47 | \usetikzlibrary{positioning,matrix,arrows} 48 | \usetikzlibrary{shapes,decorations,shadows,fadings,patterns} 49 | \usetikzlibrary{decorations.markings} 50 | 51 | 52 | 53 | Puzzle 54 | Summary 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /templates/demo/source/ex-first.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My Exercises 6 | 7 | 8 | 9 |

    10 | Is this an exercise? 11 |

    12 |
    13 | 14 |

    15 | Yes. 16 |

    17 |
    18 | 19 |

    20 | It is, but not a very good one. 21 |

    22 |
    23 |
    24 | 25 | 26 |

    27 | Another, with a hint. 28 |

    29 |
    30 | 31 |

    32 | The hint. 33 |

    34 |
    35 |
    36 | 37 | 38 | 39 | 67 | 68 |
    69 | 70 | -------------------------------------------------------------------------------- /templates/demo/source/fig-asymptote.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | Canada 4 | 5 | Image of a Canadian flag 6 | 7 | 8 |
    -------------------------------------------------------------------------------- /templates/demo/source/fig-sage2d.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | The parabola y=x^2 made by SageMath 4 | 5 | A parabola 6 | 7 | 8 |
    -------------------------------------------------------------------------------- /templates/demo/source/fig-sage3d.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | The paraboloid z=x^2+y^2 made by SageMath 4 | 5 | A paraboloid 6 | 7 | 8 |
    -------------------------------------------------------------------------------- /templates/demo/source/fig-tikz.ptx: -------------------------------------------------------------------------------- 1 | 2 |
    3 | The graph C_5 made by TikZ 4 | 5 | A 5-cycle 6 | 7 | 8 | 9 | 10 |
    11 | -------------------------------------------------------------------------------- /templates/demo/source/frontmatter.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Me 10 | My department 11 | My school 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | My Website 20 | 21 | 22 | 23 | 24 | 25 | 26 | 20202022 27 | Me 28 | 29 | 30 | 31 | This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. 32 | To view a copy of this license, visit 33 | 36 | CreativeCommons.org 37 | 38 | 39 | 40 | 41 | 42 | 43 |

    44 | For ... 45 |

    46 |
    47 | 48 | 49 |

    50 | I would like to thank... 51 |

    52 |
    53 | 54 | 55 | 56 | 57 |

    58 | About this book: 59 |

    60 |
    61 | 62 | 63 | 64 | Not just that.. 65 |

    66 | I still have more to say! 67 |

    68 |
    69 | 70 |
    71 | 72 | -------------------------------------------------------------------------------- /templates/demo/source/images/cflag.asy: -------------------------------------------------------------------------------- 1 | size(4cm,6cm); 2 | pen canadared=rgb(235/256,45/256,55/256); 3 | real flagwidth=4, flagheight=2; 4 | path flag_outline=scale(flagwidth,flagheight)*unitsquare; 5 | path cbar1=scale(1,2)*unitsquare, cbar2=shift(3,0)*cbar1; 6 | path mapleleafleft= 7 | (0,-102) --(-5,-102)--(-2,-56) {dir(87)}..{dir(190)} 8 | (-8,-53) --(-51,-61)--(-45,-45){dir(70)}..{dir(141)} 9 | (-46,-41)--(-94,-3) --(-82,1) {dir(25)}..{dir(108)} 10 | (-81,6) --(-90,34) --(-63,29) {dir(348)}..{dir(67)} 11 | (-59,30) --(-54,43) --(-33,20) {dir(313)}..{dir(101)} 12 | (-27,23) --(-38,76) --(-21,62) {dir(330)}..{dir(63)} 13 | (-16,67) --(0,100); 14 | path mapleleafright=reflect((0,0),(0,1))*reverse(mapleleafleft); 15 | path mapleleaf=mapleleafleft--mapleleafright--cycle; 16 | filldraw(flag_outline,white,black); 17 | fill(cbar1,canadared); 18 | fill(cbar2,canadared); 19 | fill(shift(2,1)*scale(.008)*mapleleaf,canadared); 20 | draw(flag_outline); 21 | -------------------------------------------------------------------------------- /templates/demo/source/images/sageplot2d.sage: -------------------------------------------------------------------------------- 1 | plot(x^2) 2 | -------------------------------------------------------------------------------- /templates/demo/source/images/sageplot3d.sage: -------------------------------------------------------------------------------- 1 | x,y = var('x y') 2 | plot3d(x^2+y^2,(x,-1,1),(y,-1,1), frame=False, color='purple', opacity=0.8) 3 | -------------------------------------------------------------------------------- /templates/demo/source/images/tikz.tex: -------------------------------------------------------------------------------- 1 | \begin{tikzpicture} 2 | \coordinate (A) at (90+360/5:1); 3 | \coordinate (B) at (90+2*360/5:1); 4 | \coordinate (C) at (90+3*360/5:1); 5 | \coordinate (D) at (90+4*360/5:1); 6 | \coordinate (E) at (90:1); 7 | 8 | \draw (A) -- (B) -- (C) -- (D) -- (E) -- (A); 9 | \foreach \x in {(A), (B), (C), (D), (E)}{ 10 | \fill \x circle (2pt); 11 | } 12 | \end{tikzpicture} 13 | -------------------------------------------------------------------------------- /templates/demo/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | My Demo Book 18 | An demo of PreTeXt features 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /templates/demo/source/sec-features.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Environments and Blocks 5 |

    Some text

    6 | 7 | My Theorem 8 | 9 | 10 |

    11 | Theorem statement. 12 |

    13 |
    14 | 15 |

    16 | Proof of theorem. 17 |

    18 |
    19 |
    20 | 21 | 22 | 23 |

    24 | Statement of example 25 |

    26 |
    27 | 28 |

    29 | The solution. 30 |

    31 |
    32 |
    33 |

    34 | Now a figure. 35 |

    36 |
    37 | A frog 38 | 39 | A nice-looking frog with a longish 40 | description. 41 | 42 |
    43 |
    44 | -------------------------------------------------------------------------------- /templates/demo/source/sec-first-examples.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Examples 5 | 6 |

    7 | Here is an example: 8 |

    9 | 10 | 11 | 12 |

    13 | The statement of the example, since it will have a solution. What is the solution? 14 |

    15 |
    16 | 17 |

    18 | This is the solution. 19 |

    20 |
    21 |
    22 | 23 |

    24 | Here is another example, but without a solution 25 |

    26 | 27 | 28 |

    29 | This is an example of an example without a solution (or hint or answer) so the paragraph doesn't need to be inside a statement tag. 30 |

    31 |
    32 | 33 |

    34 | Although the next things are not examples, they give examples of blocks that are not examples. First a theorem. 35 |

    36 | 37 | 38 | Theorem Title 39 | 40 |

    41 | This is the statement of the theorem. 42 |

    43 |
    44 | 45 |

    46 | And this is its proof. 47 |

    48 |
    49 |
    50 | 51 | 52 | 53 |

    54 | A corollary that doesn't need a proof. 55 |

    56 |
    57 |
    58 | 59 |

    60 | Perhaps at the end of the section, you want to add a note to the reader about how what you have fits into the larger scope of mathematics. 61 |

    62 | 63 | 64 | Larger Context 65 |

    66 | Comment to the reader here. 67 |

    68 |
    69 | 70 |

    71 | Of course, if you want more information, you might see . 72 |

    73 |
    74 | 75 | -------------------------------------------------------------------------------- /templates/demo/source/sec-first-intro.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Introduction to First Chapter 5 | 6 |

    7 | Intro to section, because we will have subsections. 8 |

    9 |

    10 | Another paragraph of the introduction. 11 |

    12 |
    13 | 14 | A subsection 15 |

    16 | Content of the subsection. 17 |

    18 |

    19 | More content. 20 |

    21 |
    22 | 23 | 24 | Another Subsection 25 |

    26 | Text with some math: \sin(x) = \cos(x) only for some values of x. 27 |

    28 |
    29 | 30 | 31 |

    32 | After the last subsection, you might have a conclusion. 33 |

    34 |
    35 |
    36 | 37 | -------------------------------------------------------------------------------- /templates/demo/source/ww.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $a = Compute(random(1, 9, 1)); 5 | $b = Compute(random(1, 9, 1)); 6 | $c = $a + $b; 7 | 8 | 9 |

    Compute the sum of 10 | 11 | and 12 | 13 | :

    14 |

    15 | + = 16 | 17 |

    18 |
    19 | 20 |

    Add 21 | 22 | and 23 | 24 | together.

    25 |
    26 | 27 |

    + = .

    28 |
    29 |
    -------------------------------------------------------------------------------- /templates/devcontainer.json: -------------------------------------------------------------------------------- 1 | // This file was automatically generated with PreTeXt 2.18.4. 2 | // If you modify this file, PreTeXt will no longer automatically update it. 3 | // 4 | ////////////////////////////////////////////////////////////// 5 | // 6 | // This file provides configuration options so that a PreTeXt 7 | // project can be edited and built using GitHub's Codespaces. 8 | // It is recommended to keep this in your repository even if you 9 | // do not use this feature, as it will allow other to explore 10 | // your project easily. 11 | // This file will be automatically generated by PreTeXt with the 12 | // latest updates unless you remove the first comment line above. 13 | // 14 | /////////////////////////////////////////////////////////////// 15 | { 16 | "image": "mcr.microsoft.com/devcontainers/universal:2", 17 | "features": {}, 18 | 19 | // Comment or uncomment lines below if you don't or do need that feature. 20 | "postCreateCommand": { 21 | // "install sagemath": "bash ./.devcontainer/installSage.sh", 22 | "install pandoc": "bash ./.devcontainer/installPandoc.sh", 23 | "install latex": "bash ./.devcontainer/installLatex.sh", 24 | "install pretext": "bash ./.devcontainer/installPretext.sh", 25 | "mark repo as safe": "git config --global --add safe.directory $(pwd)" 26 | }, 27 | 28 | 29 | // Port forwarding 30 | // --------------- 31 | // This is needed by the CodeChat Server. 32 | "forwardPorts": [ 33 | // The port used for a Thrift connection between the VSCode CodeChat 34 | // extension and the CodeChat Server. 35 | 27376, 36 | // The port used for an HTTP connection from the CodeChat Client to 37 | // the CodeChat Server. 38 | 27377, 39 | // The port used by a websocket connection between the CodeChat 40 | // Server and the CodeChat Client. 41 | 27378 42 | ], 43 | // See the [docs](https://containers.dev/implementors/json_reference/#port-attributes). 44 | "portsAttributes": { 45 | "27376": { 46 | "label": "VSCode extension <-> CodeChat Server", 47 | "requireLocalPort": true 48 | }, 49 | "27377": { 50 | "label": "CodeChat Client", 51 | "requireLocalPort": true 52 | }, 53 | "27378": { 54 | "label": "CodeChat Client<->Server websocket", 55 | "requireLocalPort": true 56 | // This port needs to be public; however, there's no way to specify port visibility here. See `server.py` in the CodeChat Server for details. 57 | } 58 | }, 59 | 60 | 61 | // Configure tool-specific properties. 62 | "customizations": { 63 | "codespaces": { 64 | "openFiles": ["source/main.ptx"] 65 | }, 66 | "vscode": { 67 | "settings": { 68 | "editor.quickSuggestions": { 69 | "other": "off" 70 | }, 71 | "files.autoSave": "onFocusChange", 72 | "editor.snippetSuggestions": "bottom", 73 | "xml.validation.enabled": true, 74 | "redhat.telemetry.enabled": false, 75 | "CodeChat.CodeChatServer.Command": "CodeChat_Server" 76 | }, 77 | "extensions": [ 78 | "oscarlevin.pretext-tools", 79 | "CodeChat.codechat", 80 | "streetsidesoftware.code-spell-checker", 81 | "alpinebuster.vscode-latex-table-editor" 82 | ] 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /templates/hello/README.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 | Open `source/main.ptx` to edit your PreTeXt document. 4 | -------------------------------------------------------------------------------- /templates/hello/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/hello/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |

    This is a PreTeXt document.

    6 |
    7 |
    8 | -------------------------------------------------------------------------------- /templates/installLatex.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file was automatically generated with PreTeXt 2.18.4. 4 | # If you modify this file, PreTeXt will no longer automatically update it. 5 | 6 | # We use TinyTeX (https://yihui.org/tinytex/) 7 | wget -qO- "https://yihui.org/tinytex/install-bin-unix.sh" | sh 8 | 9 | tlmgr install adjustbox amscdx bold-extra braket bussproofs cancel carlisle cases chessfss circuitikz colortbl enumitem extpfeil fontawesome5 fontaxes gensymb imakeidx jknapltx kastrup lambda-lists listings listingsutf8 makeindex marvosym mathalpha mathtools menukeys mhchem microtype musicography newpx newtx nicematrix pdfcol pdfpages pdflscape pgfplots phaistos physics polyglossia pstricks realscripts relsize siunitx skak skaknew smartdiagram snapshot stmaryrd tcolorbox tikz-cd tikzfill titlesec txfonts ulem upquote was xfrac xltxtra xpatch xstring 10 | 11 | tlmgr path add 12 | 13 | # Ensure fonts provided by TinyTeX are available, as suggested in the pretext guide 14 | fontconfig=" 15 | 16 | 17 | ~/.TinyTeX/texmf-dist/fonts 18 | ~/.TinyTeX/texmf-local/fonts 19 | " 20 | 21 | fontconfig_path="/etc/fonts/conf.d/09-texlive-fonts.conf" 22 | if [ ! -f "$fontconfig_path" ]; then 23 | echo "Creating fontconfig file at $fontconfig_path" 24 | echo "$fontconfig" | sudo tee "$fontconfig_path" > /dev/null 25 | else 26 | echo "Fontconfig file already exists at $fontconfig_path" 27 | fi 28 | # Update font cache 29 | fc-cache -f -v 30 | -------------------------------------------------------------------------------- /templates/installPandoc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file was automatically generated with PreTeXt 2.18.4. 4 | # If you modify this file, PreTeXt will no longer automatically update it. 5 | 6 | wget https://github.com/jgm/pandoc/releases/download/3.6.4/pandoc-3.6.4-1-amd64.deb -O pandoc.deb 7 | 8 | # wait for 60 second and then double check that no other script is using apt-get: 9 | sleep 60 10 | while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do 11 | echo "Waiting for apt-get to be free..." 12 | sleep 15 13 | done 14 | # Install pandoc 15 | sudo apt-get install -y --no-install-recommends ./pandoc.deb 16 | 17 | rm pandoc.deb 18 | -------------------------------------------------------------------------------- /templates/installPretext.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file was automatically generated with PreTeXt 2.18.4. 4 | # If you modify this file, PreTeXt will no longer automatically update it. 5 | 6 | sudo apt-get update 7 | sudo apt-get install -y --no-install-recommends \ 8 | python3-louis \ 9 | libcairo2-dev \ 10 | librsvg2-bin 11 | 12 | pip install --upgrade pip --break-system-packages 13 | 14 | pip install pretext[homepage,prefigure] pycairo --only-binary {greenlet} --break-system-packages 15 | 16 | pip install codechat-server --break-system-packages 17 | 18 | playwright install-deps 19 | 20 | playwright install 21 | 22 | 23 | # echo '/usr/lib/python3/dist-packages' > /usr/local/lib/python3.8/dist-packages/louis.pth 24 | prefig init 25 | 26 | # Install mermaid for diagrams 27 | npm install -g @mermaid-js/mermaid-cli 28 | 29 | echo "PreTeXt installation complete." 30 | -------------------------------------------------------------------------------- /templates/installSage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file was automatically generated with PreTeXt 2.18.4. 4 | # If you modify this file, PreTeXt will no longer automatically update it. 5 | 6 | # Conda should already be installed in the codespace. We need to add the conda-forge channel 7 | 8 | conda config --add channels conda-forge 9 | conda config --set channel_priority strict 10 | 11 | # We don't want conda to open the base environment always: 12 | conda config --set auto_activate_base false 13 | 14 | # Now create a conda environment for sage (called sage): 15 | conda create --yes -n sage sage python=3.12 16 | 17 | conda init 18 | 19 | echo 'conda activate sage' >> ~/.bashrc 20 | 21 | source ~/.bashrc 22 | -------------------------------------------------------------------------------- /templates/pretext-cli.yml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated with PreTeXt 2.18.4. 2 | # If you modify this file, PreTeXt will no longer automatically update it. 3 | # 4 | # This workflow file can be used to automatically build a project and create 5 | # an artifact for deployment. It can also be used to deploy the project to 6 | # GitHub Pages or Cloudflare Pages. 7 | # 8 | # The workflow is triggered on pull requests or can be run manually. You can uncomment 9 | # the `push` event to have it run on pushes to the main branch as well. 10 | name: PreTeXt-CLI Actions 11 | on: 12 | # Runs on pull requests 13 | pull_request: 14 | branches: ["*"] 15 | ## Runs on pushes to main 16 | #push: 17 | # branches: ["main"] 18 | # Runs on demand 19 | workflow_dispatch: 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | container: oscarlevin/pretext:full 25 | 26 | steps: 27 | - name: Checkout source 28 | uses: actions/checkout@v4 29 | 30 | - name: install deps 31 | run: pip install -r requirements.txt 32 | 33 | - name: install local ptx files 34 | run: pretext --version 35 | 36 | - name: build deploy targets 37 | run: | 38 | version="$(pretext --version)" 39 | major="$(echo $version | cut -d '.' -f 1)" 40 | minor="$(echo $version | cut -d '.' -f 2)" 41 | if [ "$major" -ge 2 -a "$minor" -ge 5 ]; then 42 | echo "PreTeXt version is 2.5 or greater; using new build command" 43 | pretext build --deploys 44 | else 45 | echo "PreTeXt version is less than 2.5, using old build command" 46 | pretext build 47 | fi 48 | - name: stage deployment 49 | run: pretext deploy --stage-only 50 | 51 | - name: Bundle output/stage as artifact 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: deploy 55 | path: output/stage 56 | 57 | deploy-cloudflare: 58 | runs-on: ubuntu-latest 59 | needs: build 60 | if: vars.CLOUDFLARE_PROJECT_NAME != '' 61 | permissions: 62 | contents: read 63 | deployments: write 64 | 65 | steps: 66 | - name: Download artifact 67 | uses: actions/download-artifact@v4 68 | with: 69 | name: deploy 70 | path: deploy 71 | - name: Create 404.html 72 | run: echo "404 page not found" >> deploy/404.html 73 | - name: Publish to Cloudflare 74 | uses: cloudflare/pages-action@v1 75 | with: 76 | apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} 77 | accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 78 | projectName: ${{ vars.CLOUDFLARE_PROJECT_NAME }} 79 | gitHubToken: ${{ secrets.GITHUB_TOKEN }} 80 | branch: ${{ github.head_ref || github.ref_name }} 81 | directory: deploy 82 | 83 | deploy-ghpages: 84 | runs-on: ubuntu-latest 85 | needs: build 86 | if: vars.PTX_ENABLE_DEPLOY_GHPAGES == 'yes' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) 87 | permissions: 88 | contents: read 89 | pages: write 90 | id-token: write 91 | concurrency: 92 | group: "page" 93 | cancel-in-progress: false 94 | environment: 95 | name: github-pages 96 | url: ${{ steps.deployment.outputs.page_url }} 97 | steps: 98 | - name: Download website artifact 99 | uses: actions/download-artifact@v4 100 | with: 101 | name: deploy 102 | path: deploy 103 | - name: Setup GitHub Pages 104 | id: check 105 | uses: actions/configure-pages@v4 106 | - name: Upload artifact 107 | uses: actions/upload-pages-artifact@v3 108 | with: 109 | path: deploy 110 | - name: Deploy to Github Pages 111 | id: deployment 112 | uses: actions/deploy-pages@v4 113 | -------------------------------------------------------------------------------- /templates/pretext-deploy.yml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated with PreTeXt 2.18.4. 2 | # If you modify this file, PreTeXt will no longer automatically update it. 3 | # 4 | 5 | name: Build and Deploy 6 | on: 7 | # Currently, this workflow only runs when manually selected (the `workflow_dispatch` event). 8 | # If you would like it to run on other events, uncomment some of the lines below. 9 | 10 | # # Runs on pull requests 11 | # pull_request: 12 | # branches: ["*"] 13 | 14 | # # Runs on pushes to main 15 | # push: 16 | # branches: ["main"] 17 | 18 | # # Runs every day at 00:00 UTC 19 | # schedule: 20 | # - cron: '0 0 * * *' 21 | 22 | # Runs on demand 23 | workflow_dispatch: 24 | 25 | permissions: 26 | contents: write 27 | 28 | jobs: 29 | build-and-deploy: 30 | runs-on: ubuntu-latest 31 | container: oscarlevin/pretext:small 32 | 33 | steps: 34 | - name: Checkout source 35 | uses: actions/checkout@v4 36 | 37 | - name: add gh-cli 38 | run: | 39 | apt-get update 40 | apt-get install gh jq -y 41 | 42 | - name: setup git config 43 | run: | 44 | git config --global --add safe.directory $(pwd) 45 | git config user.name "${{ github.actor }} via GitHub Actions" 46 | git config user.email "${{ github.actor }}@github_actions.no_reply" 47 | 48 | - name: install deps 49 | run: pip install -r requirements.txt --break-system-packages 50 | 51 | - name: install local ptx files 52 | run: pretext --version 53 | 54 | - name: build deploy targets 55 | run: pretext build --deploys 56 | 57 | - name: run deploy 58 | run: pretext deploy --no-push 59 | 60 | - name: push gh-pages branch 61 | run: git push origin gh-pages --force 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | -------------------------------------------------------------------------------- /templates/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/slideshow/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /templates/slideshow/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /templates/standalone-project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/standalone-publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/tests/__init__.py -------------------------------------------------------------------------------- /tests/common.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import subprocess 3 | from typing import List 4 | 5 | EXAMPLES_DIR = Path(__file__).parent.resolve() / "examples" 6 | 7 | DEMO_MAPPING = { 8 | "source/main.ptx": ["my-demo-book"], 9 | "source/frontmatter.ptx": [ 10 | "frontmatter", 11 | "frontmatter-preface", 12 | ], 13 | "source/ch-first with spaces.ptx": ["ch-first-without-spaces"], 14 | "source/sec-first-intro.ptx": ["sec-first-intro"], 15 | "source/sec-first-examples.ptx": ["sec-first-examples"], 16 | "source/ex-first.ptx": ["ex-first"], 17 | "source/ch-empty.ptx": ["ch-empty"], 18 | "source/ch-features.ptx": ["ch-features"], 19 | "source/sec-features.ptx": ["sec-features-blocks"], 20 | "source/ch-generate.ptx": [ 21 | "ch-generate", 22 | "sec-latex-image", 23 | "sec-sageplot", 24 | "sec-asymptote", 25 | "sec-webwork", 26 | "sec-mom", 27 | "sec-youtube", 28 | "sec-interactive", 29 | "interactive-infinity", 30 | "sec-codelens", 31 | ], 32 | "source/backmatter.ptx": ["backmatter"], 33 | } 34 | 35 | 36 | # Return True if the given binary is installed and exits with a return code of 0; otherwise, return False. This provides an easy way to check that a given binary is installed. 37 | def check_installed( 38 | # The command to run to check that a given binary is installed; for example, `["python", "--version"]` would check that Python is installed. 39 | subprocess_args: List[str], 40 | ) -> bool: 41 | try: 42 | subprocess.run(subprocess_args, check=True) 43 | except Exception: 44 | return False 45 | return True 46 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-wwserver/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | html 11 | source/main.ptx 12 | publication/publication.ptx 13 | output/html 14 | 15 | 16 | latex 17 | source/main.ptx 18 | publication/publication.ptx 19 | output/latex 20 | 21 | 22 | pdf 23 | source/main.ptx 24 | publication/publication.ptx 25 | output/pdf 26 | 27 | 28 | 29 | latex 30 | pdflatex 31 | xelatex 32 | pdf2svg 33 | asy 34 | sage 35 | convert 36 | pdftops 37 | node 38 | file2brl 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-wwserver/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-wwserver/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |

    This is a PreTeXt document.

    6 | 7 | 8 | 9 | $a = Compute(random(1, 9, 1)); 10 | $b = Compute(random(1, 9, 1)); 11 | $c = $a + $b; 12 | 13 | 14 |

    15 | Compute the sum of and : 16 |

    17 |

    18 | + = 19 |

    20 |
    21 | 22 |

    23 | Add and together. 24 |

    25 |
    26 | 27 |

    28 | + = . 29 |

    30 |
    31 |
    32 |
    33 |
    34 |
    35 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-xsl/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | html 11 | source/main.ptx 12 | publication/publication.ptx 13 | output/test 14 | xsl/custom.xsl 15 | 16 | 17 | html 18 | source/main.ptx 19 | publication/publication.ptx 20 | output/test2 21 | xsl/custom2.xsl 22 | 23 | 24 | 25 | latex 26 | pdflatex 27 | xelatex 28 | pdf2svg 29 | asy 30 | sage 31 | convert 32 | pdftops 33 | node 34 | file2brl 35 | 36 | 37 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-xsl/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-xsl/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |

    This is a PreTeXt document.

    6 |
    7 |
    8 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-xsl/xsl/custom.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | %entities; 5 | ]> 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/custom-xsl/xsl/custom2.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | %entities; 5 | ]> 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/graphics/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/examples/projects/graphics/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/graphics/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Asymptote 6 | 7 | foo 8 | 9 | 10 | size(4cm,6cm); 11 | pen canadared=rgb(235/256,45/256,55/256); 12 | real flagwidth=4, flagheight=2; 13 | path flag_outline=scale(flagwidth,flagheight)*unitsquare; 14 | path cbar1=scale(1,2)*unitsquare, cbar2=shift(3,0)*cbar1; 15 | path mapleleafleft= 16 | (0,-102) --(-5,-102)--(-2,-56) {dir(87)}..{dir(190)} 17 | (-8,-53) --(-51,-61)--(-45,-45){dir(70)}..{dir(141)} 18 | (-46,-41)--(-94,-3) --(-82,1) {dir(25)}..{dir(108)} 19 | (-81,6) --(-90,34) --(-63,29) {dir(348)}..{dir(67)} 20 | (-59,30) --(-54,43) --(-33,20) {dir(313)}..{dir(101)} 21 | (-27,23) --(-38,76) --(-21,62) {dir(330)}..{dir(63)} 22 | (-16,67) --(0,100); 23 | path mapleleafright=reflect((0,0),(0,1))*reverse(mapleleafleft); 24 | path mapleleaf=mapleleafleft--mapleleafright--cycle; 25 | filldraw(flag_outline,white,black); 26 | fill(cbar1,canadared); 27 | fill(cbar2,canadared); 28 | fill(shift(2,1)*scale(.008)*mapleleaf,canadared); 29 | draw(flag_outline); 30 | 31 | 32 | 33 | 34 | 36 | 37 | f(t,y) = (y[1], -pi*y[0]-0.3*y[1]) 38 | 39 | 40 | 43 | 45 | 48 | 50 | x(t) 51 | x'(t) 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/examples/projects/interactive/.gitignore: -------------------------------------------------------------------------------- 1 | # Boilerplate list of files in a PreTeXt project for git to ignore 2 | # ensure this file is tracked 3 | !.gitignore 4 | 5 | # don't track unpublished builds 6 | output 7 | 8 | # don't track assets generated from source 9 | generated-assets 10 | 11 | # don't track node packages 12 | node_modules 13 | 14 | # don't track error logs 15 | .error_schema.log 16 | cli.log 17 | 18 | # don't track OS related files (windows/macos/linux) 19 | .DS_Store 20 | .DS_Store? 21 | ._* 22 | .AppleDouble 23 | .LSOverride 24 | .Spotlight-V100 25 | .Trashes 26 | Icon 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | Thumbs.db 33 | Thumbs.db:encryptable 34 | ehthumbs.db 35 | ehthumbs_vista.db 36 | *.stackdump 37 | *.lnk 38 | *.cab 39 | *.msi 40 | *.msix 41 | *.msm 42 | *.msp 43 | [Dd]esktop.ini 44 | .directory 45 | .fuse_hidden* 46 | .Trash-* 47 | .nfs* 48 | 49 | # Don't include VSCode generated files 50 | .vscode 51 | *.code-workspace 52 | 53 | # Don't inlucde SublimeText files 54 | # Cache files for Sublime Text 55 | *.tmlanguage.cache 56 | *.tmPreferences.cache 57 | *.stTheme.cache 58 | 59 | # Workspace files are user-specific 60 | *.sublime-workspace 61 | 62 | # Project files should be checked into the repository, unless a significant 63 | # proportion of contributors will probably not be using Sublime Text 64 | *.sublime-project 65 | 66 | # SFTP configuration file 67 | sftp-config.json 68 | sftp-config-alt*.json 69 | 70 | # Package control specific files 71 | Package Control.last-run 72 | Package Control.ca-list 73 | Package Control.ca-bundle 74 | Package Control.system-ca-bundle 75 | Package Control.cache/ 76 | Package Control.ca-certs/ 77 | Package Control.merged-ca-bundle 78 | Package Control.user-ca-bundle 79 | oscrypto-ca-bundle.crt 80 | bh_unicode_properties.cache 81 | 82 | # Sublime-github package stores a github token in this file 83 | # https://packagecontrol.io/packages/sublime-github 84 | GitHub.sublime-settings 85 | 86 | 87 | # Don't include Dropbox settings and caches 88 | .dropbox 89 | .dropbox.attr 90 | .dropbox.cache 91 | 92 | -------------------------------------------------------------------------------- /tests/examples/projects/interactive/assets/jsxgraph/infinity.js: -------------------------------------------------------------------------------- 1 | /* http://jsxgraph.uni-bayreuth.de/showcase/infinity.html */ 2 | /* Accessed January 2017 */ 3 | 4 | JXG.Options.renderer = 'canvas'; 5 | var board = JXG.JSXGraph.initBoard('jsxgraph-infinity', { 6 | boundingbox: [-9, 8, 9, -10], 7 | keepaspectreatio: true, 8 | axis: false, 9 | grid: false, 10 | shownavigation: false 11 | }); 12 | 13 | // construction 14 | board.suspendUpdate(); 15 | var S = board.create('slider', [[-5,-6],[5,-6],[0,0.85,1]], { 16 | name:'Whirl' 17 | }); 18 | var hue = board.create('slider', [[-5,-7],[5,-7],[0,20.5,36]], { 19 | name:'Colors' 20 | }); 21 | 22 | var points = new Array(); 23 | points[0] = board.create('point',[5, 5], {name:' '}); 24 | points[1] = board.create('point',[-5, 5], {name:' '}); 25 | points[2] = board.create('point',[-5, -5], {name:' '}); 26 | points[3] = board.create('point',[5, -5], {name:' '}); 27 | 28 | function quadrangle(pt, n) { 29 | var col; 30 | var arr = new Array(); 31 | for(var i = 0; i < 4; i++) { 32 | arr[i] = board.create('point', 33 | [function(t) { 34 | return function () {var x = pt[t].X(); 35 | var x1 = pt[(t+1)%4].X(); 36 | var s = S.Value(); 37 | return x+(x1-x)*s; 38 | }}(i), 39 | function(t) { 40 | return function () {var y = pt[t].Y(); 41 | var y1 = pt[(t+1)%4].Y(); 42 | var s = S.Value(); 43 | return y+(y1-y)*s; 44 | }}(i) 45 | ], 46 | {size:1, name: "", withLabel: false, visible: false}); 47 | } 48 | col = function(){return JXG.hsv2rgb(hue.Value()*n,0.7,0.9);}; 49 | board.create('polygon',pt, {fillColor:col}); 50 | if(n>0) 51 | quadrangle(arr, --n); 52 | } 53 | quadrangle(points,30); 54 | 55 | board.unsuspendUpdate(); -------------------------------------------------------------------------------- /tests/examples/projects/interactive/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | html 11 | source/main.ptx 12 | publication/publication.ptx 13 | output/html 14 | 15 | 16 | latex 17 | source/main.ptx 18 | publication/publication.ptx 19 | output/latex 20 | 21 | 22 | pdf 23 | source/main.ptx 24 | publication/publication.ptx 25 | output/pdf 26 | 27 | 28 | 29 | latex 30 | pdflatex 31 | xelatex 32 | pdf2svg 33 | asy 34 | sage 35 | convert 36 | pdftops 37 | node 38 | file2brl 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/examples/projects/interactive/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/interactive/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |

    This is a PreTeXt document.

    6 | 7 |
    8 | Infinity, from the JSXGraph Showcase 9 | 10 | 12 | 13 | 14 |

    Drag the sliders to change the pattern, and drag any of the four red corners to change 15 | the overall shape.

    16 |
    17 |
    18 |
    19 |
    20 |
    21 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/.gitignore: -------------------------------------------------------------------------------- 1 | generated-assets 2 | output -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/source/different-than-web.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |
    6 | It says foo 7 | 8 | it says foo 9 | bar 10 | 11 |
    12 |

    This is a PreTeXt document.

    13 |
    14 |
    15 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/source/same-as-web.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |
    6 | It says what goes before bar 7 | 8 | it says what goes before bar 9 | foo 10 | 11 |
    12 |

    This is a PreTeXt document.

    13 |
    14 |
    15 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/assets/source/web.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! 5 |

    This is a PreTeXt document.

    6 |
    7 | It says foo 8 | 9 | it says foo 10 | foo 11 | 12 |
    13 |
    14 |
    15 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | generated-stuff 3 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/customizations/silly.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | %entities; 5 | ]> 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/dont-touch/extras/print.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/dont-touch/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/executables.ptx: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/external-things/foo.txt: -------------------------------------------------------------------------------- 1 | bar 2 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/my-great-site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | hi mom 4 | 5 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/my_ptx_source/book.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! (web) 5 |
    6 | First 7 | 8 |
    9 |
    10 | Another 11 |

    Another

    12 |
    13 |
    14 |
    15 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/my_ptx_source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Hello World! (print) 5 | 6 |
    7 |
    8 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/my_ptx_source/para.ptx: -------------------------------------------------------------------------------- 1 | 2 |

    This is a PreTeXt document.

    3 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/elaborate/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/legacy/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | pdflatex 7 | xelatex 8 | asy 9 | sage 10 | convert 11 | pdftops 12 | node 13 | foobar 14 | 15 | latex1 16 | 17 | 18 | 19 | source/main.ptx 20 | publication/publication.ptx 21 | output/html 22 | 26 | 30 | 31 | html 32 | 33 | 34 | latex 35 | source/main.ptx 36 | publication/publication.ptx 37 | output/latex 38 | 39 | 43 | pdf 44 | source/main.ptx 45 | publication/publication.ptx 46 | output/pdf 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/legacy/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/legacy_extra/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | pdflatex 7 | xelatex 8 | pdf2svg 9 | asy 10 | sage 11 | convert 12 | pdftops 13 | node 14 | foobar 15 | 16 | foobar.exe 17 | 18 | latex1 19 | 20 | 21 | 22 | source/main.ptx 23 | publication/publication.ptx 24 | output/html 25 | 29 | 33 | 34 | html 35 | 36 | 37 | latex 38 | source/main.ptx 39 | publication/publication.ptx 40 | output/latex 41 | 42 | foo 43 | 44 | 48 | pdf 49 | source/main.ptx 50 | publication/publication.ptx 51 | output/pdf 52 | 53 | 54 | 55 | 56 | 57 | fake 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/legacy_extra/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple/.gitignore: -------------------------------------------------------------------------------- 1 | generated-assets 2 | output -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple/assets/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/tests/examples/projects/project_refactor/simple/assets/foo.txt -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | runestone-document-id 5 | A Runestone book 6 | 7 |
    8 | Hello World! 9 |

    This is a PreTeXt document.

    10 |
    11 |
    12 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_attribute/.gitignore: -------------------------------------------------------------------------------- 1 | generated-assets 2 | output -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_attribute/assets/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/tests/examples/projects/project_refactor/simple_extra_attribute/assets/foo.txt -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_attribute/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_attribute/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_attribute/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | runestone-document-id 5 | A Runestone book 6 | 7 |
    8 | Hello World! 9 |

    This is a PreTeXt document.

    10 |
    11 |
    12 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_element/.gitignore: -------------------------------------------------------------------------------- 1 | generated-assets 2 | output -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_element/assets/foo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreTeXtBook/pretext-cli/1244e3ec97c55c122ebeb6606e5c144862fc6553/tests/examples/projects/project_refactor/simple_extra_element/assets/foo.txt -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_element/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_element/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /tests/examples/projects/project_refactor/simple_extra_element/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | runestone-document-id 5 | A Runestone book 6 | 7 |
    8 | Hello World! 9 |

    This is a PreTeXt document.

    10 |
    11 |
    12 | -------------------------------------------------------------------------------- /tests/examples/projects/xref/.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # (delete the above line to manage this file manually) 3 | 4 | # Boilerplate list of files in a PreTeXt project for git to ignore 5 | # ensure this file is tracked 6 | !.gitignore 7 | 8 | # don't track unpublished builds or stage 9 | output 10 | 11 | # don't track assets generated from source 12 | generated-assets 13 | 14 | # don't track the executables.ptx file 15 | executables.ptx 16 | 17 | # don't track node packages 18 | node_modules 19 | 20 | # don't track error logs 21 | .error_schema.log 22 | logs 23 | 24 | # don't track OS related files (windows/macos/linux) 25 | .DS_Store 26 | .DS_Store? 27 | ._* 28 | .AppleDouble 29 | .LSOverride 30 | .Spotlight-V100 31 | .Trashes 32 | Icon 33 | .AppleDB 34 | .AppleDesktop 35 | Network Trash Folder 36 | Temporary Items 37 | .apdisk 38 | Thumbs.db 39 | Thumbs.db:encryptable 40 | ehthumbs.db 41 | ehthumbs_vista.db 42 | *.stackdump 43 | *.lnk 44 | *.cab 45 | *.msi 46 | *.msix 47 | *.msm 48 | *.msp 49 | [Dd]esktop.ini 50 | .directory 51 | .fuse_hidden* 52 | .Trash-* 53 | .nfs* 54 | 55 | # Don't include VSCode generated files 56 | .vscode 57 | *.code-workspace 58 | 59 | # Don't inlucde SublimeText files 60 | # Cache files for Sublime Text 61 | *.tmlanguage.cache 62 | *.tmPreferences.cache 63 | *.stTheme.cache 64 | 65 | # Workspace files are user-specific 66 | *.sublime-workspace 67 | 68 | # Project files should be checked into the repository, unless a significant 69 | # proportion of contributors will probably not be using Sublime Text 70 | *.sublime-project 71 | 72 | # SFTP configuration file 73 | sftp-config.json 74 | sftp-config-alt*.json 75 | 76 | # Package control specific files 77 | Package Control.last-run 78 | Package Control.ca-list 79 | Package Control.ca-bundle 80 | Package Control.system-ca-bundle 81 | Package Control.cache/ 82 | Package Control.ca-certs/ 83 | Package Control.merged-ca-bundle 84 | Package Control.user-ca-bundle 85 | oscrypto-ca-bundle.crt 86 | bh_unicode_properties.cache 87 | 88 | # Sublime-github package stores a github token in this file 89 | # https://packagecontrol.io/packages/sublime-github 90 | GitHub.sublime-settings 91 | 92 | 93 | # Don't include Dropbox settings and caches 94 | .dropbox 95 | .dropbox.attr 96 | .dropbox.cache 97 | 98 | # Don't track codechat config (will be generated automatically) 99 | codechat_config.yaml 100 | -------------------------------------------------------------------------------- /tests/examples/projects/xref/project.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/xref/publication/publication.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/examples/projects/xref/source/main.ptx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | Xref Example 5 | 6 | Foo 7 |

    Bar.

    8 |

    Baz.

    9 |
    10 |

    This is an xref: .

    11 |
    12 |
    13 | -------------------------------------------------------------------------------- /tests/test_sample_article.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import pytest 3 | from pathlib import Path 4 | import errorhandler # type: ignore 5 | from pretext.project import Project 6 | import pretext.utils 7 | from .common import check_installed, EXAMPLES_DIR 8 | 9 | 10 | @pytest.mark.skipif( 11 | not check_installed(["xelatex", "--version"]), 12 | reason="Note: several tests are skipped, since xelatex wasn't installed.", 13 | ) 14 | def test_sample_article(tmp_path: Path) -> None: 15 | error_checker = errorhandler.ErrorHandler(logger="ptxlogger") 16 | prj_path = tmp_path / "sample" 17 | shutil.copytree(EXAMPLES_DIR / "core" / "examples" / "sample-article", prj_path) 18 | with pretext.utils.working_directory(prj_path): 19 | project = Project.parse() 20 | t = project.get_target() 21 | t.build() 22 | assert not error_checker.fired 23 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from pretext import utils 4 | 5 | 6 | def test_working_directory(tmp_path: Path) -> None: 7 | os.chdir(tmp_path) 8 | subdir = Path("foobar") 9 | subdir.mkdir() 10 | assert Path().resolve() == tmp_path.resolve() 11 | with utils.working_directory(subdir): 12 | assert Path().resolve().parent == tmp_path.resolve() 13 | # TODO check path returns afterward 14 | 15 | 16 | def test_project_path(tmp_path: Path) -> None: 17 | os.chdir(tmp_path) 18 | Path("project.ptx").write_text("") 19 | assert Path("project.ptx").exists() 20 | assert utils.project_path_found().resolve() == tmp_path.resolve() 21 | subdir = Path("foobar") 22 | print(subdir.resolve()) 23 | subdir.mkdir() 24 | os.chdir(subdir) 25 | assert utils.project_path_found().resolve() == Path().resolve().parent 26 | 27 | 28 | def test_parse_git_remote() -> None: 29 | valids = [ 30 | "git@github.com:PreTeXtBook/pretext-cli.git", 31 | "https://github.com/PreTeXtBook/pretext-cli.git", 32 | "https://github.com/PreTeXtBook/pretext-cli", 33 | "https://github.com/PreTeXtBook/pretext-cli/", 34 | ] 35 | for string in valids: 36 | assert utils.parse_git_remote(string)[0] == "PreTeXtBook" 37 | assert utils.parse_git_remote(string)[1] == "pretext-cli" 38 | 39 | 40 | def test_is_unmodified() -> None: 41 | magic_comment = ( 42 | b"foo\n\nbar" 43 | ) 44 | assert utils.is_unmodified("foo", magic_comment) 45 | --------------------------------------------------------------------------------