postext 0.3.5 → 0.3.7
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/dist/__tests__/exports.test.js +1 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/canvas-backend/blockRender.d.ts +3 -0
- package/dist/canvas-backend/blockRender.d.ts.map +1 -0
- package/dist/canvas-backend/blockRender.js +176 -0
- package/dist/canvas-backend/blockRender.js.map +1 -0
- package/dist/canvas-backend/decorations.d.ts +6 -0
- package/dist/canvas-backend/decorations.d.ts.map +1 -0
- package/dist/canvas-backend/decorations.js +106 -0
- package/dist/canvas-backend/decorations.js.map +1 -0
- package/dist/{canvas-backend.d.ts → canvas-backend/index.d.ts} +2 -2
- package/dist/canvas-backend/index.d.ts.map +1 -0
- package/dist/canvas-backend/index.js +66 -0
- package/dist/canvas-backend/index.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/knuthPlass/breakpoints.d.ts +6 -0
- package/dist/knuthPlass/breakpoints.d.ts.map +1 -0
- package/dist/knuthPlass/breakpoints.js +284 -0
- package/dist/knuthPlass/breakpoints.js.map +1 -0
- package/dist/knuthPlass/constants.d.ts +8 -0
- package/dist/knuthPlass/constants.d.ts.map +1 -0
- package/dist/knuthPlass/constants.js +8 -0
- package/dist/knuthPlass/constants.js.map +1 -0
- package/dist/knuthPlass/index.d.ts +12 -0
- package/dist/knuthPlass/index.d.ts.map +1 -0
- package/dist/knuthPlass/index.js +11 -0
- package/dist/knuthPlass/index.js.map +1 -0
- package/dist/knuthPlass/pretextAdapter.d.ts +12 -0
- package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -0
- package/dist/knuthPlass/pretextAdapter.js +178 -0
- package/dist/knuthPlass/pretextAdapter.js.map +1 -0
- package/dist/knuthPlass/richAdapter.d.ts +26 -0
- package/dist/knuthPlass/richAdapter.d.ts.map +1 -0
- package/dist/knuthPlass/richAdapter.js +189 -0
- package/dist/knuthPlass/richAdapter.js.map +1 -0
- package/dist/{knuthPlass.d.ts → knuthPlass/types.d.ts} +1 -31
- package/dist/knuthPlass/types.d.ts.map +1 -0
- package/dist/knuthPlass/types.js +5 -0
- package/dist/knuthPlass/types.js.map +1 -0
- package/dist/knuthPlass/utils.d.ts +2 -0
- package/dist/knuthPlass/utils.d.ts.map +1 -0
- package/dist/knuthPlass/utils.js +4 -0
- package/dist/knuthPlass/utils.js.map +1 -0
- package/dist/math/rasterCache.d.ts.map +1 -1
- package/dist/math/rasterCache.js +29 -6
- package/dist/math/rasterCache.js.map +1 -1
- package/dist/measure/cache.d.ts +5 -0
- package/dist/measure/cache.d.ts.map +1 -0
- package/dist/measure/cache.js +38 -0
- package/dist/measure/cache.js.map +1 -0
- package/dist/measure/canvas.d.ts +8 -0
- package/dist/measure/canvas.d.ts.map +1 -0
- package/dist/measure/canvas.js +30 -0
- package/dist/measure/canvas.js.map +1 -0
- package/dist/measure/font.d.ts +19 -0
- package/dist/measure/font.d.ts.map +1 -0
- package/dist/measure/font.js +34 -0
- package/dist/measure/font.js.map +1 -0
- package/dist/measure/index.d.ts +7 -0
- package/dist/measure/index.d.ts.map +1 -0
- package/dist/measure/index.js +6 -0
- package/dist/measure/index.js.map +1 -0
- package/dist/measure/plain.d.ts +13 -0
- package/dist/measure/plain.d.ts.map +1 -0
- package/dist/measure/plain.js +167 -0
- package/dist/measure/plain.js.map +1 -0
- package/dist/measure/rich.d.ts +25 -0
- package/dist/measure/rich.d.ts.map +1 -0
- package/dist/measure/rich.js +246 -0
- package/dist/measure/rich.js.map +1 -0
- package/dist/measure/types.d.ts +28 -0
- package/dist/measure/types.d.ts.map +1 -0
- package/dist/measure/types.js +2 -0
- package/dist/measure/types.js.map +1 -0
- package/dist/parse/blockParser.d.ts +28 -0
- package/dist/parse/blockParser.d.ts.map +1 -0
- package/dist/parse/blockParser.js +302 -0
- package/dist/parse/blockParser.js.map +1 -0
- package/dist/parse/index.d.ts +4 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +3 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/inlineFormatting.d.ts +12 -0
- package/dist/parse/inlineFormatting.d.ts.map +1 -0
- package/dist/parse/inlineFormatting.js +90 -0
- package/dist/parse/inlineFormatting.js.map +1 -0
- package/dist/parse/inlineMath.d.ts +29 -0
- package/dist/parse/inlineMath.d.ts.map +1 -0
- package/dist/parse/inlineMath.js +141 -0
- package/dist/parse/inlineMath.js.map +1 -0
- package/dist/parse/sourceMapping.d.ts +12 -0
- package/dist/parse/sourceMapping.d.ts.map +1 -0
- package/dist/parse/sourceMapping.js +130 -0
- package/dist/parse/sourceMapping.js.map +1 -0
- package/dist/{parse.d.ts → parse/types.d.ts} +2 -25
- package/dist/parse/types.d.ts.map +1 -0
- package/dist/parse/types.js +2 -0
- package/dist/parse/types.js.map +1 -0
- package/dist/pipeline/build.d.ts +13 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +43 -277
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/buildBlockKind.d.ts +33 -0
- package/dist/pipeline/buildBlockKind.d.ts.map +1 -0
- package/dist/pipeline/buildBlockKind.js +82 -0
- package/dist/pipeline/buildBlockKind.js.map +1 -0
- package/dist/pipeline/buildHelpers.d.ts +47 -0
- package/dist/pipeline/buildHelpers.d.ts.map +1 -0
- package/dist/pipeline/buildHelpers.js +169 -0
- package/dist/pipeline/buildHelpers.js.map +1 -0
- package/dist/pipeline/buildMeasurement.d.ts +27 -0
- package/dist/pipeline/buildMeasurement.d.ts.map +1 -0
- package/dist/pipeline/buildMeasurement.js +49 -0
- package/dist/pipeline/buildMeasurement.js.map +1 -0
- package/dist/pipeline/index.d.ts +2 -1
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +1 -1
- package/dist/pipeline/index.js.map +1 -1
- package/dist/worker/client.d.ts +21 -0
- package/dist/worker/client.d.ts.map +1 -0
- package/dist/worker/client.js +98 -0
- package/dist/worker/client.js.map +1 -0
- package/dist/worker/layout.worker.d.ts +2 -0
- package/dist/worker/layout.worker.d.ts.map +1 -0
- package/dist/worker/layout.worker.js +121 -0
- package/dist/worker/layout.worker.js.map +1 -0
- package/dist/worker/protocol.d.ts +43 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +2 -0
- package/dist/worker/protocol.js.map +1 -0
- package/package.json +9 -1
- package/dist/canvas-backend.d.ts.map +0 -1
- package/dist/canvas-backend.js +0 -370
- package/dist/canvas-backend.js.map +0 -1
- package/dist/knuthPlass.d.ts.map +0 -1
- package/dist/knuthPlass.js +0 -665
- package/dist/knuthPlass.js.map +0 -1
- package/dist/measure.d.ts +0 -61
- package/dist/measure.d.ts.map +0 -1
- package/dist/measure.js +0 -512
- package/dist/measure.js.map +0 -1
- package/dist/parse.d.ts.map +0 -1
- package/dist/parse.js +0 -653
- package/dist/parse.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceMapping.d.ts","sourceRoot":"","sources":["../../src/parse/sourceMapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA+F1C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,UAAU,EAAE,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CA0B5D"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { MATH_PLACEHOLDER } from './inlineMath';
|
|
2
|
+
/**
|
|
3
|
+
* Build a per-character map from plain text to absolute source offsets.
|
|
4
|
+
* Greedy matches each plain char against the raw source (delimited by
|
|
5
|
+
* [blockSrcStart, blockSrcEnd)), skipping markdown markers and treating
|
|
6
|
+
* newlines/tabs as spaces for paragraph line joins.
|
|
7
|
+
*/
|
|
8
|
+
function computeSourceMap(markdown, blockSrcStart, blockSrcEnd, plainText) {
|
|
9
|
+
const map = new Array(plainText.length);
|
|
10
|
+
let r = blockSrcStart;
|
|
11
|
+
for (let p = 0; p < plainText.length; p++) {
|
|
12
|
+
const ch = plainText[p];
|
|
13
|
+
// Math placeholder: the plain char represents `$...$` in the markdown.
|
|
14
|
+
// Advance to the opening `$`, map to it, then skip past the closing `$`
|
|
15
|
+
// so subsequent plain chars can keep aligning with the source.
|
|
16
|
+
if (ch === MATH_PLACEHOLDER) {
|
|
17
|
+
while (r < blockSrcEnd && markdown[r] !== '$')
|
|
18
|
+
r++;
|
|
19
|
+
if (r >= blockSrcEnd) {
|
|
20
|
+
map[p] = blockSrcEnd;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
map[p] = r;
|
|
24
|
+
let j = r + 1;
|
|
25
|
+
while (j < blockSrcEnd) {
|
|
26
|
+
if (markdown[j] === '\\' && markdown[j + 1] === '$') {
|
|
27
|
+
j += 2;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (markdown[j] === '$') {
|
|
31
|
+
j++;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (markdown[j] === '\n')
|
|
35
|
+
break;
|
|
36
|
+
j++;
|
|
37
|
+
}
|
|
38
|
+
r = j;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const isSpace = ch === ' ';
|
|
42
|
+
while (r < blockSrcEnd) {
|
|
43
|
+
const rc = markdown[r];
|
|
44
|
+
if (rc === ch)
|
|
45
|
+
break;
|
|
46
|
+
if (isSpace && (rc === '\n' || rc === '\t'))
|
|
47
|
+
break;
|
|
48
|
+
r++;
|
|
49
|
+
}
|
|
50
|
+
if (r >= blockSrcEnd) {
|
|
51
|
+
map[p] = blockSrcEnd;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
map[p] = r;
|
|
55
|
+
r++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return map;
|
|
59
|
+
}
|
|
60
|
+
const COLLAPSIBLE_WS_RE = /[ \t\n\r\f]/;
|
|
61
|
+
/**
|
|
62
|
+
* Collapse runs of `[ \t\n\r\f]` to a single space and strip leading/trailing
|
|
63
|
+
* whitespace across spans. Mirrors pretext's `normalizeWhitespaceNormal` so
|
|
64
|
+
* that `spans` and the block's plain text stay aligned with what the layout
|
|
65
|
+
* engine actually renders — otherwise cursor/selection mapping drifts by one
|
|
66
|
+
* character per collapsed whitespace character.
|
|
67
|
+
*/
|
|
68
|
+
function normalizeWhitespaceInSpans(spans) {
|
|
69
|
+
const out = [];
|
|
70
|
+
let inSpace = true; // start true to strip leading whitespace
|
|
71
|
+
for (const span of spans) {
|
|
72
|
+
let result = '';
|
|
73
|
+
for (const ch of span.text) {
|
|
74
|
+
if (COLLAPSIBLE_WS_RE.test(ch)) {
|
|
75
|
+
if (!inSpace) {
|
|
76
|
+
result += ' ';
|
|
77
|
+
inSpace = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
result += ch;
|
|
82
|
+
inSpace = false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
out.push({ ...span, text: result });
|
|
86
|
+
}
|
|
87
|
+
// Strip trailing space from the last span that contributed content
|
|
88
|
+
for (let i = out.length - 1; i >= 0; i--) {
|
|
89
|
+
const text = out[i].text;
|
|
90
|
+
if (text.length === 0)
|
|
91
|
+
continue;
|
|
92
|
+
if (text.endsWith(' ')) {
|
|
93
|
+
out[i] = { ...out[i], text: text.slice(0, -1) };
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
return out.filter((s) => s.text.length > 0);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build normalized text, spans, and sourceMap for a block. The plain text is
|
|
101
|
+
* whitespace-normalized to match pretext's internal normalization so that the
|
|
102
|
+
* per-character `sourceMap` aligns with rendered line segments.
|
|
103
|
+
*/
|
|
104
|
+
export function buildBlockMapping(markdown, blockSrcStart, blockSrcEnd, rawSpans) {
|
|
105
|
+
const rawText = rawSpans.map((s) => s.text).join('');
|
|
106
|
+
const rawSourceMap = computeSourceMap(markdown, blockSrcStart, blockSrcEnd, rawText);
|
|
107
|
+
const spans = normalizeWhitespaceInSpans(rawSpans);
|
|
108
|
+
const text = spans.map((s) => s.text).join('');
|
|
109
|
+
// Walk the raw text building the same normalization, and project each kept
|
|
110
|
+
// normalized character onto the rawSourceMap to obtain the source offset.
|
|
111
|
+
const sourceMap = [];
|
|
112
|
+
let inSpace = true;
|
|
113
|
+
for (let i = 0; i < rawText.length; i++) {
|
|
114
|
+
const ch = rawText[i];
|
|
115
|
+
if (COLLAPSIBLE_WS_RE.test(ch)) {
|
|
116
|
+
if (!inSpace) {
|
|
117
|
+
sourceMap.push(rawSourceMap[i] ?? blockSrcEnd);
|
|
118
|
+
inSpace = true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
sourceMap.push(rawSourceMap[i] ?? blockSrcEnd);
|
|
123
|
+
inSpace = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (sourceMap.length > text.length)
|
|
127
|
+
sourceMap.length = text.length;
|
|
128
|
+
return { text, spans, sourceMap };
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=sourceMapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceMapping.js","sourceRoot":"","sources":["../../src/parse/sourceMapping.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ export interface InlineSpan {
|
|
|
18
18
|
math?: MathMeta;
|
|
19
19
|
/** Resolved math render — populated by the pipeline before measurement
|
|
20
20
|
* so the parser remains free of MathJax dependencies. */
|
|
21
|
-
mathRender?: import('
|
|
21
|
+
mathRender?: import('../math/types').MathRender;
|
|
22
22
|
}
|
|
23
23
|
/** Convenience discriminants for inline span iteration. */
|
|
24
24
|
export type TextSpan = InlineSpan & {
|
|
@@ -66,27 +66,4 @@ export interface ContentBlock {
|
|
|
66
66
|
*/
|
|
67
67
|
sourceMap: number[];
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
* span. One code unit per formula so `sourceMap` stays 1-to-1. */
|
|
71
|
-
export declare const MATH_PLACEHOLDER = "\uFFFC";
|
|
72
|
-
/**
|
|
73
|
-
* Memoized wrapper around parseMarkdown: returns the cached result when the
|
|
74
|
-
* input string is byte-for-byte identical to the previous call. This avoids
|
|
75
|
-
* reparsing the whole document on each keystroke when upstream recomputes
|
|
76
|
-
* only because a sibling state changed.
|
|
77
|
-
*/
|
|
78
|
-
export declare function parseMarkdownMemo(markdown: string): ContentBlock[];
|
|
79
|
-
export declare function parseMarkdownWithIssuesMemo(markdown: string): {
|
|
80
|
-
blocks: ContentBlock[];
|
|
81
|
-
issues: ParseIssue[];
|
|
82
|
-
};
|
|
83
|
-
export declare function parseMarkdown(markdown: string): ContentBlock[];
|
|
84
|
-
/**
|
|
85
|
-
* Merge consecutive blockquote lines into a single block, and consecutive
|
|
86
|
-
* non-blank, non-special lines into paragraphs.
|
|
87
|
-
*/
|
|
88
|
-
export declare function parseMarkdownWithIssues(markdown: string): {
|
|
89
|
-
blocks: ContentBlock[];
|
|
90
|
-
issues: ParseIssue[];
|
|
91
|
-
};
|
|
92
|
-
//# sourceMappingURL=parse.d.ts.map
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/parse/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,YAAY,GACZ,UAAU,GACV,aAAa,CAAC;AAElB;;sEAEsE;AACtE,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB;uEACmE;IACnE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;8DAC0D;IAC1D,UAAU,CAAC,EAAE,OAAO,eAAe,EAAE,UAAU,CAAC;CACjD;AAED,2DAA2D;AAC3D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG;IAAE,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,mBAAmB,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC;IACtB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB;mCAC+B;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/parse/types.ts"],"names":[],"mappings":""}
|
package/dist/pipeline/build.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { PostextContent, PostextConfig } from '../types';
|
|
2
2
|
import { type VDTDocument } from '../vdt';
|
|
3
3
|
import type { MeasurementCache } from '../measure';
|
|
4
|
-
export
|
|
4
|
+
export interface BuildDocumentOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Cooperative cancellation hook. Called once per top-level content block
|
|
7
|
+
* during placement. Throw (or return a truthy value checked by the caller)
|
|
8
|
+
* to abort. Intended for running `buildDocument` inside a Web Worker where
|
|
9
|
+
* a newer request has superseded this one.
|
|
10
|
+
*/
|
|
11
|
+
shouldCancel?: () => boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class BuildCancelledError extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare function buildDocument(content: PostextContent, config?: PostextConfig, cache?: MeasurementCache, options?: BuildDocumentOptions): VDTDocument;
|
|
5
17
|
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/pipeline/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9D,OAAO,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/pipeline/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9D,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,QAAQ,CAAC;AAKhB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4BnD,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;CAC9B;AAED,qBAAa,mBAAoB,SAAQ,KAAK;;CAK7C;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,MAAM,CAAC,EAAE,aAAa,EACtB,KAAK,CAAC,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,WAAW,CAifb"}
|
package/dist/pipeline/build.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { dimensionToPx } from '../units';
|
|
2
|
-
import {
|
|
2
|
+
import { createVDTDocument, createVDTBlock, } from '../vdt';
|
|
3
3
|
import { parseMarkdownMemo } from '../parse';
|
|
4
4
|
import { computeHeadingNumbers } from '../numbering';
|
|
5
5
|
import { extractFrontmatter } from '../frontmatter';
|
|
6
|
-
import {
|
|
6
|
+
import { initHyphenator } from '../measure';
|
|
7
7
|
import { resolveAllConfig, computeBaselineGrid } from './config';
|
|
8
|
-
import { resolveBodyStyle,
|
|
9
|
-
import {
|
|
10
|
-
import { computeLevelIndentsPx, computeOrderedLevelIndentsPx, computeOrderedListRunMetrics, resolveUnorderedListItemStyle, resolveOrderedListItemStyle, } from './lists';
|
|
8
|
+
import { resolveBodyStyle, resolveBlockquoteStyle } from './styles';
|
|
9
|
+
import { computeLevelIndentsPx, computeOrderedLevelIndentsPx, computeOrderedListRunMetrics, } from './lists';
|
|
11
10
|
import { resetLinePositions, createPageWithColumns, currentColumn, advanceToNextColumn, placeBlockInColumn, } from './placement';
|
|
12
11
|
import { chooseParagraphSplit } from './orphanWidow';
|
|
13
|
-
|
|
12
|
+
import { applyStyleAttrs, computeMeasureViewport, computePageMetrics, enrichMathSpans, rollbackTrailingBlocks, stampSourceRanges, } from './buildHelpers';
|
|
13
|
+
import { resolveBlockKind } from './buildBlockKind';
|
|
14
|
+
import { runMeasurement } from './buildMeasurement';
|
|
15
|
+
export class BuildCancelledError extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super('Build cancelled');
|
|
18
|
+
this.name = 'BuildCancelledError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function buildDocument(content, config, cache, options) {
|
|
14
22
|
const resolved = resolveAllConfig(config);
|
|
15
23
|
const dpi = resolved.page.dpi;
|
|
16
24
|
// Initialize hyphenator if needed
|
|
@@ -21,26 +29,7 @@ export function buildDocument(content, config, cache) {
|
|
|
21
29
|
const baselineGrid = computeBaselineGrid(resolved);
|
|
22
30
|
// Create document
|
|
23
31
|
const doc = createVDTDocument(resolved, baselineGrid);
|
|
24
|
-
|
|
25
|
-
const trimWidthPx = dimensionToPx(resolved.page.width, dpi);
|
|
26
|
-
const trimHeightPx = dimensionToPx(resolved.page.height, dpi);
|
|
27
|
-
// Cut lines expansion: canvas grows to fit bleed + mark offset + mark length
|
|
28
|
-
let trimOffset = 0;
|
|
29
|
-
if (resolved.page.cutLines.enabled) {
|
|
30
|
-
const bleedPx = dimensionToPx(resolved.page.cutLines.bleed, dpi);
|
|
31
|
-
const markOffsetPx = dimensionToPx(resolved.page.cutLines.markOffset, dpi);
|
|
32
|
-
const markLengthPx = dimensionToPx(resolved.page.cutLines.markLength, dpi);
|
|
33
|
-
trimOffset = bleedPx + markOffsetPx + markLengthPx;
|
|
34
|
-
}
|
|
35
|
-
const pageWidthPx = trimWidthPx + trimOffset * 2;
|
|
36
|
-
const pageHeightPx = trimHeightPx + trimOffset * 2;
|
|
37
|
-
// Margins in px
|
|
38
|
-
const marginTop = dimensionToPx(resolved.page.margins.top, dpi);
|
|
39
|
-
const marginBottom = dimensionToPx(resolved.page.margins.bottom, dpi);
|
|
40
|
-
const marginLeft = dimensionToPx(resolved.page.margins.left, dpi);
|
|
41
|
-
const marginRight = dimensionToPx(resolved.page.margins.right, dpi);
|
|
42
|
-
// Content area (offset by trimOffset so content sits inside the trim area)
|
|
43
|
-
const contentArea = createBoundingBox(marginLeft + trimOffset, marginTop + trimOffset, trimWidthPx - marginLeft - marginRight, trimHeightPx - marginTop - marginBottom);
|
|
32
|
+
const { pageWidthPx, pageHeightPx, trimOffset, contentArea } = computePageMetrics(resolved);
|
|
44
33
|
doc.trimOffset = trimOffset;
|
|
45
34
|
// Create first page
|
|
46
35
|
const firstPage = createPageWithColumns(0, resolved, contentArea, pageWidthPx, pageHeightPx);
|
|
@@ -67,112 +56,30 @@ export function buildDocument(content, config, cache) {
|
|
|
67
56
|
let blockIdCounter = 0;
|
|
68
57
|
let pendingSpacing = 0;
|
|
69
58
|
for (let blockIdx = 0; blockIdx < contentBlocks.length; blockIdx++) {
|
|
59
|
+
if (options?.shouldCancel?.())
|
|
60
|
+
throw new BuildCancelledError();
|
|
70
61
|
const rawBlock = contentBlocks[blockIdx];
|
|
71
62
|
const id = `block-${blockIdCounter++}`;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
style = resolveHeadingStyle(rawBlock.level ?? 1, resolved);
|
|
85
|
-
vdtType = 'heading';
|
|
86
|
-
headingLevel = rawBlock.level;
|
|
87
|
-
numberPrefix = headingPrefixes[blockIdx];
|
|
88
|
-
if (numberPrefix) {
|
|
89
|
-
const sep = `${numberPrefix} `;
|
|
90
|
-
const firstSpan = rawBlock.spans[0];
|
|
91
|
-
const newSpans = firstSpan
|
|
92
|
-
? [{ text: sep + firstSpan.text, bold: firstSpan.bold, italic: firstSpan.italic }, ...rawBlock.spans.slice(1)]
|
|
93
|
-
: [{ text: sep, bold: false, italic: false }];
|
|
94
|
-
contentBlock = { ...rawBlock, text: sep + rawBlock.text, spans: newSpans };
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
case 'blockquote':
|
|
99
|
-
style = blockquoteStyle;
|
|
100
|
-
vdtType = 'blockquote';
|
|
101
|
-
break;
|
|
102
|
-
case 'mathDisplay': {
|
|
103
|
-
style = resolveMathDisplayStyle(resolved);
|
|
104
|
-
vdtType = 'mathDisplay';
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
case 'listItem': {
|
|
108
|
-
const depth = rawBlock.depth ?? 1;
|
|
109
|
-
const kind = rawBlock.listKind ?? 'unordered';
|
|
110
|
-
let resolvedList;
|
|
111
|
-
if (kind === 'ordered') {
|
|
112
|
-
const metric = orderedMetrics.perBlock.get(blockIdx) ??
|
|
113
|
-
{ numberText: '', numberWidthPx: 0, maxNumberWidthPx: 0 };
|
|
114
|
-
resolvedList = resolveOrderedListItemStyle(depth, resolved, orderedLevelIndentsPx, metric);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
resolvedList = resolveUnorderedListItemStyle(depth, resolved, listLevelIndentsPx, rawBlock.checked ?? false, kind === 'task');
|
|
118
|
-
}
|
|
119
|
-
style = resolvedList.text;
|
|
120
|
-
listBullet = resolvedList.bullet;
|
|
121
|
-
listDepth = depth;
|
|
122
|
-
listKind = kind;
|
|
123
|
-
bulletXOffsetInColumn = resolvedList.bulletXOffsetInColumn;
|
|
124
|
-
strikethroughText = resolvedList.strikethroughText;
|
|
125
|
-
vdtType = 'listItem';
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
default:
|
|
129
|
-
style = bodyStyle;
|
|
130
|
-
vdtType = 'paragraph';
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
63
|
+
const kind = resolveBlockKind(rawBlock, {
|
|
64
|
+
resolved,
|
|
65
|
+
bodyStyle,
|
|
66
|
+
blockquoteStyle,
|
|
67
|
+
headingPrefixes,
|
|
68
|
+
blockIdx,
|
|
69
|
+
listLevelIndentsPx,
|
|
70
|
+
orderedLevelIndentsPx,
|
|
71
|
+
orderedMetrics,
|
|
72
|
+
});
|
|
73
|
+
const { style, vdtType, headingLevel, numberPrefix, listBullet, listDepth, listKind, bulletXOffsetInColumn, strikethroughText } = kind;
|
|
74
|
+
let contentBlock = kind.contentBlock;
|
|
133
75
|
// Measure text — use rich measurement for blocks with bold spans
|
|
134
76
|
const col = currentColumn(doc, cursor);
|
|
135
|
-
// Resolve inline math
|
|
136
|
-
// When math is disabled, drop the math metadata so spans fall back to
|
|
137
|
-
// the raw TeX (visible as literal `$...$`).
|
|
77
|
+
// Resolve inline math on spans (no-op when the block has no math).
|
|
138
78
|
const mathEnabled = resolved.math.enabled;
|
|
139
|
-
|
|
140
|
-
const mathFontSizePx = style.fontSizePx * resolved.math.fontSizeScale;
|
|
141
|
-
const mathColor = resolved.math.color?.hex ?? style.color;
|
|
142
|
-
const enrichedSpans = contentBlock.spans.map((s) => {
|
|
143
|
-
if (!s.math)
|
|
144
|
-
return s;
|
|
145
|
-
if (!mathEnabled) {
|
|
146
|
-
return { text: `$${s.math.tex}$`, bold: s.bold, italic: s.italic };
|
|
147
|
-
}
|
|
148
|
-
const render = isMathReady()
|
|
149
|
-
? renderMath(s.math.tex, false, mathFontSizePx, { lineBoxPx: style.lineHeightPx, color: mathColor })
|
|
150
|
-
: undefined;
|
|
151
|
-
return { ...s, mathRender: render };
|
|
152
|
-
});
|
|
153
|
-
contentBlock = { ...contentBlock, spans: enrichedSpans };
|
|
154
|
-
}
|
|
79
|
+
contentBlock = enrichMathSpans(contentBlock, style, resolved);
|
|
155
80
|
const hasRichSpans = contentBlock.spans.some((s) => s.bold || s.italic || s.mathRender);
|
|
156
81
|
// List items reserve horizontal space for indent + bullet + gap.
|
|
157
|
-
|
|
158
|
-
let lineXShift = 0;
|
|
159
|
-
let measureFirstLineIndent = style.firstLineIndentPx;
|
|
160
|
-
let measureHangingIndent = style.hangingIndent;
|
|
161
|
-
if (listBullet) {
|
|
162
|
-
const textGap = listBullet.bulletWidthPx + listBullet.gapPx;
|
|
163
|
-
if (listBullet.hangingIndent) {
|
|
164
|
-
measureMaxWidth = Math.max(1, col.bbox.width - listBullet.indentPx - textGap);
|
|
165
|
-
lineXShift = listBullet.indentPx + textGap;
|
|
166
|
-
measureFirstLineIndent = 0;
|
|
167
|
-
measureHangingIndent = false;
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
measureMaxWidth = Math.max(1, col.bbox.width - listBullet.indentPx);
|
|
171
|
-
lineXShift = listBullet.indentPx;
|
|
172
|
-
measureFirstLineIndent = textGap;
|
|
173
|
-
measureHangingIndent = false;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
82
|
+
const { measureMaxWidth, lineXShift, measureFirstLineIndent, measureHangingIndent, } = computeMeasureViewport(col.bbox.width, style, listBullet);
|
|
176
83
|
const runtActive = resolved.bodyText.avoidRunts
|
|
177
84
|
&& (vdtType === 'paragraph'
|
|
178
85
|
|| (vdtType === 'listItem' && resolved.bodyText.avoidRuntsInLists));
|
|
@@ -187,50 +94,10 @@ export function buildDocument(content, config, cache) {
|
|
|
187
94
|
runtPenalty: runtActive ? resolved.bodyText.runtPenalty : 0,
|
|
188
95
|
runtMinCharacters: runtActive ? resolved.bodyText.runtMinCharacters : 0,
|
|
189
96
|
};
|
|
190
|
-
const useRich = hasRichSpans && style.boldFontString && style.italicFontString && style.boldItalicFontString;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
let measured;
|
|
195
|
-
if (vdtType === 'mathDisplay') {
|
|
196
|
-
const tex = rawBlock.tex ?? '';
|
|
197
|
-
if (!mathEnabled) {
|
|
198
|
-
// Fallback: render the literal TeX as a paragraph-like run.
|
|
199
|
-
measured = useRich
|
|
200
|
-
? measureRichBlock([{ text: `$$${tex}$$`, bold: false, italic: false }], style.fontString, style.fontString, style.fontString, style.fontString, measureMaxWidth, style.lineHeightPx, measureOptions)
|
|
201
|
-
: measureBlock(`$$${tex}$$`, style.fontString, measureMaxWidth, style.lineHeightPx, measureOptions);
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
// `renderMath` internally returns a cheap placeholder when MathJax
|
|
205
|
-
// isn't initialised yet — no need to gate the call here. When the
|
|
206
|
-
// real engine lands later, `CanvasPreview` bumps `resizeKey` and the
|
|
207
|
-
// pipeline rebuilds with the genuine render.
|
|
208
|
-
const render = renderMath(tex, true, style.fontSizePx, { color: style.color });
|
|
209
|
-
mathDisplayRender = render;
|
|
210
|
-
const width = Math.min(render.widthPx, measureMaxWidth);
|
|
211
|
-
const height = render.heightPx;
|
|
212
|
-
measured = {
|
|
213
|
-
lines: [{
|
|
214
|
-
text: '',
|
|
215
|
-
bbox: { x: 0, y: 0, width, height },
|
|
216
|
-
baseline: render.ascentPx,
|
|
217
|
-
hyphenated: false,
|
|
218
|
-
segments: [{ kind: 'math', text: '\uFFFC', width, mathRender: render }],
|
|
219
|
-
isLastLine: true,
|
|
220
|
-
}],
|
|
221
|
-
totalHeight: height,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
measured = cache
|
|
227
|
-
? (useRich
|
|
228
|
-
? cachedMeasureRichBlock(contentBlock.spans, style.fontString, style.boldFontString, style.italicFontString, style.boldItalicFontString, measureMaxWidth, style.lineHeightPx, measureOptions, cache)
|
|
229
|
-
: cachedMeasureBlock(contentBlock.text, style.fontString, measureMaxWidth, style.lineHeightPx, measureOptions, cache))
|
|
230
|
-
: (useRich
|
|
231
|
-
? measureRichBlock(contentBlock.spans, style.fontString, style.boldFontString, style.italicFontString, style.boldItalicFontString, measureMaxWidth, style.lineHeightPx, measureOptions)
|
|
232
|
-
: measureBlock(contentBlock.text, style.fontString, measureMaxWidth, style.lineHeightPx, measureOptions));
|
|
233
|
-
}
|
|
97
|
+
const useRich = !!(hasRichSpans && style.boldFontString && style.italicFontString && style.boldItalicFontString);
|
|
98
|
+
const { measured, mathDisplayRender } = runMeasurement({
|
|
99
|
+
vdtType, rawBlock, contentBlock, style, measureMaxWidth, measureOptions, mathEnabled, useRich, cache,
|
|
100
|
+
});
|
|
234
101
|
if (measured.lines.length === 0)
|
|
235
102
|
continue;
|
|
236
103
|
if (lineXShift > 0) {
|
|
@@ -240,46 +107,7 @@ export function buildDocument(content, config, cache) {
|
|
|
240
107
|
}
|
|
241
108
|
// Per-line source-range mapping using the block's plain→source map.
|
|
242
109
|
// Accounts for heading numbering prefix which prepends chars with no source.
|
|
243
|
-
const
|
|
244
|
-
const blockSrcEnd = rawBlock.sourceEnd + bodyOffset;
|
|
245
|
-
const srcMap = rawBlock.sourceMap;
|
|
246
|
-
const prefixLen = contentBlock.text.length - rawBlock.text.length;
|
|
247
|
-
const plainToSrc = (p) => {
|
|
248
|
-
const idx = p - prefixLen;
|
|
249
|
-
if (idx <= 0)
|
|
250
|
-
return blockSrcStart;
|
|
251
|
-
if (idx >= srcMap.length)
|
|
252
|
-
return blockSrcEnd;
|
|
253
|
-
return srcMap[idx] + bodyOffset;
|
|
254
|
-
};
|
|
255
|
-
let cumPlain = 0;
|
|
256
|
-
const lastLineIdx = measured.lines.length - 1;
|
|
257
|
-
for (let li = 0; li < measured.lines.length; li++) {
|
|
258
|
-
const line = measured.lines[li];
|
|
259
|
-
// If segments are present, prefer their aggregate text length for a more
|
|
260
|
-
// accurate plain-char count (excludes trailing hyphen for hyphenated lines).
|
|
261
|
-
let lineLen;
|
|
262
|
-
if (line.segments && line.segments.length > 0) {
|
|
263
|
-
lineLen = line.segments.reduce((s, seg) => s + seg.text.length, 0);
|
|
264
|
-
if (line.hyphenated) {
|
|
265
|
-
const last = line.segments[line.segments.length - 1];
|
|
266
|
-
if (last.text.endsWith('-'))
|
|
267
|
-
lineLen -= 1;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
lineLen = line.text.length - (line.hyphenated ? 1 : 0);
|
|
272
|
-
}
|
|
273
|
-
line.plainStart = cumPlain;
|
|
274
|
-
line.plainEnd = cumPlain + lineLen;
|
|
275
|
-
// Advance past the separator space that was consumed to break the line
|
|
276
|
-
// (skip when hyphenated — break was at a soft hyphen — or on the last line).
|
|
277
|
-
const skipSeparator = !line.hyphenated && li !== lastLineIdx ? 1 : 0;
|
|
278
|
-
cumPlain = line.plainEnd + skipSeparator;
|
|
279
|
-
line.sourceStart = plainToSrc(line.plainStart);
|
|
280
|
-
line.sourceEnd = plainToSrc(line.plainEnd);
|
|
281
|
-
}
|
|
282
|
-
const absoluteSourceMap = srcMap.map((o) => o + bodyOffset);
|
|
110
|
+
const { prefixLen, absoluteSourceMap } = stampSourceRanges(measured, rawBlock, contentBlock, bodyOffset);
|
|
283
111
|
const finalizeListItem = (blk, isFirstPart) => {
|
|
284
112
|
if (!listBullet)
|
|
285
113
|
return;
|
|
@@ -387,16 +215,7 @@ export function buildDocument(content, config, cache) {
|
|
|
387
215
|
curCol.availableHeight -= spacingBefore;
|
|
388
216
|
const splitLines = remainingLines.slice(0, splitAt);
|
|
389
217
|
const blk = createVDTBlock(id, vdtType, style.fontString, style.color, style.textAlign);
|
|
390
|
-
|
|
391
|
-
blk.boldFontString = style.boldFontString;
|
|
392
|
-
if (style.italicFontString)
|
|
393
|
-
blk.italicFontString = style.italicFontString;
|
|
394
|
-
if (style.boldItalicFontString)
|
|
395
|
-
blk.boldItalicFontString = style.boldItalicFontString;
|
|
396
|
-
if (style.boldColor)
|
|
397
|
-
blk.boldColor = style.boldColor;
|
|
398
|
-
if (style.italicColor)
|
|
399
|
-
blk.italicColor = style.italicColor;
|
|
218
|
+
applyStyleAttrs(blk, style);
|
|
400
219
|
blk.headingLevel = headingLevel;
|
|
401
220
|
if (numberPrefix)
|
|
402
221
|
blk.numberPrefix = numberPrefix;
|
|
@@ -483,21 +302,8 @@ export function buildDocument(content, config, cache) {
|
|
|
483
302
|
if (remainAfterHeading < minSpaceAfter) {
|
|
484
303
|
// Roll back any immediately-preceding heading blocks in this
|
|
485
304
|
// column so they travel with this one.
|
|
486
|
-
|
|
487
|
-
for (let j = curCol.blocks.length - 1; j >= 0; j--) {
|
|
488
|
-
if (curCol.blocks[j].type === 'heading')
|
|
489
|
-
rollbackCount++;
|
|
490
|
-
else
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
305
|
+
const rollbackCount = rollbackTrailingBlocks(curCol, doc.blocks, (b) => b.type === 'heading');
|
|
493
306
|
if (rollbackCount > 0) {
|
|
494
|
-
const popped = curCol.blocks.splice(curCol.blocks.length - rollbackCount);
|
|
495
|
-
for (const p of popped) {
|
|
496
|
-
const idx = doc.blocks.indexOf(p);
|
|
497
|
-
if (idx !== -1)
|
|
498
|
-
doc.blocks.splice(idx, 1);
|
|
499
|
-
curCol.availableHeight += p.bbox.height;
|
|
500
|
-
}
|
|
501
307
|
// Rewind so the for-loop's blockIdx++ lands on the first
|
|
502
308
|
// rolled-back heading.
|
|
503
309
|
blockIdx -= rollbackCount + 1;
|
|
@@ -516,16 +322,7 @@ export function buildDocument(content, config, cache) {
|
|
|
516
322
|
}
|
|
517
323
|
const partId = partIndex === 0 ? id : `${id}-cont-${partIndex}`;
|
|
518
324
|
const blk = createVDTBlock(partId, vdtType, style.fontString, style.color, style.textAlign);
|
|
519
|
-
|
|
520
|
-
blk.boldFontString = style.boldFontString;
|
|
521
|
-
if (style.italicFontString)
|
|
522
|
-
blk.italicFontString = style.italicFontString;
|
|
523
|
-
if (style.boldItalicFontString)
|
|
524
|
-
blk.boldItalicFontString = style.boldItalicFontString;
|
|
525
|
-
if (style.boldColor)
|
|
526
|
-
blk.boldColor = style.boldColor;
|
|
527
|
-
if (style.italicColor)
|
|
528
|
-
blk.italicColor = style.italicColor;
|
|
325
|
+
applyStyleAttrs(blk, style);
|
|
529
326
|
if (partIndex === 0) {
|
|
530
327
|
blk.headingLevel = headingLevel;
|
|
531
328
|
if (numberPrefix)
|
|
@@ -605,16 +402,7 @@ export function buildDocument(content, config, cache) {
|
|
|
605
402
|
const partId = partIndex === 0 ? id : `${id}-cont-${partIndex}`;
|
|
606
403
|
const splitLines = remainingLines.slice(0, choice.splitAt);
|
|
607
404
|
const blk = createVDTBlock(partId, vdtType, style.fontString, style.color, style.textAlign);
|
|
608
|
-
|
|
609
|
-
blk.boldFontString = style.boldFontString;
|
|
610
|
-
if (style.italicFontString)
|
|
611
|
-
blk.italicFontString = style.italicFontString;
|
|
612
|
-
if (style.boldItalicFontString)
|
|
613
|
-
blk.boldItalicFontString = style.boldItalicFontString;
|
|
614
|
-
if (style.boldColor)
|
|
615
|
-
blk.boldColor = style.boldColor;
|
|
616
|
-
if (style.italicColor)
|
|
617
|
-
blk.italicColor = style.italicColor;
|
|
405
|
+
applyStyleAttrs(blk, style);
|
|
618
406
|
if (partIndex === 0) {
|
|
619
407
|
blk.headingLevel = headingLevel;
|
|
620
408
|
if (numberPrefix)
|
|
@@ -648,21 +436,8 @@ export function buildDocument(content, config, cache) {
|
|
|
648
436
|
// pull those headings along so they don't remain stranded as orphans
|
|
649
437
|
// at the column's bottom. Mirrors the rollback inside the "fits" path.
|
|
650
438
|
if (vdtType === 'heading' && resolved.headings.keepWithNext) {
|
|
651
|
-
|
|
652
|
-
for (let j = curCol.blocks.length - 1; j >= 0; j--) {
|
|
653
|
-
if (curCol.blocks[j].type === 'heading')
|
|
654
|
-
rollbackCount++;
|
|
655
|
-
else
|
|
656
|
-
break;
|
|
657
|
-
}
|
|
439
|
+
const rollbackCount = rollbackTrailingBlocks(curCol, doc.blocks, (b) => b.type === 'heading');
|
|
658
440
|
if (rollbackCount > 0) {
|
|
659
|
-
const popped = curCol.blocks.splice(curCol.blocks.length - rollbackCount);
|
|
660
|
-
for (const p of popped) {
|
|
661
|
-
const idx = doc.blocks.indexOf(p);
|
|
662
|
-
if (idx !== -1)
|
|
663
|
-
doc.blocks.splice(idx, 1);
|
|
664
|
-
curCol.availableHeight += p.bbox.height;
|
|
665
|
-
}
|
|
666
441
|
blockIdx -= rollbackCount + 1;
|
|
667
442
|
pendingSpacing = 0;
|
|
668
443
|
advanceToNextColumn(doc, cursor, resolved, contentArea, pageWidthPx, pageHeightPx);
|
|
@@ -676,16 +451,7 @@ export function buildDocument(content, config, cache) {
|
|
|
676
451
|
// Empty column but block still doesn't fit (block taller than page) — place anyway
|
|
677
452
|
const partId = partIndex === 0 ? id : `${id}-cont-${partIndex}`;
|
|
678
453
|
const blk = createVDTBlock(partId, vdtType, style.fontString, style.color, style.textAlign);
|
|
679
|
-
|
|
680
|
-
blk.boldFontString = style.boldFontString;
|
|
681
|
-
if (style.italicFontString)
|
|
682
|
-
blk.italicFontString = style.italicFontString;
|
|
683
|
-
if (style.boldItalicFontString)
|
|
684
|
-
blk.boldItalicFontString = style.boldItalicFontString;
|
|
685
|
-
if (style.boldColor)
|
|
686
|
-
blk.boldColor = style.boldColor;
|
|
687
|
-
if (style.italicColor)
|
|
688
|
-
blk.italicColor = style.italicColor;
|
|
454
|
+
applyStyleAttrs(blk, style);
|
|
689
455
|
if (partIndex === 0)
|
|
690
456
|
blk.headingLevel = headingLevel;
|
|
691
457
|
blk.lines = resetLinePositions(remainingLines, style.lineHeightPx);
|