Skip to content

Commit 6e08b8c

Browse files
authored
introduce experimental Typst support (#251)
* introduce experimental Typst support * fix mistaken capitalization of analyze_pdf_logs
1 parent d8d81a6 commit 6e08b8c

File tree

4 files changed

+359
-20
lines changed

4 files changed

+359
-20
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
*.pdf
2+
*.typ
3+
*.log
24
*.docx
35
*.html
46
.cache/*

Dockerfile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# syntax=docker/dockerfile:1.3-labs
2+
ARG RUSTBASE=rust:1.87.0-bookworm
23
ARG BUILDBASE=debian:bookworm-20250203-slim
34
ARG RUNBASE=pandoc/core:3.6-ubuntu
45

5-
FROM ${BUILDBASE} as build-texlive
6+
FROM ${RUSTBASE} AS build-typst
7+
8+
RUN cargo install --version 0.13.1 typst-cli
9+
10+
FROM ${BUILDBASE} AS build-texlive
611

712
# Pass the correct platform to texlive build.
813
ARG TARGETPLATFORM
@@ -42,7 +47,7 @@ RUN export ARCH=$(cat /ARCH) && \
4247

4348
RUN mkdir -p /texlivebins && cp -r /usr/local/texlive/*/* /texlivebins
4449

45-
FROM ${BUILDBASE} as build-fonts
50+
FROM ${BUILDBASE} AS build-fonts
4651

4752
RUN apt update && apt install -y \
4853
wget \
@@ -66,7 +71,7 @@ RUN wget https://github.com/alerque/libertinus/releases/download/v7.040/Libertin
6671
mkdir -p /usr/share/fonts/OTF/ && \
6772
cp Libertinus-7.040/static/OTF/*.otf /usr/share/fonts/OTF/
6873

69-
FROM ${BUILDBASE} as build-latexdiff
74+
FROM ${BUILDBASE} AS build-latexdiff
7075

7176
RUN apt update && apt install -y \
7277
build-essential \
@@ -81,10 +86,13 @@ RUN wget https://github.com/ftilmann/latexdiff/releases/download/1.3.4/latexdiff
8186
make install-fast
8287

8388
# Build's done. Copy what we need into the actual container for running.
84-
FROM ${RUNBASE} as run
89+
FROM ${RUNBASE} AS run
8590

8691
ARG TARGETPLATFORM
8792

93+
# Copy Typst
94+
COPY --from=build-typst /usr/local/cargo/bin/typst /usr/local/bin
95+
8896
# These binaries are the second most costly part of the build.
8997
COPY --from=build-texlive /texlivebins /usr/local/texlive
9098

build.sh

Lines changed: 115 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ DIFFTEX_OUTPUT=""
99
DOCX_OUTPUT=""
1010
HTML_OUTPUT=""
1111
LATEX_OUTPUT=""
12+
TYPST_OUTPUT=""
1213
PDFLOG_OUTPUT=""
1314
VERSIONED_FILENAMES="no"
1415
PR_NUMBER=""
@@ -54,6 +55,7 @@ print_usage() {
5455
echo " --crossref=(iso|tcg): set cross-reference style."
5556
echo " --pdf=output: enable output of pdf and specify the output file name."
5657
echo " --latex=output: enable output of latex and specify the output file name."
58+
echo " --typst=output: enable output of typst and specify the output file name."
5759
echo " --html=output: enable output of html and specify the output file name."
5860
echo " --pdflog=output: enable logging of pdf engine and specify the output file name."
5961
echo " --diffpdf=output: enable output of pdf diff and specify the output file name (requires --diffbase)"
@@ -72,13 +74,13 @@ print_usage() {
7274
echo " --versioned_filenames: insert version information before the file extension for outputs"
7375
echo " --pr_number=number: mark the document as a pull-request draft if using Git versioning."
7476
echo " --pr_repo=url: provide the URL for the repository for pull-request drafts (has no effect if --PR_NUMBER is not passed)."
75-
echo " --pdf_engine=(xelatex|lualatex): use the given latex engine (default xelatex)"
77+
echo " --pdf_engine=(xelatex|lualatex|typst): use the given PDF engine (default xelatex)"
7678
echo " --noautobackmatter: don't automatically insert back matter at the end of the document."
7779
echo " --csl: provide a csl file via the command line (instead of in YAML metadata)."
7880
}
7981

8082

81-
if ! options=$(getopt --longoptions=help,puppeteer,gitversion,gitstatus,nogitversion,table_rules,plain_quotes,versioned_filenames,pr_number:,pr_repo:,diffbase:,pdf:,diffpdf:,difftex:,diffpdflog:,latex:,pdflog:,pdf_engine:,template:,template_html:,html_stylesheet:,reference_doc:,docx:,crossref:,html:,resourcedir:,noautobackmatter,csl: --options="" -- "$@"); then
83+
if ! options=$(getopt --longoptions=help,puppeteer,gitversion,gitstatus,nogitversion,table_rules,plain_quotes,versioned_filenames,pr_number:,pr_repo:,diffbase:,pdf:,diffpdf:,difftex:,diffpdflog:,latex:,typst:,pdflog:,pdf_engine:,template:,template_html:,html_stylesheet:,reference_doc:,docx:,crossref:,html:,resourcedir:,noautobackmatter,csl: --options="" -- "$@"); then
8284
echo "Incorrect options provided"
8385
print_usage
8486
exit 1
@@ -128,6 +130,10 @@ while true; do
128130
LATEX_OUTPUT="${2}"
129131
shift 2
130132
;;
133+
--typst)
134+
TYPST_OUTPUT="${2}"
135+
shift 2
136+
;;
131137
--pdflog)
132138
PDFLOG_OUTPUT="${2}"
133139
shift 2
@@ -243,7 +249,7 @@ if [ -z "${PDF_OUTPUT}${LATEX_OUTPUT}${DOCX_OUTPUT}${HTML_OUTPUT}" ]; then
243249
fi
244250

245251
# the pdf engine must be supported
246-
if [ "${PDF_ENGINE}" != "xelatex" -a "${PDF_ENGINE}" != "lualatex" ]; then
252+
if [ "${PDF_ENGINE}" != "xelatex" -a "${PDF_ENGINE}" != "lualatex" -a "${PDF_ENGINE}" != "typst" ]; then
247253
>&2 echo "Unsupported PDF engine '${PDF_ENGINE}', expected one of: xelatex, lualatex"
248254
print_usage
249255
exit 1
@@ -504,6 +510,7 @@ echo "pdf: ${PDF_OUTPUT:-none} (engine: ${PDF_ENGINE})"
504510
echo "diff pdf: ${DIFFPDF_OUTPUT:-none} (engine: ${PDF_ENGINE})"
505511
echo "latex: ${latex_ouput:-none}"
506512
echo "diff latex: ${DIFFTEX_OUTPUT:-none} "
513+
echo "typst: ${TYPST_OUTPUT:-none}"
507514
echo "html: ${html_ouput:-none}"
508515
echo "resource dir: ${RESOURCE_DIR}"
509516
echo "build dir: ${BUILD_DIR}"
@@ -718,7 +725,7 @@ retry () {
718725
}
719726

720727
# Greps the latex logs to surface relevant errors and warnings.
721-
analyze_latex_logs() {
728+
analyze_pdf_logs() {
722729
local logfile=$1
723730

724731
local runcount=$(grep "Run number " "${logfile}" | tail -n 1 | cut -d ' ' -f 3)
@@ -819,8 +826,61 @@ do_latex() {
819826
cache_generated_files
820827
}
821828

829+
# Takes Markdown input and writes Typst output using pandoc.
830+
do_typst() {
831+
local input=$1
832+
local output=$2
833+
local crossref=$3
834+
local extra_pandoc_options=$4
835+
mkdir -p "$(dirname ${output})"
836+
837+
# TODO: https://github.com/TrustedComputingGroup/pandoc/issues/164
838+
# highlighting breaks diffing due to the \xxxxTok commands generated during highlighting being fragile.
839+
# Citations: https://pandoc.org/MANUAL.html#other-relevant-metadata-fields
840+
echo "Generating Typst Output"
841+
local start=$(date +%s)
842+
local cmd=(pandoc
843+
--standalone
844+
--highlight-style=${SYNTAX_HIGHLIGHT_STYLE}
845+
--lua-filter=convert-diagrams.lua
846+
--lua-filter=convert-images.lua
847+
--lua-filter=parse-html.lua
848+
--filter=pandoc-crossref
849+
--citeproc
850+
--resource-path=.:/resources:${RESOURCE_DIR}
851+
--data-dir=/resources
852+
--top-level-division=section
853+
--variable=block-headings
854+
--variable=numbersections
855+
--metadata=date:"'${DATE}'"
856+
--metadata=date-english:"'${DATE_ENGLISH}'"
857+
--metadata=year:"'${YEAR}'"
858+
--metadata=titlepage:true
859+
--metadata=link-citations
860+
--metadata=link-bibliography
861+
--metadata=crossrefYaml:/resources/filters/pandoc-crossref-${crossref}.yaml
862+
--metadata=colorlinks:true
863+
--metadata=contact:[email protected]
864+
--from=${FROM}
865+
${extra_pandoc_options}
866+
--to=typst
867+
--output="'${output}'"
868+
"'${input}'")
869+
retry 5 "${cmd[@]}"
870+
if [ $? -ne 0 ]; then
871+
FAILED=true
872+
echo "Typst output failed"
873+
fi
874+
local end=$(date +%s)
875+
echo "Elapsed time: $(($end-$start)) seconds"
876+
877+
# Cache generated files now so they don't need to be
878+
# re-rendered if the build later fails.
879+
cache_generated_files
880+
}
881+
822882
# Takes LaTeX input and writes PDF output and logs using the PDF engine of choice.
823-
do_pdf() {
883+
do_pdf_from_latex() {
824884
local input=$1
825885
local output=$2
826886
mkdir -p "$(dirname ${output})"
@@ -854,10 +914,37 @@ do_pdf() {
854914
cp_chown ".cache/${temp_pdf_file}" "${output}" && rm ".cache/${temp_pdf_file}"
855915
fi
856916
if [[ ! "${FAILED}" = "true" ]]; then
857-
analyze_latex_logs "${logfile}"
917+
analyze_pdf_logs "${logfile}"
858918
fi
859919
}
860920

921+
922+
# Takes Typst input and writes PDF output and logs.
923+
do_pdf_from_typst() {
924+
local input=$1
925+
local output=$2
926+
mkdir -p "$(dirname ${output})"
927+
928+
local logfile=$3
929+
local temp_pdf_file="$(basename ${input%.*}).pdf"
930+
rm -f ${temp_pdf_file}
931+
local start=$(date +%s)
932+
typst compile ${input} ${temp_pdf_file}
933+
if [ $? -ne 0 ]; then
934+
FAILED=true
935+
echo "PDF output failed"
936+
fi
937+
if [[ ! "${FAILED}" = "true" || "${ignore_errors}" = "true" ]]; then
938+
cp_chown "${temp_pdf_file}" "${output}"
939+
fi
940+
if [ $? -ne 0 ]; then
941+
FAILED=true
942+
echo "PDF output failed"
943+
fi
944+
local end=$(date +%s)
945+
echo "Elapsed time: $(($end-$start)) seconds"
946+
}
947+
861948
# Takes Markdown input and writes Docx output using pandoc.
862949
do_docx() {
863950
local input=$1
@@ -964,31 +1051,43 @@ do_html() {
9641051
fi
9651052
}
9661053

967-
# Generate .tex output if either latex or pdf formats were requested, because
968-
# the .tex is an intermediate requirement to the pdf.
1054+
do_md_fixups "${BUILD_DIR}/${INPUT_FILE}"
1055+
1056+
# Generate .typ output if either typst or pdf format (using the Typst engine) were requested.
1057+
readonly TEMP_TYP_FILE="${BUILD_DIR}/${INPUT_FILE}.typ"
1058+
if { [ -n "${TYPST_OUTPUT}" ] || { [ "${PDF_ENGINE}" == "typst" ] && [ -n "${PDF_OUTPUT}" ]; }; }; then
1059+
do_typst "${BUILD_DIR}/${INPUT_FILE}" "${TEMP_TYP_FILE}" "${CROSSREF_TYPE}" "${EXTRA_PANDOC_OPTIONS}"
1060+
fi
1061+
if [ -n "${TYPST_OUTPUT}" ]; then
1062+
cp_chown "${TEMP_TYP_FILE}" "${SOURCE_DIR}/${TYPST_OUTPUT}"
1063+
fi
1064+
1065+
# Generate .tex output if either latex or pdf formats (using a non-Typst engine) were requested.
9691066
readonly TEMP_TEX_FILE="${BUILD_DIR}/${INPUT_FILE}.tex"
970-
if [ -n "${PDF_OUTPUT}" -o -n "${LATEX_OUTPUT}" -o -n "${DIFFPDF_OUTPUT}" -o -n "${DIFFTEX_OUTPUT}" ]; then
971-
do_md_fixups "${BUILD_DIR}/${INPUT_FILE}"
1067+
if { [ -n "${LATEX_OUTPUT}" ] || [ -n "${DIFFTEX_OUTPUT}" ] || { [ "${PDF_ENGINE}" != "typst" ] && { [ -n "${PDF_OUTPUT}" ] || [ -n "${DIFFPDF_OUTPUT}" ]; }; }; }; then
9721068
do_latex "${BUILD_DIR}/${INPUT_FILE}" "${TEMP_TEX_FILE}" "${CROSSREF_TYPE}" "${EXTRA_PANDOC_OPTIONS}"
9731069
fi
9741070
if [ -n "${LATEX_OUTPUT}" ]; then
9751071
cp_chown "${TEMP_TEX_FILE}" "${SOURCE_DIR}/${LATEX_OUTPUT}"
9761072
fi
9771073

9781074
# Generate the PDF output
979-
readonly LATEX_LOG="${BUILD_DIR}/latex.log"
1075+
readonly PDF_LOG="${BUILD_DIR}/pdf.log"
9801076
if [ -n "${PDF_OUTPUT}" ]; then
981-
do_pdf "${TEMP_TEX_FILE}" "${SOURCE_DIR}/${PDF_OUTPUT}" "${LATEX_LOG}" false
1077+
if [ "${PDF_ENGINE}" == "typst" ]; then
1078+
do_pdf_from_typst "${TEMP_TYP_FILE}" "${SOURCE_DIR}/${PDF_OUTPUT}" "${PDF_LOG}" false
1079+
else
1080+
do_pdf_from_latex "${TEMP_TEX_FILE}" "${SOURCE_DIR}/${PDF_OUTPUT}" "${PDF_LOG}" false
1081+
fi
9821082

9831083
# Copy the logs, if requested.
9841084
if [ -n "${PDFLOG_OUTPUT}" ]; then
985-
cp_chown "${LATEX_LOG}" "${SOURCE_DIR}/${PDFLOG_OUTPUT}"
1085+
cp_chown "${PDF_LOG}" "${SOURCE_DIR}/${PDFLOG_OUTPUT}"
9861086
fi
9871087
fi
9881088

9891089
# Generate the html output
9901090
if [ -n "${HTML_OUTPUT}" ]; then
991-
do_md_fixups "${BUILD_DIR}/${INPUT_FILE}" "html"
9921091
do_html "${BUILD_DIR}/${INPUT_FILE}" "${SOURCE_DIR}/${HTML_OUTPUT}" "${CROSSREF_TYPE}"
9931092
fi
9941093

@@ -1036,7 +1135,7 @@ if [ "${FAILED}" != "true" -a -n "${DIFFPDF_OUTPUT}" ]; then
10361135
# We do our best to fix up the latexdiff result so that it compiles without errors.
10371136
# In some cases, there are still errors. It is better to produce an ugly diff-document than to
10381137
# produce no diff-document at all.
1039-
do_pdf "${TEMP_DIFF_TEX_FILE}" "${SOURCE_DIR}/${DIFFPDF_OUTPUT}" "${LATEX_LOG}" true
1138+
do_pdf_from_latex "${TEMP_DIFF_TEX_FILE}" "${SOURCE_DIR}/${DIFFPDF_OUTPUT}" "${PDF_LOG}" true
10401139

10411140
# Copy the logs, if requested. Note that this file gets the latexdiff and PDF driver output.
10421141
if [ -n "${DIFFPDFLOG_OUTPUT}" ]; then
@@ -1045,7 +1144,7 @@ if [ "${FAILED}" != "true" -a -n "${DIFFPDF_OUTPUT}" ]; then
10451144
cat "${TEMP_LATEXDIFF_LOG}" >> "${SOURCE_DIR}/${DIFFPDFLOG_OUTPUT}"
10461145
echo "" >> "${SOURCE_DIR}/${DIFFPDFLOG_OUTPUT}"
10471146
echo "${PDF_ENGINE} output:" >> "${SOURCE_DIR}/${DIFFPDFLOG_OUTPUT}"
1048-
cat "${LATEX_LOG}" >> "${SOURCE_DIR}/${DIFFPDFLOG_OUTPUT}"
1147+
cat "${PDF_LOG}" >> "${SOURCE_DIR}/${DIFFPDFLOG_OUTPUT}"
10491148
fi
10501149
fi
10511150

0 commit comments

Comments
 (0)