Skip to content

Commit 5c8b344

Browse files
committed
fix: ensure back-labels are emitted only once
1 parent ac932e9 commit 5c8b344

3 files changed

Lines changed: 37 additions & 13 deletions

File tree

src/format/typst/format-typst.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ function skylightingPostProcessor(brandBgColor?: string) {
210210
/\/\/ quarto-code-annotations: ([\w-]*) (\([^)]*\))\n(\s*(?:#block\[\s*)*(?:#quarto-code-filename\([^\n]*\)\[\s*)?)#Skylighting\(/g;
211211

212212
return async (output: string) => {
213-
let content = Deno.readTextFileSync(output);
213+
let content = Deno.readTextFileSync(output).replace(/\r\n/g, "\n");
214214
let changed = false;
215215

216216
const match = skylightingFnRe.exec(content);
@@ -243,14 +243,27 @@ function skylightingPostProcessor(brandBgColor?: string) {
243243
"lnum = lnum + 1\n if number {\n",
244244
);
245245

246+
// Initialise a dictionary to track which annotation numbers have
247+
// already emitted a back-label (avoids duplicate labels when one
248+
// annotation spans multiple lines).
249+
fn = fn.replace(
250+
/let lnum = start - 1\n/,
251+
"let lnum = start - 1\n let seen-annotes = (:)\n",
252+
);
253+
246254
// Add annotation rendering per line (derive circle colour from bgcolor)
247255
fn = fn.replace(
248256
"blocks = blocks + ln + EndLine()",
249257
`let annote-num = annotations.at(str(lnum), default: none)
250258
if annote-num != none {
251259
if cell-id != "" {
252260
let lbl = cell-id + "-annote-" + str(annote-num)
253-
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()
261+
if str(annote-num) not in seen-annotes {
262+
seen-annotes.insert(str(annote-num), true)
263+
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()
264+
} else {
265+
blocks = blocks + box(width: 100%)[#ln #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: quarto-annote-color(bgcolor))]] + EndLine()
266+
}
254267
} else {
255268
blocks = blocks + box(width: 100%)[#ln #h(1fr) #quarto-circled-number(annote-num, color: quarto-annote-color(bgcolor))] + EndLine()
256269
}

src/resources/filters/quarto-pre/code-annotation.lua

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,16 @@ local function wrapTypstAnnotatedCode(codeBlock, annotations, cellId)
126126
adjustedAnnotations[annoteId] = adjusted
127127
end
128128
local dict = typstAnnotationsDict(adjustedAnnotations)
129-
local cellIdParam = ""
130-
if cellId and cellId ~= "" then
131-
cellIdParam = ", cell-id: \"" .. cellId .. "\""
132-
end
133129
local lang = codeBlock.attr.classes[1] or ""
134130
local code = codeBlock.text
135131
local maxBackticks = 2
136132
for seq in code:gmatch("`+") do
137133
maxBackticks = math.max(maxBackticks, #seq)
138134
end
139135
local fence = string.rep("`", maxBackticks + 1)
140-
local raw = "#quarto-code-annotation(" .. dict .. cellIdParam .. ")[" .. fence .. lang .. "\n" .. code .. "\n" .. fence .. "]"
136+
local raw = "#quarto-code-annotation(" .. dict
137+
.. (cellId and cellId ~= "" and (", cell-id: \"" .. cellId .. "\"") or "")
138+
.. ")[" .. fence .. lang .. "\n" .. code .. "\n" .. fence .. "]"
141139
return pandoc.RawBlock("typst", raw)
142140
end
143141

@@ -568,14 +566,12 @@ function code_annotations()
568566
end
569567
end
570568

571-
local useSkylighting = param(constants.kSyntaxHighlighting, true)
572-
573569
if pendingCodeCell ~= nil then
574570
local resolvedCell = _quarto.ast.walk(pendingCodeCell, {
575571
CodeBlock = function(el)
576572
if el.attr.classes:find('cell-code') or
577573
el.attr.classes:find(constants.kDataCodeAnnonationClz) then
578-
if useSkylighting then
574+
if param(constants.kSyntaxHighlighting, true) then
579575
return nil
580576
else
581577
return wrapTypstAnnotatedCode(el, pendingAnnotations, pendingCellId)
@@ -587,12 +583,12 @@ function code_annotations()
587583
local dlDiv = pandoc.Div(annotationBlocks, pandoc.Attr("", {constants.kCellAnnotationClass}))
588584
if is_custom_node(resolvedCell) then
589585
local custom = _quarto.ast.resolve_custom_data(resolvedCell) or pandoc.Div({})
590-
if useSkylighting then
586+
if param(constants.kSyntaxHighlighting, true) then
591587
custom.content:insert(1, typstAnnotationMarker(pendingAnnotations, pendingCellId))
592588
end
593589
custom.content:insert(dlDiv)
594590
else
595-
if useSkylighting then
591+
if param(constants.kSyntaxHighlighting, true) then
596592
resolvedCell.content:insert(1, typstAnnotationMarker(pendingAnnotations, pendingCellId))
597593
end
598594
resolvedCell.content:insert(dlDiv)

src/resources/formats/typst/pandoc/quarto/definitions.typ

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,28 @@
6060
}
6161

6262
#let quarto-code-annotation(annotations, cell-id: "", color: luma(60), body) = {
63+
// Build a set of first-line positions per annotation number so that
64+
// back-labels are only emitted once (avoiding duplicate labels when
65+
// one annotation spans multiple lines).
66+
let first-lines = (:)
67+
for (line, num) in annotations {
68+
let key = str(num)
69+
if key not in first-lines or int(line) < int(first-lines.at(key)) {
70+
first-lines.insert(key, line)
71+
}
72+
}
6373
show raw.where(block: true): it => it
6474
show raw.line: it => {
6575
let annote-num = annotations.at(str(it.number), default: none)
6676
if annote-num != none {
6777
if cell-id != "" {
6878
let lbl = cell-id + "-annote-" + str(annote-num)
69-
box(width: 100%)[#it #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: color)] #label(lbl + "-back")]
79+
let is-first = first-lines.at(str(annote-num), default: none) == str(it.number)
80+
if is-first {
81+
box(width: 100%)[#it #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: color)] #label(lbl + "-back")]
82+
} else {
83+
box(width: 100%)[#it #h(1fr) #link(label(lbl))[#quarto-circled-number(annote-num, color: color)]]
84+
}
7085
} else {
7186
box(width: 100%)[#it #h(1fr) #quarto-circled-number(annote-num, color: color)]
7287
}

0 commit comments

Comments
 (0)