diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 863d3d9603..ff2cfe685a 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -51,10 +51,13 @@ import { kResourcePath, kShortcodes, kTblColwidths, + kHighlightStyle, + kSyntaxHighlighting, kTocTitleDocument, kUnrollMarkdownCells, kUseRsvgConvert, } from "../../config/constants.ts"; +import { kDefaultHighlightStyle } from "./constants.ts"; import { PandocOptions } from "./types.ts"; import { Format, @@ -945,11 +948,19 @@ async function resolveFilterExtension( } const extractTypstFilterParams = (format: Format) => { + const theme = + format.pandoc[kSyntaxHighlighting] || + format.pandoc[kHighlightStyle] || + kDefaultHighlightStyle; + const skylighting = + typeof theme === "string" && theme !== "none" && theme !== "idiomatic"; + return { [kTocIndent]: format.metadata[kTocIndent], [kLogo]: format.metadata[kLogo], [kCssPropertyProcessing]: format.metadata[kCssPropertyProcessing], [kBrandMode]: format.metadata[kBrandMode], [kHtmlPreTagProcessing]: format.metadata[kHtmlPreTagProcessing], + [kSyntaxHighlighting]: skylighting, }; }; diff --git a/src/format/typst/format-typst.ts b/src/format/typst/format-typst.ts index 71f0657022..e4a1abd579 100644 --- a/src/format/typst/format-typst.ts +++ b/src/format/typst/format-typst.ts @@ -187,40 +187,110 @@ export function typstFormat(): Format { // When brand provides a monospace-block background-color, also overrides the // bgcolor value. This is a temporary workaround until the fix is upstreamed // to the Skylighting library. +// +// Additionally patches the Skylighting function for code annotation support: +// adds an annotations parameter, moves line tracking outside the if-number +// block, adds per-line annotation rendering, and routes output through +// quarto-code-block(). Also merges annotation comment markers from the Lua +// filter into Skylighting call sites. +// +// Upstream compatibility: a PR to skylighting-format-typst +// (fix/typst-skylighting-block-style) adds block styling upstream. Once merged +// and picked up by Pandoc, the block styling patch becomes a no-op (the +// replace target won't match). The brand color regex targets rgb("...") which +// works with both current and future upstream bgcolor init patterns. function skylightingPostProcessor(brandBgColor?: string) { // Match the entire #let Skylighting(...) = { ... } function. // The signature is stable and generated by Skylighting's Typst backend. const skylightingFnRe = /(#let Skylighting\(fill: none, number: false, start: 1, sourcelines\) = \{[\s\S]*?\n\})/; + // Annotation markers emitted by the Lua filter as Typst comments + const annotationMarkerRe = + /\/\/ quarto-code-annotations: ([\w-]*) (\([^)]*\))\n(\s*(?:#block\[\s*)*(?:#quarto-code-filename\([^\n]*\)\[\s*)?)#Skylighting\(/g; + return async (output: string) => { - const content = Deno.readTextFileSync(output); + let content = Deno.readTextFileSync(output).replace(/\r\n/g, "\n"); + let changed = false; const match = skylightingFnRe.exec(content); - if (!match) { - // No Skylighting function found — document may not have code blocks, - // or upstream changed the function signature. Nothing to patch. - return; - } + if (match) { + let fn = match[1]; - let fn = match[1]; + // Fix block() call: add width, inset, radius, stroke + fn = fn.replace( + "block(fill: bgcolor, blocks)", + "block(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0.5pt + luma(200), blocks)", + ); - // Fix block() call: add width, inset, radius - fn = fn.replace( - "block(fill: bgcolor, blocks)", - "block(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks)", - ); + // Override bgcolor with brand monospace-block background-color + if (brandBgColor) { + fn = fn.replace( + /rgb\("[^"]*"\)/, + `rgb("${brandBgColor}")`, + ); + } + + // Add cell-id and annotations parameters to function signature + fn = fn.replace( + "start: 1, sourcelines)", + "start: 1, cell-id: \"\", annotations: (:), sourcelines)", + ); + + // Move lnum increment outside if-number block (always track position) + fn = fn.replace( + /if number \{\n\s+lnum = lnum \+ 1\n/, + "lnum = lnum + 1\n if number {\n", + ); + + // Initialise a dictionary to track which annotation numbers have + // already emitted a back-label (avoids duplicate labels when one + // annotation spans multiple lines). + fn = fn.replace( + /let lnum = start - 1\n/, + "let lnum = start - 1\n let seen-annotes = (:)\n", + ); - // Override bgcolor with brand monospace-block background-color - if (brandBgColor) { + // Add annotation rendering per line (derive circle colour from bgcolor) fn = fn.replace( - /let bgcolor = rgb\("[^"]*"\)/, - `let bgcolor = rgb("${brandBgColor}")`, + "blocks = blocks + ln + EndLine()", + `let annote-num = annotations.at(str(lnum), default: none) + if annote-num != none { + if cell-id != "" { + let lbl = cell-id + "-annote-" + str(annote-num) + if str(annote-num) not in seen-annotes { + seen-annotes.insert(str(annote-num), true) + blocks = blocks + box(width: 100%)[#ln #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: quarto-annote-color(bgcolor))] #label(lbl + "-back")] + EndLine() + } else { + blocks = blocks + box(width: 100%)[#ln #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: quarto-annote-color(bgcolor))]] + EndLine() + } + } else { + blocks = blocks + box(width: 100%)[#ln #h(1fr) #quarto-circled-number(annote-num, color: quarto-annote-color(bgcolor))] + EndLine() + } + } else { + blocks = blocks + ln + EndLine() + }`, ); + + if (fn !== match[1]) { + content = content.replace(match[1], fn); + changed = true; + } + } + + // Merge annotation markers into Skylighting call sites, including + // optional #block[ wrappers and #quarto-code-filename(...)[ wrappers. + const merged = content.replace( + annotationMarkerRe, + "$3#Skylighting(cell-id: \"$1\", annotations: $2, ", + ); + if (merged !== content) { + content = merged; + changed = true; } - if (fn !== match[1]) { - Deno.writeTextFileSync(output, content.replace(match[1], fn)); + if (changed) { + Deno.writeTextFileSync(output, content); } }; } diff --git a/src/resources/filters/customnodes/decoratedcodeblock.lua b/src/resources/filters/customnodes/decoratedcodeblock.lua index 5aeefb0a55..a0c7c1dd49 100644 --- a/src/resources/filters/customnodes/decoratedcodeblock.lua +++ b/src/resources/filters/customnodes/decoratedcodeblock.lua @@ -180,3 +180,27 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", return pandoc.Div(blocks, pandoc.Attr("", classes)) end) + +-- typst renderer +_quarto.ast.add_renderer("DecoratedCodeBlock", + function(_) + return _quarto.format.isTypstOutput() + end, + function(node) + if node.filename == nil then + return _quarto.ast.walk(quarto.utils.as_blocks(node.code_block), { + CodeBlock = render_folded_block + }) + end + local el = node.code_block + local rendered = _quarto.ast.walk(quarto.utils.as_blocks(el), { + CodeBlock = render_folded_block + }) or pandoc.Blocks({}) + local blocks = pandoc.Blocks({}) + local escaped = node.filename:gsub('\\', '\\\\'):gsub('"', '\\"') + blocks:insert(pandoc.RawBlock("typst", + '#quarto-code-filename("' .. escaped .. '")[')) + blocks:extend(rendered) + blocks:insert(pandoc.RawBlock("typst", "]")) + return pandoc.Div(blocks) + end) diff --git a/src/resources/filters/modules/constants.lua b/src/resources/filters/modules/constants.lua index cb22ee3be6..0fd8d29215 100644 --- a/src/resources/filters/modules/constants.lua +++ b/src/resources/filters/modules/constants.lua @@ -33,6 +33,7 @@ local kAsciidocNativeCites = 'use-asciidoc-native-cites' local kShowNotes = 'showNotes' local kProjectResolverIgnore = 'project-resolve-ignore' +local kSyntaxHighlighting = 'syntax-highlighting' local kCodeAnnotationsParam = 'code-annotations' local kDataCodeCellTarget = 'data-code-cell' local kDataCodeCellLines = 'data-code-lines' @@ -200,6 +201,7 @@ return { kAsciidocNativeCites = kAsciidocNativeCites, kShowNotes = kShowNotes, kProjectResolverIgnore = kProjectResolverIgnore, + kSyntaxHighlighting = kSyntaxHighlighting, kCodeAnnotationsParam = kCodeAnnotationsParam, kDataCodeCellTarget = kDataCodeCellTarget, kDataCodeCellLines = kDataCodeCellLines, diff --git a/src/resources/filters/quarto-pre/code-annotation.lua b/src/resources/filters/quarto-pre/code-annotation.lua index e09e9f036f..ddae0f6ad7 100644 --- a/src/resources/filters/quarto-pre/code-annotation.lua +++ b/src/resources/filters/quarto-pre/code-annotation.lua @@ -81,7 +81,62 @@ local function toAnnoteId(number) end local function latexListPlaceholder(number) - return '5CB6E08D-list-annote-' .. number + return '5CB6E08D-list-annote-' .. number +end + +-- Typst annotation helpers + +-- Convert annotations table to a flat Typst dictionary string. +-- Keys are line positions (as strings), values are annotation numbers. +local function typstAnnotationsDict(annotations) + local entries = {} + for annoteId, lineNumbers in pairs(annotations) do + local num = annoteId:match("annote%-(%d+)") + if num then + for _, lineNo in ipairs(lineNumbers) do + table.insert(entries, {pos = lineNo, annoteNum = tonumber(num)}) + end + end + end + table.sort(entries, function(a, b) return a.pos < b.pos end) + local parts = {} + for _, e in ipairs(entries) do + table.insert(parts, '"' .. tostring(e.pos) .. '": ' .. tostring(e.annoteNum)) + end + return '(' .. table.concat(parts, ', ') .. ')' +end + +-- Skylighting mode: emit a Typst comment that the TS post-processor +-- will merge into the Skylighting call site. +local function typstAnnotationMarker(annotations, cellId) + local dict = typstAnnotationsDict(annotations) + return pandoc.RawBlock("typst", "// quarto-code-annotations: " .. (cellId or "") .. " " .. dict) +end + +-- Native/none mode: wrap a CodeBlock in #quarto-code-annotation(annotations)[...]. +-- raw.line numbers always start at 1 regardless of startFrom, so adjust keys. +local function wrapTypstAnnotatedCode(codeBlock, annotations, cellId) + local startFrom = tonumber(codeBlock.attr.attributes['startFrom']) or 1 + local adjustedAnnotations = {} + for annoteId, lineNumbers in pairs(annotations) do + local adjusted = pandoc.List({}) + for _, lineNo in ipairs(lineNumbers) do + adjusted:insert(lineNo - startFrom + 1) + end + adjustedAnnotations[annoteId] = adjusted + end + local dict = typstAnnotationsDict(adjustedAnnotations) + local lang = codeBlock.attr.classes[1] or "" + local code = codeBlock.text + local maxBackticks = 2 + for seq in code:gmatch("`+") do + maxBackticks = math.max(maxBackticks, #seq) + end + local fence = string.rep("`", maxBackticks + 1) + local raw = "#quarto-code-annotation(" .. dict + .. (cellId and cellId ~= "" and (", cell-id: \"" .. cellId .. "\"") or "") + .. ")[" .. fence .. lang .. "\n" .. code .. "\n" .. fence .. "]" + return pandoc.RawBlock("typst", raw) end local function toLines(s) @@ -263,11 +318,12 @@ end function processAnnotation(line, annoteNumber, annotationProvider) -- For all other formats, just strip the annotation- the definition list is converted - -- to be based upon line numbers. + -- to be based upon line numbers. local stripped = annotationProvider.stripAnnotation(line, annoteNumber) return stripped end + function code_meta() return { Meta = function(meta) @@ -424,17 +480,32 @@ function code_annotations() -- output the pending code cell and continue flushPending() - if #block.content == 1 and #block.content[1].content == 1 then + if #block.content == 1 and #block.content[1].content == 1 + and block.content[1].content[1] ~= nil + and block.content[1].content[1].t == "CodeBlock" then -- Find the code block and process that local codeblock = block.content[1].content[1] - + local cellId = resolveCellId(codeblock.attr.identifier) local codeCell = processCodeCell(codeblock, cellId) if codeCell then if codeAnnotations ~= constants.kCodeAnnotationStyleNone then codeCell.attr.identifier = cellId; end - block.content[1].content[1] = codeCell + -- Typst DecoratedCodeBlock: embed annotation data inside the block + -- so the marker stays adjacent to the Skylighting call after rendering + if _quarto.format.isTypstOutput() + and codeAnnotations ~= constants.kCodeAnnotationStyleNone + and pendingAnnotations and next(pendingAnnotations) ~= nil then + if param(constants.kSyntaxHighlighting, true) then + block.content[1].content[1] = codeCell + block.content[1].content:insert(1, typstAnnotationMarker(pendingAnnotations, pendingCellId)) + else + block.content[1].content[1] = wrapTypstAnnotatedCode(codeCell, pendingAnnotations, pendingCellId) + end + else + block.content[1].content[1] = codeCell + end outputBlock(block) else outputBlockClearPending(block) @@ -460,7 +531,20 @@ function code_annotations() if codeAnnotations ~= constants.kCodeAnnotationStyleNone then codeCell.attr.identifier = cellId; end - outputBlock(codeCell) + -- Typst standalone CodeBlock: emit annotation data alongside + -- the code block. The OL handler will emit annotation items. + if _quarto.format.isTypstOutput() + and codeAnnotations ~= constants.kCodeAnnotationStyleNone + and pendingAnnotations and next(pendingAnnotations) ~= nil then + if param(constants.kSyntaxHighlighting, true) then + outputBlock(typstAnnotationMarker(pendingAnnotations, pendingCellId)) + outputBlock(codeCell) + else + outputBlock(wrapTypstAnnotatedCode(codeCell, pendingAnnotations, pendingCellId)) + end + else + outputBlock(codeCell) + end else outputBlockClearPending(block) end @@ -468,6 +552,59 @@ function code_annotations() outputBlockClearPending(block) end elseif block.t == 'OrderedList' and pendingAnnotations ~= nil and next(pendingAnnotations) ~= nil then + + -- Typst: emit annotation items as raw Typst blocks + if _quarto.format.isTypstOutput() and codeAnnotations ~= constants.kCodeAnnotationStyleNone then + local annotationBlocks = pandoc.List() + for i, v in ipairs(block.content) do + local annotationNumber = block.start + i - 1 + local annoteId = toAnnoteId(annotationNumber) + if pendingAnnotations[annoteId] then + local content = pandoc.write(pandoc.Pandoc({v[1]}), "typst") + annotationBlocks:insert(pandoc.RawBlock("typst", + "#quarto-annotation-item(\"" .. (pendingCellId or "") .. "\", " .. tostring(annotationNumber) .. ", [" .. content .. "])")) + end + end + + if pendingCodeCell ~= nil then + local resolvedCell = _quarto.ast.walk(pendingCodeCell, { + CodeBlock = function(el) + if el.attr.classes:find('cell-code') or + el.attr.classes:find(constants.kDataCodeAnnonationClz) then + if param(constants.kSyntaxHighlighting, true) then + return nil + else + return wrapTypstAnnotatedCode(el, pendingAnnotations, pendingCellId) + end + end + end + }) + + local dlDiv = pandoc.Div(annotationBlocks, pandoc.Attr("", {constants.kCellAnnotationClass})) + if is_custom_node(resolvedCell) then + local custom = _quarto.ast.resolve_custom_data(resolvedCell) or pandoc.Div({}) + if param(constants.kSyntaxHighlighting, true) then + custom.content:insert(1, typstAnnotationMarker(pendingAnnotations, pendingCellId)) + end + custom.content:insert(dlDiv) + else + if param(constants.kSyntaxHighlighting, true) then + resolvedCell.content:insert(1, typstAnnotationMarker(pendingAnnotations, pendingCellId)) + end + resolvedCell.content:insert(dlDiv) + end + outputBlock(resolvedCell) + else + for _, ab in ipairs(annotationBlocks) do + outputBlock(ab) + end + end + pendingAnnotations = nil + pendingCellId = nil + pendingCodeCell = nil + + -- Generic handler for all other formats + else -- There are pending annotations, which means this OL is immediately after -- a code cell with annotations. Use to emit a DL describing the code local items = pandoc.List() @@ -496,7 +633,7 @@ function code_annotations() end -- compute the definition for the DD - local definitionContent = v[1].content + local definitionContent = v[1].content local annotationToken = tostring(annotationNumber); -- Only output span for certain formats (HTML) @@ -511,7 +648,7 @@ function code_annotations() {constants.kDataCodeCellAnnotation, annotationToken} } definition = pandoc.Span(definitionContent, pandoc.Attr(attribs)) - else + else definition = pandoc.Plain(definitionContent) end @@ -554,15 +691,16 @@ function code_annotations() flushPending() else if requireNonIncremental then - -- wrap in Non Incremental Div to prevent automatique + -- wrap in Non Incremental Div to prevent automatique outputBlockClearPending(pandoc.Div({dl}, pandoc.Attr("", {constants.kNonIncremental}))) - else + else outputBlockClearPending(dl) end end else flushPending() end + end -- end generic handler else outputBlockClearPending(block) end diff --git a/src/resources/formats/typst/pandoc/quarto/definitions.typ b/src/resources/formats/typst/pandoc/quarto/definitions.typ index 40dc1a164b..04c6851610 100644 --- a/src/resources/formats/typst/pandoc/quarto/definitions.typ +++ b/src/resources/formats/typst/pandoc/quarto/definitions.typ @@ -24,12 +24,95 @@ // Some quarto-specific definitions. -#show raw.where(block: true): set block( - fill: luma(230), - width: 100%, - inset: 8pt, - radius: 2pt - ) +// Code annotation support +#let quarto-circled-number(n, color: none) = context { + let c = if color != none { color } else { text.fill } + box(baseline: 15%, circle( + radius: 0.55em, + stroke: 0.5pt + c, + )[#set text(size: 0.7em, fill: c); #align(center + horizon, str(n))]) +} + +// Derive a contrasting annotation colour from a background fill. +// Light backgrounds get dark circles; dark backgrounds get light circles. +#let quarto-annote-color(bg) = { + if type(bg) == color { + let comps = bg.components(alpha: false) + let lum = if comps.len() == 1 { + comps.at(0) / 100% + } else { + 0.2126 * comps.at(0) / 100% + 0.7152 * comps.at(1) / 100% + 0.0722 * comps.at(2) / 100% + } + if lum < 0.5 { luma(200) } else { luma(60) } + } else { + luma(60) + } +} + +#let quarto-code-filename(filename, body) = { + show raw.where(block: true): it => it + block(width: 100%, radius: 2pt, clip: true, stroke: 0.5pt + luma(200))[ + #set block(spacing: 0pt) + #block(fill: luma(220), width: 100%, inset: (x: 8pt, y: 4pt))[ + #text(size: 0.85em, weight: "bold")[#filename]] + #body + ] +} + +#let quarto-code-annotation(annotations, cell-id: "", color: luma(60), body) = { + // Build a set of first-line positions per annotation number so that + // back-labels are only emitted once (avoiding duplicate labels when + // one annotation spans multiple lines). + let first-lines = (:) + for (line, num) in annotations { + let key = str(num) + if key not in first-lines or int(line) < int(first-lines.at(key)) { + first-lines.insert(key, line) + } + } + show raw.where(block: true): it => it + show raw.line: it => { + let annote-num = annotations.at(str(it.number), default: none) + if annote-num != none { + if cell-id != "" { + let lbl = cell-id + "-annote-" + str(annote-num) + let is-first = first-lines.at(str(annote-num), default: none) == str(it.number) + if is-first { + box(width: 100%)[#it #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: color)] #label(lbl + "-back")] + } else { + box(width: 100%)[#it #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: color)]] + } + } else { + box(width: 100%)[#it #h(1fr) #quarto-circled-number(annote-num, color: color)] + } + } else { + it + } + } + body +} + +#let quarto-annotation-item(cell-id, n, content) = { + if cell-id != "" { + [#block(above: 0.4em, below: 0.4em)[ + #link(label(cell-id + "-annote-" + str(n) + "-back"))[#quarto-circled-number(n)] + #h(0.4em) + #content + ] #label(cell-id + "-annote-" + str(n))] + } else { + block(above: 0.4em, below: 0.4em)[ + #quarto-circled-number(n) + #h(0.4em) + #content + ] + } +} + +// Style native raw code blocks with default inset, radius, and stroke +#show raw.where(block: true): it => block( + fill: luma(230), width: 100%, inset: 8pt, radius: 2pt, + stroke: 0.5pt + luma(200), it, +) #let block_with_new_content(old_block, new_content) = { let fields = old_block.fields() diff --git a/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-jupyter.qmd b/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-jupyter.qmd new file mode 100644 index 0000000000..609c41dfc9 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-jupyter.qmd @@ -0,0 +1,26 @@ +--- +title: Code Annotations (Cell, Jupyter) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - "quarto-circled-number" + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```{python} +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-knitr.qmd b/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-knitr.qmd new file mode 100644 index 0000000000..f2883a45b6 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-annotations/code-annotations-cell-knitr.qmd @@ -0,0 +1,26 @@ +--- +title: Code Annotations (Cell, Knitr) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - "quarto-circled-number" + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```{r} +x <- 1 # <1> +y <- 2 +z <- x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-annotations/code-annotations-native.qmd b/tests/docs/smoke-all/typst/code-annotations/code-annotations-native.qmd new file mode 100644 index 0000000000..51e0205ae0 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-annotations/code-annotations-native.qmd @@ -0,0 +1,26 @@ +--- +title: Code Annotations (Native) +format: + typst: + keep-typ: true + code-annotations: true + syntax-highlighting: idiomatic +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - "quarto-code-annotation" + - "cell-id:" + - "quarto-annotation-item" + - [] +--- + +```python +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-annotations/code-annotations-none.qmd b/tests/docs/smoke-all/typst/code-annotations/code-annotations-none.qmd new file mode 100644 index 0000000000..d5b39ac735 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-annotations/code-annotations-none.qmd @@ -0,0 +1,24 @@ +--- +title: Code Annotations (None) +format: + typst: + keep-typ: true + code-annotations: none +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - [] + - + - '#quarto-annotation-item\(' + - 'annotations: \("' +--- + +```python +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-annotations/code-annotations.qmd b/tests/docs/smoke-all/typst/code-annotations/code-annotations.qmd new file mode 100644 index 0000000000..a9c6f31227 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-annotations/code-annotations.qmd @@ -0,0 +1,26 @@ +--- +title: Code Annotations (Skylighting) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - "quarto-circled-number" + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```python +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-jupyter.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-jupyter.qmd new file mode 100644 index 0000000000..25add89663 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-jupyter.qmd @@ -0,0 +1,24 @@ +--- +title: Code Filename + Annotation (Cell, Jupyter) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\("hello\.py"\)\[\s*#Skylighting\(cell-id:' + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```{python} +#| filename: "hello.py" +print("Hello, world!") # <1> +``` + +1. Print a greeting. diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-knitr.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-knitr.qmd new file mode 100644 index 0000000000..76372384a9 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-cell-knitr.qmd @@ -0,0 +1,24 @@ +--- +title: Code Filename + Annotation (Cell, Knitr) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\("hello\.R"\)\[\s*#Skylighting\(cell-id:' + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```{r} +#| filename: "hello.R" +print("Hello, world!") # <1> +``` + +1. Print a greeting. diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-native.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-native.qmd new file mode 100644 index 0000000000..2789e01631 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation-native.qmd @@ -0,0 +1,27 @@ +--- +title: Code Filename + Annotation (Native) +format: + typst: + keep-typ: true + code-annotations: true + syntax-highlighting: idiomatic +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - "quarto-code-annotation" + - "cell-id:" + - "quarto-annotation-item" + - [] +--- + +```{.python filename="example.py"} +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-annotation.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation.qmd new file mode 100644 index 0000000000..2182af5069 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-annotation.qmd @@ -0,0 +1,26 @@ +--- +title: Code Filename + Annotation (Code Block) +format: + typst: + keep-typ: true + code-annotations: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - "quarto-annotation-item" + - "cell-id:" + - "annotations:" + - [] +--- + +```{.python filename="example.py"} +x = 1 # <1> +y = 2 +z = x + y # <2> +``` + +1. Assign x. +2. Compute sum. diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-cell-jupyter.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-cell-jupyter.qmd new file mode 100644 index 0000000000..fc839eef4f --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-cell-jupyter.qmd @@ -0,0 +1,18 @@ +--- +title: Code Filename (Cell, Jupyter) +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - [] +--- + +```{python} +#| filename: "hello.py" +print("Hello, world!") +``` diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-cell-knitr.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-cell-knitr.qmd new file mode 100644 index 0000000000..867209f751 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-cell-knitr.qmd @@ -0,0 +1,18 @@ +--- +title: Code Filename (Cell, Knitr) +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - [] +--- + +```{r} +#| filename: "hello.R" +print("Hello, world!") +``` diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename-native.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename-native.qmd new file mode 100644 index 0000000000..5f6fa3caf8 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename-native.qmd @@ -0,0 +1,19 @@ +--- +title: Code Filename (Native) +format: + typst: + keep-typ: true + syntax-highlighting: idiomatic +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - [] +--- + +```{.python filename="example.py"} +def hello(): + print("Hello, world!") +``` diff --git a/tests/docs/smoke-all/typst/code-filename/code-filename.qmd b/tests/docs/smoke-all/typst/code-filename/code-filename.qmd new file mode 100644 index 0000000000..db7f158771 --- /dev/null +++ b/tests/docs/smoke-all/typst/code-filename/code-filename.qmd @@ -0,0 +1,18 @@ +--- +title: Code Filename (Code Block) +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'quarto-code-filename\(' + - [] +--- + +```{.python filename="example.py"} +def hello(): + print("Hello, world!") +``` diff --git a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-block-no-bg/brand-monospace-block-no-bg.qmd b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-block-no-bg/brand-monospace-block-no-bg.qmd index 3e6bf00c79..6c84975a01 100644 --- a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-block-no-bg/brand-monospace-block-no-bg.qmd +++ b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-block-no-bg/brand-monospace-block-no-bg.qmd @@ -17,7 +17,7 @@ _quarto: # Even without brand bg, Skylighting override uses theme bgcolor # so that width/inset/radius are applied - 'let bgcolor = rgb\("#f1f3f5"\)' - - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)' + - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0\.5pt \+ luma\(200\), blocks\)' # No brand background-color show rule (not configured) - ['^#show raw\.where\(block: true\): set block\(fill:'] --- diff --git a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-inheritance/brand-monospace-inheritance.qmd b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-inheritance/brand-monospace-inheritance.qmd index acdf6d9ade..4b01d4ceb3 100644 --- a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-inheritance/brand-monospace-inheritance.qmd +++ b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-inheritance/brand-monospace-inheritance.qmd @@ -18,7 +18,7 @@ _quarto: - '^#show raw\.where\(block: true\): set par\(leading: 0\.75em\)$' # Quarto Skylighting override with inherited brand bg - 'let bgcolor = rgb\("#edf2f7"\)' - - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)' + - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0\.5pt \+ luma\(200\), blocks\)' # monospace-inline overrides weight to 700, inherits color, gets its own bg - '^#show raw\.where\(block: false\): set text\(weight: 700, size: 0\.85em, fill: rgb\("#2d3748"\), \)$' - '^#show raw\.where\(block: false\): content => highlight\(fill: rgb\("#fefcbf"\), content\)$' diff --git a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-with-theme/brand-monospace-with-theme.qmd b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-with-theme/brand-monospace-with-theme.qmd index 0248936596..d4c56fcff5 100644 --- a/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-with-theme/brand-monospace-with-theme.qmd +++ b/tests/docs/smoke-all/typst/syntax-highlighting/brand-monospace-with-theme/brand-monospace-with-theme.qmd @@ -18,7 +18,7 @@ _quarto: - '^#show raw\.where\(block: true\): set par\(leading: 0\.65em\)$' # Quarto Skylighting override uses brand bg (not espresso theme bg) - 'let bgcolor = rgb\("#282a36"\)' - - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)' + - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0\.5pt \+ luma\(200\), blocks\)' # Brand monospace-inline properties - '^#show raw\.where\(block: false\): set text\(weight: 500, fill: rgb\("#6c3483"\), \)$' - '^#show raw\.where\(block: false\): content => highlight\(fill: rgb\("#e8e0f0"\), content\)$' diff --git a/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-default.qmd b/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-default.qmd index de81bcf646..9dd63241bb 100644 --- a/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-default.qmd +++ b/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-default.qmd @@ -14,7 +14,7 @@ _quarto: - "#let EndLine" # Quarto override with proper block styling and arrow theme bgcolor - 'let bgcolor = rgb\("#f1f3f5"\)' - - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)' + - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0\.5pt \+ luma\(200\), blocks\)' - ["```python"] --- diff --git a/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-line-numbers.qmd b/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-line-numbers.qmd index af2fe7e9f3..b7e43d82ea 100644 --- a/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-line-numbers.qmd +++ b/tests/docs/smoke-all/typst/syntax-highlighting/skylighting-line-numbers.qmd @@ -14,7 +14,7 @@ _quarto: - '#Skylighting\(number: true' - "#KeywordTok" # Quarto override with proper block styling - - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, blocks\)' + - 'block\(fill: bgcolor, width: 100%, inset: 8pt, radius: 2pt, stroke: 0\.5pt \+ luma\(200\), blocks\)' - ["```python"] ---