@heroiclands/package-build 25.2.0 → 25.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/assets/styles/content-base.css +65 -116
- package/docs/authoring/links-and-markup.md +114 -109
- package/docs/content-format.md +20 -3
- package/docs/diagnostics.md +25 -26
- package/docs/guides/writing-in-invented-scripts.md +41 -62
- package/docs/reference/format-details.md +0 -1
- package/docs/reference/theme-pages.md +30 -57
- package/docs/source-preview.md +2 -1
- package/engine/content-blocks.mjs +3 -2
- package/engine/content-render.mjs +31 -29
- package/engine/content-scripts.mjs +180 -86
- package/engine/content-spans.mjs +4 -6
- package/engine/content-verse.mjs +482 -281
- package/engine/journals.mjs +14 -14
- package/engine/pdf-render.mjs +65 -117
- package/engine/preview-source.mjs +15 -8
- package/engine/roman-verse.mjs +68 -57
- package/engine/verse-metre.mjs +33 -40
- package/package.json +1 -1
- package/site-theme/static/css/style.css +49 -101
- package/types/engine/content-blocks.d.mts +3 -1
- package/types/engine/content-scripts.d.mts +9 -5
- package/types/engine/content-verse.d.mts +269 -83
- package/types/engine/journals.d.mts +3 -3
- package/types/engine/roman-verse.d.mts +7 -6
|
@@ -34,9 +34,8 @@
|
|
|
34
34
|
*
|
|
35
35
|
* Span, div, verse and scroll scanners retain original UTF-16 source offsets.
|
|
36
36
|
* Public diagnostics count Unicode code-point columns. A scroll's face must
|
|
37
|
-
* belong to a script written vertically
|
|
38
|
-
*
|
|
39
|
-
* its line boundary before a stanza or canto.
|
|
37
|
+
* belong to a script written vertically. An encoded verse derives native and
|
|
38
|
+
* Roman presentations from one authored text and retains explicit boundaries.
|
|
40
39
|
* @module
|
|
41
40
|
*/
|
|
42
41
|
|
|
@@ -44,7 +43,7 @@ import MarkdownIt from "markdown-it";
|
|
|
44
43
|
import { blockTokens } from "./markdown-blocks.mjs";
|
|
45
44
|
|
|
46
45
|
import { scanBlocks, BLOCK_CONTAINERS } from "./content-blocks.mjs";
|
|
47
|
-
import { scanVerse
|
|
46
|
+
import { scanVerse } from "./content-verse.mjs";
|
|
48
47
|
import { scanSpans } from "./content-spans.mjs";
|
|
49
48
|
import { scanScrolls, scrollParagraphs } from "./content-scroll.mjs";
|
|
50
49
|
import { directionsFromRecords } from "./script-direction.mjs";
|
|
@@ -1055,11 +1054,6 @@ function analyseRuns(source, ctx, syntax) {
|
|
|
1055
1054
|
nativeAt(construct),
|
|
1056
1055
|
"`.nativefont` is not an accepted class; select an encoding with `enc=`",
|
|
1057
1056
|
);
|
|
1058
|
-
if (native(construct) && construct.kind === "verse" && hasColumns(construct.node))
|
|
1059
|
-
report(
|
|
1060
|
-
construct.at("enc", "value"),
|
|
1061
|
-
"a verse with cols>1 selects encoding on individual runs, not the fence",
|
|
1062
|
-
);
|
|
1063
1057
|
|
|
1064
1058
|
if (lang !== undefined && !Object.hasOwn(languages, lang)) {
|
|
1065
1059
|
if (isLanguageTag(lang)) {
|
|
@@ -1203,41 +1197,47 @@ function analyseRuns(source, ctx, syntax) {
|
|
|
1203
1197
|
|
|
1204
1198
|
const verseMarkers = new Map();
|
|
1205
1199
|
const verseContexts = new Map();
|
|
1206
|
-
const
|
|
1207
|
-
for (const poem of scanVerse(text).blocks) {
|
|
1200
|
+
for (const poem of scanVerse(text, { checkWorks: false }).blocks) {
|
|
1208
1201
|
for (let line = poem.start + 1; line < poem.end; line++) verseContexts.set(line, poem);
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
)
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
const start = starts[part.line];
|
|
1221
|
-
if (part.prefixLength)
|
|
1222
|
-
verseMarkers.set(
|
|
1223
|
-
start + part.sourceColumn - 1,
|
|
1224
|
-
start + part.textColumn - 1,
|
|
1225
|
-
);
|
|
1226
|
-
if (part.markerLength)
|
|
1227
|
-
verseMarkers.set(
|
|
1228
|
-
start + part.markerStart,
|
|
1229
|
-
start + part.markerStart + part.markerLength,
|
|
1230
|
-
);
|
|
1231
|
-
}
|
|
1202
|
+
const bodyStart = starts[poem.start + 1];
|
|
1203
|
+
for (const [from, to] of poem.model.layout)
|
|
1204
|
+
verseMarkers.set(bodyStart + from, bodyStart + to);
|
|
1205
|
+
for (const match of poem.body.matchAll(WIKILINK)) {
|
|
1206
|
+
const bar = match[1].indexOf("|");
|
|
1207
|
+
if (bar < 0) {
|
|
1208
|
+
verseMarkers.set(
|
|
1209
|
+
bodyStart + match.index,
|
|
1210
|
+
bodyStart + match.index + match[0].length,
|
|
1211
|
+
);
|
|
1212
|
+
continue;
|
|
1232
1213
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1214
|
+
verseMarkers.set(bodyStart + match.index, bodyStart + match.index + 3 + bar);
|
|
1215
|
+
verseMarkers.set(
|
|
1216
|
+
bodyStart + match.index + match[0].indexOf("]]"),
|
|
1217
|
+
bodyStart + match.index + match[0].length,
|
|
1218
|
+
);
|
|
1219
|
+
}
|
|
1220
|
+
// Link destinations and footnote references remain Markdown; only a
|
|
1221
|
+
// link's visible label contributes text to the encoding projection.
|
|
1222
|
+
for (let at = 0; at < poem.body.length; at++) {
|
|
1223
|
+
if (poem.body[at] === "\\") {
|
|
1224
|
+
at++;
|
|
1225
|
+
continue;
|
|
1240
1226
|
}
|
|
1227
|
+
if (poem.body[at] !== "[") continue;
|
|
1228
|
+
const end = closing(poem.body, at);
|
|
1229
|
+
if (end < 0) continue;
|
|
1230
|
+
const label = poem.body.slice(at + 1, end);
|
|
1231
|
+
if (/^\^[^\s\]]+$/.test(label) && footnotes.has(label.slice(1))) {
|
|
1232
|
+
verseMarkers.set(bodyStart + at, bodyStart + end + 1);
|
|
1233
|
+
at = end;
|
|
1234
|
+
} else if (poem.body[end + 1] === "(" && poem.body[at - 1] !== "!") {
|
|
1235
|
+
const past = closing(poem.body, end + 1);
|
|
1236
|
+
if (past < 0) continue;
|
|
1237
|
+
verseMarkers.set(bodyStart + at, bodyStart + at + 1);
|
|
1238
|
+
verseMarkers.set(bodyStart + end, bodyStart + past + 1);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
1241
|
}
|
|
1242
1242
|
|
|
1243
1243
|
/** Nested spans and verse markers excluded from a run, by absolute offset. */
|
|
@@ -1560,23 +1560,7 @@ function analyseRuns(source, ctx, syntax) {
|
|
|
1560
1560
|
}
|
|
1561
1561
|
return owners.get(detail);
|
|
1562
1562
|
};
|
|
1563
|
-
|
|
1564
|
-
if (detail.run.kind === "verse") return true;
|
|
1565
|
-
if (detail.run.kind !== "span") return false;
|
|
1566
|
-
const line = detail.run.line - 1;
|
|
1567
|
-
const poem = verseContexts.get(line);
|
|
1568
|
-
if (!poem) return false;
|
|
1569
|
-
const end = starts[line] + lines[line].length;
|
|
1570
|
-
if (detail.run.end > end) return false;
|
|
1571
|
-
const reading = verseReadings.get(line);
|
|
1572
|
-
const from =
|
|
1573
|
-
hasColumns(poem) ? starts[line] + (reading?.textColumn ?? 1) - 1 : starts[line];
|
|
1574
|
-
return (
|
|
1575
|
-
from <= detail.run.start &&
|
|
1576
|
-
/^[ \t.]*$/.test(text.slice(from, detail.run.start)) &&
|
|
1577
|
-
/^[ \t\r]*$/.test(text.slice(detail.run.end, end))
|
|
1578
|
-
);
|
|
1579
|
-
};
|
|
1563
|
+
|
|
1580
1564
|
const spanDetails = new Map(
|
|
1581
1565
|
details
|
|
1582
1566
|
.filter((detail) => detail.run.kind === "span")
|
|
@@ -1604,13 +1588,17 @@ function analyseRuns(source, ctx, syntax) {
|
|
|
1604
1588
|
includeSpan: (span) =>
|
|
1605
1589
|
spanDetails.has(span.start) && ownerOf(spanDetails.get(span.start)) === owner,
|
|
1606
1590
|
};
|
|
1607
|
-
const
|
|
1591
|
+
const poem =
|
|
1592
|
+
owner.run.kind === "verse" ?
|
|
1593
|
+
poems.get(owner.run.start)
|
|
1594
|
+
: verseContexts.get(owner.run.line - 1);
|
|
1595
|
+
const verse = poem !== undefined;
|
|
1608
1596
|
const projection =
|
|
1609
1597
|
verse ?
|
|
1610
1598
|
plainRomanVerse(text, {
|
|
1611
1599
|
...projectionOptions,
|
|
1612
|
-
|
|
1613
|
-
|
|
1600
|
+
model: poem.model,
|
|
1601
|
+
modelOffset: starts[poem.start + 1],
|
|
1614
1602
|
})
|
|
1615
1603
|
: plainRomanRun(text, projectionOptions);
|
|
1616
1604
|
const before = errors.length;
|
|
@@ -1628,18 +1616,7 @@ function analyseRuns(source, ctx, syntax) {
|
|
|
1628
1616
|
);
|
|
1629
1617
|
for (const problem of projection.errors ?? [])
|
|
1630
1618
|
report(positionOf(starts, problem.offset), problem.message);
|
|
1631
|
-
|
|
1632
|
-
for (const match of projection.text.matchAll(/\//g)) {
|
|
1633
|
-
if (
|
|
1634
|
-
projection.text.lastIndexOf("⟦", match.index) >
|
|
1635
|
-
projection.text.lastIndexOf("⟧", match.index)
|
|
1636
|
-
)
|
|
1637
|
-
continue;
|
|
1638
|
-
report(
|
|
1639
|
-
positionOf(starts, projection.offsets[match.index]),
|
|
1640
|
-
"a verse fence uses authored line endings for verse boundaries; write no literal `/` inside it",
|
|
1641
|
-
);
|
|
1642
|
-
}
|
|
1619
|
+
|
|
1643
1620
|
const book = ctx.wordBooks?.get(owner.run.lang);
|
|
1644
1621
|
if (book) {
|
|
1645
1622
|
const mask = projection.text.split("");
|
|
@@ -2026,11 +2003,10 @@ function setRange(text, from, to, detail, lineStart, book) {
|
|
|
2026
2003
|
|
|
2027
2004
|
/**
|
|
2028
2005
|
* Rewrite text marked with `lang=`, `font=` and `enc=` into the plain span,
|
|
2029
|
-
* div and verse grammar the rest of each chain renders
|
|
2006
|
+
* div and verse grammar the rest of each chain renders.
|
|
2030
2007
|
*
|
|
2031
|
-
* - **
|
|
2032
|
-
*
|
|
2033
|
-
* lines and source positions remain unchanged.
|
|
2008
|
+
* - **Verse layout markers** stay outside encoded text. A shared logical
|
|
2009
|
+
* structure retains authored source positions and both presentations.
|
|
2034
2010
|
* - **The enc, if any, is applied first.** Characters Markdown would read are
|
|
2035
2011
|
* then backslash-escaped, so they reach every later pass as characters.
|
|
2036
2012
|
* - **Emphasis in a face** becomes an `<em>` or a `<strong>` carrying its
|
|
@@ -2057,7 +2033,7 @@ function setRange(text, from, to, detail, lineStart, book) {
|
|
|
2057
2033
|
* scanner projections.
|
|
2058
2034
|
* @param {{target?: "site"|"foundry"|"book"}} [options] - The target the
|
|
2059
2035
|
* Markdown is rendered for; only `site` writes the search marker.
|
|
2060
|
-
* @returns {{markdown: string, errors: Array<{file?: string, line: number, column: number, message: string}>, scrolls: Map<string, import("./content-scroll.mjs").ScrollLayout>}}
|
|
2036
|
+
* @returns {{markdown: string, errors: Array<{file?: string, line: number, column: number, message: string}>, scrolls: Map<string, import("./content-scroll.mjs").ScrollLayout>, verses: Map<string, {model: ReturnType<typeof import("./content-verse.mjs").parseVerse>, classes: string[], attributes: Record<string, string>}>}}
|
|
2061
2037
|
* The rewritten Markdown, the findings of {@link scanRuns}, and each
|
|
2062
2038
|
* rewritten scroll fence's layout, by its rewritten body.
|
|
2063
2039
|
*/
|
|
@@ -2067,11 +2043,12 @@ export function renderRuns(source, ctx = {}, syntax, options = {}) {
|
|
|
2067
2043
|
const text = String(source ?? "");
|
|
2068
2044
|
/** @type {Map<string, import("./content-scroll.mjs").ScrollLayout>} */
|
|
2069
2045
|
const scrolls = new Map();
|
|
2046
|
+
const verses = new Map();
|
|
2070
2047
|
if (!/\b(?:lang|font|enc)=|\bnativefont\b|\.(?:emph|strong)\b|⟦/.test(text))
|
|
2071
|
-
return { markdown: text, errors: [], scrolls };
|
|
2048
|
+
return { markdown: text, errors: [], scrolls, verses };
|
|
2072
2049
|
const { details, errors } = analyseRuns(text, ctx, syntax);
|
|
2073
2050
|
if (!details.length)
|
|
2074
|
-
return { markdown: text, errors: diagnosticColumns(text, errors), scrolls };
|
|
2051
|
+
return { markdown: text, errors: diagnosticColumns(text, errors), scrolls, verses };
|
|
2075
2052
|
const lines = text.split("\n");
|
|
2076
2053
|
const starts = lineStarts(text);
|
|
2077
2054
|
|
|
@@ -2090,6 +2067,18 @@ export function renderRuns(source, ctx = {}, syntax, options = {}) {
|
|
|
2090
2067
|
|
|
2091
2068
|
/** @type {Array<{from: number, to: number, text: string}>} */
|
|
2092
2069
|
const edits = [];
|
|
2070
|
+
const poems = scanVerse(text, { checkWorks: false }).blocks;
|
|
2071
|
+
const logicalRanges = poems.flatMap((poem) => {
|
|
2072
|
+
const base = starts[poem.start + 1];
|
|
2073
|
+
return poem.model.groups.flatMap((group) =>
|
|
2074
|
+
group.cantoBreak ? [] : group.lines.map((line) => [base + line.from, base + line.to]),
|
|
2075
|
+
);
|
|
2076
|
+
});
|
|
2077
|
+
const rangesWithin = (from, to) => {
|
|
2078
|
+
const cuts = logicalRanges.flat().filter((at) => at > from && at < to);
|
|
2079
|
+
const points = [from, ...new Set(cuts.sort((a, b) => a - b)), to];
|
|
2080
|
+
return points.slice(1).map((past, index) => [points[index], past]);
|
|
2081
|
+
};
|
|
2093
2082
|
|
|
2094
2083
|
/**
|
|
2095
2084
|
* A scroll fence's body set as one line per paragraph, and its layout.
|
|
@@ -2207,8 +2196,11 @@ export function renderRuns(source, ctx = {}, syntax, options = {}) {
|
|
|
2207
2196
|
for (const [from, to] of detail.reference ?
|
|
2208
2197
|
[detail.reference]
|
|
2209
2198
|
: outsideHoles(run.start + 1, contentEnd, detail.holes)) {
|
|
2210
|
-
const
|
|
2211
|
-
|
|
2199
|
+
for (const [first, past] of rangesWithin(from, to)) {
|
|
2200
|
+
const set = setRange(text, first, past, detail, false, book);
|
|
2201
|
+
if (set !== text.slice(first, past))
|
|
2202
|
+
edits.push({ from: first, to: past, text: set });
|
|
2203
|
+
}
|
|
2212
2204
|
}
|
|
2213
2205
|
continue;
|
|
2214
2206
|
}
|
|
@@ -2239,9 +2231,12 @@ export function renderRuns(source, ctx = {}, syntax, options = {}) {
|
|
|
2239
2231
|
}
|
|
2240
2232
|
if (detail.plain && detail.body)
|
|
2241
2233
|
for (const [from, to] of outsideHoles(detail.body[0], detail.body[1], detail.holes)) {
|
|
2242
|
-
const
|
|
2243
|
-
|
|
2244
|
-
|
|
2234
|
+
for (const [first, past] of rangesWithin(from, to)) {
|
|
2235
|
+
const lineStart = first === 0 || text[first - 1] === "\n";
|
|
2236
|
+
const set = setRange(text, first, past, detail, lineStart, book);
|
|
2237
|
+
if (set !== text.slice(first, past))
|
|
2238
|
+
edits.push({ from: first, to: past, text: set });
|
|
2239
|
+
}
|
|
2245
2240
|
}
|
|
2246
2241
|
}
|
|
2247
2242
|
|
|
@@ -2268,5 +2263,104 @@ export function renderRuns(source, ctx = {}, syntax, options = {}) {
|
|
|
2268
2263
|
let markdown = text;
|
|
2269
2264
|
for (const edit of edits.sort((a, b) => b.from - a.from))
|
|
2270
2265
|
markdown = markdown.slice(0, edit.from) + edit.text + markdown.slice(edit.to);
|
|
2271
|
-
|
|
2266
|
+
// Models retain authored structure; a native script may draw the boundaries
|
|
2267
|
+
// as glyphs which must not be reparsed as Roman delimiters.
|
|
2268
|
+
const rewritten = scanVerse(markdown, { checkWorks: false }).blocks;
|
|
2269
|
+
const pairedEdits = [];
|
|
2270
|
+
for (const [index, poem] of poems.entries()) {
|
|
2271
|
+
const detail = details.find(
|
|
2272
|
+
(detail) => detail.run.kind === "verse" && detail.run.start === poem.start,
|
|
2273
|
+
);
|
|
2274
|
+
if (!detail || detail.run.enc === "default" || !detail.selection || faulted(detail.run))
|
|
2275
|
+
continue;
|
|
2276
|
+
const block = rewritten[index];
|
|
2277
|
+
if (!block) continue;
|
|
2278
|
+
const base = starts[poem.start + 1];
|
|
2279
|
+
const applyLine = (line) => {
|
|
2280
|
+
const patches = [];
|
|
2281
|
+
for (const edit of edits) {
|
|
2282
|
+
const positions = line.offsets.flatMap((offset, index) => {
|
|
2283
|
+
const sourceOffset = base + offset;
|
|
2284
|
+
return sourceOffset >= edit.from && sourceOffset < edit.to ? [index] : [];
|
|
2285
|
+
});
|
|
2286
|
+
if (positions.length)
|
|
2287
|
+
patches.push({ from: positions[0], to: positions.at(-1) + 1, text: edit.text });
|
|
2288
|
+
else if (edit.from === edit.to && edit.from === base + line.to)
|
|
2289
|
+
patches.push({ from: line.text.length, to: line.text.length, text: edit.text });
|
|
2290
|
+
}
|
|
2291
|
+
let result = line.text;
|
|
2292
|
+
for (const edit of patches.sort((a, b) => b.from - a.from))
|
|
2293
|
+
result = result.slice(0, edit.from) + edit.text + result.slice(edit.to);
|
|
2294
|
+
return result.replace(/\r?\n[ ]*/g, "").trim();
|
|
2295
|
+
};
|
|
2296
|
+
const rewriteSpanAttributes = (source, rewrite) => {
|
|
2297
|
+
const changes = scanSpans(source).spans.flatMap((span) => {
|
|
2298
|
+
const attrs = parseExtensionAttributes(
|
|
2299
|
+
source.slice(span.contentEnd + 2, span.end - 1),
|
|
2300
|
+
);
|
|
2301
|
+
if (!rewrite(attrs, span)) return [];
|
|
2302
|
+
return [
|
|
2303
|
+
{
|
|
2304
|
+
from: span.contentEnd + 2,
|
|
2305
|
+
to: span.end - 1,
|
|
2306
|
+
text: attributeText({
|
|
2307
|
+
lang: attrs.values.lang,
|
|
2308
|
+
id: attrs.id,
|
|
2309
|
+
classes: attrs.classes,
|
|
2310
|
+
values: Object.entries(attrs.values).filter(([key]) => key !== "lang"),
|
|
2311
|
+
}),
|
|
2312
|
+
},
|
|
2313
|
+
];
|
|
2314
|
+
});
|
|
2315
|
+
let result = source;
|
|
2316
|
+
for (const change of changes.sort((a, b) => b.from - a.from))
|
|
2317
|
+
result = result.slice(0, change.from) + change.text + result.slice(change.to);
|
|
2318
|
+
return result;
|
|
2319
|
+
};
|
|
2320
|
+
const romanLine = (source) =>
|
|
2321
|
+
rewriteSpanAttributes(source, (attrs) => {
|
|
2322
|
+
const lang = attrs.values.lang;
|
|
2323
|
+
if (lang !== undefined) attrs.values.lang = ctx.languages?.[lang]?.tag ?? lang;
|
|
2324
|
+
delete attrs.values.enc;
|
|
2325
|
+
delete attrs.values.font;
|
|
2326
|
+
attrs.id = "";
|
|
2327
|
+
return true;
|
|
2328
|
+
});
|
|
2329
|
+
const model = structuredClone(poem.model);
|
|
2330
|
+
for (const group of model.groups) {
|
|
2331
|
+
if (group.cantoBreak) {
|
|
2332
|
+
group.text = detail.selection.encoding.controls.verseCanto ?? "";
|
|
2333
|
+
continue;
|
|
2334
|
+
}
|
|
2335
|
+
for (const line of group.lines) {
|
|
2336
|
+
line.romanText = romanLine(line.text);
|
|
2337
|
+
const ids = new Set(
|
|
2338
|
+
scanSpans(line.text)
|
|
2339
|
+
.spans.map((span) => span.id)
|
|
2340
|
+
.filter(Boolean),
|
|
2341
|
+
);
|
|
2342
|
+
line.text = rewriteSpanAttributes(applyLine(line), (attrs, span) => {
|
|
2343
|
+
if (!span.id || ids.has(span.id)) return false;
|
|
2344
|
+
attrs.id = "";
|
|
2345
|
+
return true;
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
const classes = [SCRIPT_CLASS, ...(detail.face ? [detail.face.class] : [])];
|
|
2350
|
+
const attributes = {
|
|
2351
|
+
...(detail.run.tag ? { lang: detail.run.tag } : {}),
|
|
2352
|
+
...(detail.face?.direction === "rtl" ? { dir: "rtl" } : {}),
|
|
2353
|
+
...(search ? { "data-pagefind-ignore": "true" } : {}),
|
|
2354
|
+
};
|
|
2355
|
+
const body = `<!--verse-pair:${verses.size + 1}-->\n${block.body}`;
|
|
2356
|
+
verses.set(body, { model, classes, attributes });
|
|
2357
|
+
const rewrittenStarts = lineStarts(markdown);
|
|
2358
|
+
pairedEdits.push({
|
|
2359
|
+
at: rewrittenStarts[block.start + 1],
|
|
2360
|
+
text: `<!--verse-pair:${verses.size}-->\n`,
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
for (const edit of pairedEdits.sort((a, b) => b.at - a.at))
|
|
2364
|
+
markdown = markdown.slice(0, edit.at) + edit.text + markdown.slice(edit.at);
|
|
2365
|
+
return { markdown, errors: diagnosticColumns(text, errors), scrolls, verses };
|
|
2272
2366
|
}
|
package/engine/content-spans.mjs
CHANGED
|
@@ -293,12 +293,10 @@ export function scanSpans(source) {
|
|
|
293
293
|
}
|
|
294
294
|
// Verse fences preserve inline Markdown even though the block parser
|
|
295
295
|
// normally treats every code fence as literal text.
|
|
296
|
-
for (const poem of scanVerse(text).blocks) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
collect(children, (pos) => starts[line] + pos);
|
|
301
|
-
}
|
|
296
|
+
for (const poem of scanVerse(text, { checkWorks: false }).blocks) {
|
|
297
|
+
const children = [];
|
|
298
|
+
parser.inline.parse(poem.body, parser, env, children);
|
|
299
|
+
collect(children, (pos) => starts[poem.start + 1] + pos);
|
|
302
300
|
}
|
|
303
301
|
spans.sort((a, b) => a.start - b.start);
|
|
304
302
|
errors.sort((a, b) => a.line - b.line || a.column - b.column);
|