diff --git a/CHANGELOG.md b/CHANGELOG.md index c7853c0..4db0b6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Bug Fixes +- fix: Keep inline code in a Typst document as a code element, so Pandoc writes the syntax highlighting definitions for it. A document with inline code and no code block failed to compile before. (#65) - fix: Remove the code-window attributes from a block that sets code-window-enabled="false", and from a block that sets code-window-lines when lines-label is off. They reached the HTML output as data-code-window-* attributes before. (#63) - fix: Remove the extension's own label attribute when the output format gets no window chrome, so a writer that keeps attributes no longer prints it. (#63) - fix: Check every code block attribute in the code-window group against the schema, so a value nothing validated before, such as code-window-enabled, is now reported when it is wrong. The extension's own duplicate warnings for an invalid code-window-style or code-window-collapse are removed, since the schema already names the same mistake. (#60) diff --git a/_extensions/code-window/_modules/hotfix/skylighting-typst-fix.lua b/_extensions/code-window/_modules/hotfix/skylighting-typst-fix.lua index 7d1aef8..a3a48d3 100644 --- a/_extensions/code-window/_modules/hotfix/skylighting-typst-fix.lua +++ b/_extensions/code-window/_modules/hotfix/skylighting-typst-fix.lua @@ -155,44 +155,35 @@ local function build_raw_line_annotation_rule() ]==], circled, circled) end +--- Shape of the box that holds inline code, after its fill. +local _inline_box_style = 'inset: (x: 3pt, y: 0pt), outset: (y: 3pt), ' + .. 'radius: 2pt, stroke: none)[' + --- Process inline Code for Typst format. ---- Renders the Code element through Pandoc's Typst writer to get syntax- ---- highlighted output, then wraps it in a box with the theme background colour. +--- Puts the Code element in a box that carries the theme background colour. +--- The element itself stays in the document, so Pandoc highlights it and +--- writes the token definitions for it. --- @param el pandoc.Code Inline code element ---- @return pandoc.RawInline|pandoc.Code Transformed or original element +--- @return pandoc.Inlines The boxed code local function process_typst_inline(el) local hm = PANDOC_WRITER_OPTIONS and PANDOC_WRITER_OPTIONS.highlight_method - local bg_fill = nil - local write_opts = nil - - if hm then - local bg = hm['background-color'] - if bg and type(bg) == 'string' then - bg_fill = string.format('rgb("%s")', bg) - end - write_opts = pandoc.WriterOptions({ - highlight_method = hm, - }) - end - - local rendered = pandoc.write(pandoc.Pandoc({ pandoc.Plain({ el }) }), 'typst', write_opts) - rendered = rendered:gsub('%s+$', '') - if rendered == '' then return el end + local bg = hm and hm['background-color'] + local opening, closing - local typst_code - if bg_fill then - typst_code = string.format( - '#box(fill: %s, inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt, stroke: none)[%s]', - bg_fill, rendered) + if type(bg) == 'string' then + opening = string.format('#box(fill: rgb("%s"), ', bg) .. _inline_box_style + closing = ']' else - typst_code = string.format( - '#context { let _bg = _cw-page-bg(); let _f = _cw-fg(_bg); ' - .. 'box(fill: color.mix((_f, 10%%), (_bg, 90%%)), ' - .. 'inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt, stroke: none)[%s] }', - rendered) + opening = '#context { let _bg = _cw-page-bg(); let _f = _cw-fg(_bg); ' + .. 'box(fill: color.mix((_f, 10%), (_bg, 90%)), ' .. _inline_box_style + closing = '] }' end - return pandoc.RawInline('typst', typst_code) + return pandoc.Inlines({ + pandoc.RawInline('typst', opening), + el, + pandoc.RawInline('typst', closing), + }) end --- Inject Skylighting override at the start of the document. @@ -245,8 +236,10 @@ local function is_title_scaffold(div) return true end ---- Walk the document tree and convert inline Code to RawInline with ---- background styling. Code in title scaffolds is converted to plain +--- Walk the document tree and box inline Code with background styling. +--- The extension contributes the pass once, so it sees each Code element +--- once and boxes it once. +--- Code in title scaffolds is converted to plain --- Typst backtick code to avoid Skylighting tokens with inner quotes --- that would break the string parameter Quarto generates. --- The typst-title-fix post-quarto filter then evaluates the string diff --git a/tests/fixtures/inline-code-no-theme.qmd b/tests/fixtures/inline-code-no-theme.qmd new file mode 100644 index 0000000..f572db7 --- /dev/null +++ b/tests/fixtures/inline-code-no-theme.qmd @@ -0,0 +1,17 @@ +--- +title: "Inline code, no theme" +filters: + - code-window +highlight-style: none +format: + typst: + keep-typ: true +--- + +The document below turns syntax highlighting off, so the theme gives no +background colour. + +The filter then boxes the inline code with a colour it mixes from the page, +and that box has to compile too. + +A paragraph with `inline code` in it. diff --git a/tests/fixtures/inline-code-only.qmd b/tests/fixtures/inline-code-only.qmd new file mode 100644 index 0000000..65d5eb9 --- /dev/null +++ b/tests/fixtures/inline-code-only.qmd @@ -0,0 +1,15 @@ +--- +title: "Inline code, no block" +filters: + - code-window +format: + typst: + keep-typ: true +--- + +The document below has inline code and no code block. + +The filter boxes the inline code and leaves the element in place, so Pandoc +writes the token definitions for it. + +A paragraph with `inline code` in it. diff --git a/tests/fixtures/inline-code-with-block.qmd b/tests/fixtures/inline-code-with-block.qmd new file mode 100644 index 0000000..2f1c4c1 --- /dev/null +++ b/tests/fixtures/inline-code-with-block.qmd @@ -0,0 +1,19 @@ +--- +title: "Inline code and a block" +filters: + - code-window +format: + typst: + keep-typ: true +--- + +The document below has inline code and a code block. + +The boxed inline code and the block that goes through the Skylighting +override share one document, and that document has to compile. + +A paragraph with `inline code` in it. + +```python +x = 1 +``` diff --git a/tests/run.sh b/tests/run.sh index ae328f0..0b5c929 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -85,6 +85,50 @@ for fixture in cell-output-bare cell-output-classed; do fi done +# ============================================================================ +# Inline code keeps the token definitions in a document with no code block +# ============================================================================ + +# The filter boxes inline code and leaves the element itself in place, so +# Pandoc highlights it and writes the token definitions. The render fails to +# compile when they are missing, and the grep says why. +render inline-code-only typst +if grep -q '^#let NormalTok(' "${work_dir}/inline-code-only.typ"; then + report pass "inline-code-only: the token definitions reach the document" +else + report fail "inline-code-only: the token definitions reach the document" \ + "a #let NormalTok( definition in inline-code-only.typ" +fi + +# A theme with a background colour takes the box that names the colour. +if grep -q 'box(fill: rgb(' "${work_dir}/inline-code-only.typ"; then + report pass "inline-code-only: the box takes the colour of the theme" +else + report fail "inline-code-only: the box takes the colour of the theme" \ + "a box(fill: rgb( call in inline-code-only.typ" +fi + +# A code block goes through the Skylighting override, and the inline code +# keeps its own box in the same document. +render inline-code-with-block typst +if grep -q '^#Skylighting(' "${work_dir}/inline-code-with-block.typ" && + grep -q 'box(fill: rgb(' "${work_dir}/inline-code-with-block.typ"; then + report pass "inline-code-with-block: the block and the inline code share the document" +else + report fail "inline-code-with-block: the block and the inline code share the document" \ + "a #Skylighting( call and a box(fill: rgb( call in inline-code-with-block.typ" +fi + +# A theme that gives no background colour takes the other box, which mixes its +# colour from the page. The render compiles that box. +render inline-code-no-theme typst +if grep -q 'box(fill: color.mix' "${work_dir}/inline-code-no-theme.typ"; then + report pass "inline-code-no-theme: the box takes its colour from the page" +else + report fail "inline-code-no-theme: the box takes its colour from the page" \ + "a box(fill: color.mix call in inline-code-no-theme.typ" +fi + # ============================================================================ # A per-block style override reaches the output # ============================================================================