rapier-markdown-kit 1.1.102 → 1.1.104
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/LICENSE +2 -2
- package/README.md +213 -53
- package/dist/agent/vendor/hyphen-en-us/LICENSE +14 -0
- package/dist/agent/vendor/hyphen-en-us/SOURCE.json +33 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.hyp.txt +14 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.pat.txt +4938 -0
- package/dist/agent/vendor/hyphen-en-us/patterns.js +25 -0
- package/dist/agent/vendor/pretext/LICENSE +208 -0
- package/dist/agent/vendor/pretext/NOTICE +26 -13
- package/dist/agent/vendor/pretext/SOURCE.json +213 -45
- package/dist/agent/vendor/pretext/analysis.js +675 -1224
- package/dist/agent/vendor/pretext/entry-geometry.js +183 -0
- package/dist/agent/vendor/pretext/gecko-line-breaks.js +688 -0
- package/dist/agent/vendor/pretext/generated/engine-break-data.js +57 -0
- package/dist/agent/vendor/pretext/generated/webkit-generic-families.js +80 -0
- package/dist/agent/vendor/pretext/graphemes.js +98 -0
- package/dist/agent/vendor/pretext/han-kerning.js +253 -0
- package/dist/agent/vendor/pretext/layout.js +352 -290
- package/dist/agent/vendor/pretext/line-break.js +1154 -588
- package/dist/agent/vendor/pretext/line-breaks.js +892 -0
- package/dist/agent/vendor/pretext/line-text.js +81 -39
- package/dist/agent/vendor/pretext/measurement.js +1105 -176
- package/dist/agent/vendor/pretext/prepare.js +807 -0
- package/dist/agent/vendor/pretext/rich-inline.js +1242 -273
- package/dist/agent/will.mjs +2 -0
- package/dist/kit/assets.mjs +5 -1
- package/dist/kit/conformance/run.mjs +4 -4
- package/dist/kit/export-fonts.mjs +26 -11
- package/dist/kit/index.mjs +1 -0
- package/dist/kit/ledger/carried.mjs +9 -7
- package/dist/kit/ledger/data.mjs +73 -13
- package/dist/kit/ledger/format.mjs +166 -53
- package/dist/kit/ledger/hash.mjs +75 -18
- package/dist/kit/ledger/history.mjs +143 -115
- package/dist/kit/ledger/inverse-source.mjs +158 -19
- package/dist/kit/ledger/journal-records.mjs +292 -67
- package/dist/kit/model.mjs +1 -1
- package/dist/kit/pdf-glyphs.mjs +4 -4
- package/dist/kit/render-markdown.mjs +259 -122
- package/dist/kit/render-sanitize.mjs +24 -4
- package/dist/kit/render-work.mjs +99 -20
- package/dist/kit/render.mjs +101 -65
- package/dist/kit/typography.mjs +2 -0
- package/dist/layout/hyphenation.mjs +127 -0
- package/dist/layout/line-plan.mjs +88 -96
- package/dist/layout/model.mjs +61 -80
- package/dist/layout/paragraph-fit.mjs +191 -0
- package/dist/layout/preparation.mjs +373 -0
- package/dist/layout/prepared-paragraph.mjs +223 -0
- package/dist/layout/typography.mjs +345 -111
- package/dist/packages/rapier-diff/index.mjs +288 -196
- package/dist/spec/document-fonts.mjs +13 -4
- package/dist/spec/md-assets.mjs +149 -30
- package/dist/spec/md-layout.mjs +5 -2
- package/dist/spec/md-marks.mjs +218 -3
- package/dist/spec/md-source.mjs +122 -0
- package/package.json +2 -1
- package/style.css +9 -0
- package/dist/agent/vendor/pretext/bidi.js +0 -151
- package/dist/agent/vendor/pretext/generated/bidi-data.js +0 -3831
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
|
|
2
|
+
// Fresh-line geometry, or entry geometry: the widths a line takes where it starts inside a
|
|
3
|
+
// segment cut between graphemes, at or inside a stretch of it that holds a default-ignorable code
|
|
4
|
+
// point (a ZWNJ, a word joiner, a bidi mark). Shaping looks past such a character, so the text
|
|
5
|
+
// after the cut, shaped afresh at the line's start, can measure otherwise than the segment's own
|
|
6
|
+
// advances give (RESEARCH.md, Widths After A Line Break). For each such start, preparation
|
|
7
|
+
// measures the text from the start through the first whole grapheme past that stretch, the
|
|
8
|
+
// anchor, in at most three prefixes (the entry's head); past the anchor the widths go on by the
|
|
9
|
+
// segment's advances. The walkers (src/line-break.ts) ask an entry whether the segment's whole
|
|
10
|
+
// tail fits the line (admissionFit), which Blink reads from the tail as measured afresh and Gecko
|
|
11
|
+
// from the whole segment's width less the prefixes already placed (the profile's entryFitBasis),
|
|
12
|
+
// and, where it doesn't fit, how many graphemes do by the fresh prefixes. Only the desktop Blink
|
|
13
|
+
// and Gecko profiles observe entries, the browsers they were checked in, and a segment of more
|
|
14
|
+
// than 96 graphemes takes none (RESEARCH.md, Keeping Work Bounded).
|
|
15
|
+
import { findGraphemeEnds } from './graphemes.js'
|
|
16
|
+
import { getEngineProfile } from './measurement.js'
|
|
17
|
+
|
|
18
|
+
const defaultIgnorable = /\p{Default_Ignorable_Code_Point}/u
|
|
19
|
+
const MAX_GRAPHEMES = 96
|
|
20
|
+
const MAX_HEAD_ENDPOINTS = 3
|
|
21
|
+
|
|
22
|
+
// Whether a text holds a default-ignorable code point, without which no segment of it has entry
|
|
23
|
+
// geometry (observeSegmentEntries).
|
|
24
|
+
export function textMayHaveEntryGeometry(text ) {
|
|
25
|
+
return defaultIgnorable.test(text)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
// The stretches of a segment that a default-ignorable affects, as intervals of the source text.
|
|
37
|
+
// The text without its default-ignorables (the projection) is cut into grapheme clusters, and the
|
|
38
|
+
// segment's own graphemes that one such cluster spans are joined into one interval. An interval
|
|
39
|
+
// is observed where it holds a default-ignorable, and leading default-ignorables join the first
|
|
40
|
+
// visible interval. The projection only picks the intervals: what is measured is the source text,
|
|
41
|
+
// and the segment's grapheme boundaries and breaks stay its own.
|
|
42
|
+
function affectedIntervals(text , endpoints ) {
|
|
43
|
+
const spans = []
|
|
44
|
+
const projected = []
|
|
45
|
+
const visibleRuns = /[^\p{Default_Ignorable_Code_Point}]+/gu
|
|
46
|
+
for (let match; (match = visibleRuns.exec(text)) !== null;) {
|
|
47
|
+
spans.push({ start: match.index, end: match.index + match[0].length })
|
|
48
|
+
projected.push(match[0])
|
|
49
|
+
}
|
|
50
|
+
// Map only the projected grapheme endpoints through retained source views.
|
|
51
|
+
// The last code unit maps before an ignored gap; the next start maps after it.
|
|
52
|
+
let spanIndex = 0
|
|
53
|
+
let projectedStart = 0
|
|
54
|
+
function sourceOffset(offset ) {
|
|
55
|
+
let span = spans[spanIndex]
|
|
56
|
+
while (offset >= projectedStart + span.end - span.start) {
|
|
57
|
+
projectedStart += span.end - span.start
|
|
58
|
+
span = spans[++spanIndex]
|
|
59
|
+
}
|
|
60
|
+
return span.start + offset - projectedStart
|
|
61
|
+
}
|
|
62
|
+
const joined = new Uint8Array(endpoints.length)
|
|
63
|
+
const visible = projected.join('')
|
|
64
|
+
const ends = new Int32Array(visible.length)
|
|
65
|
+
const count = findGraphemeEnds(getEngineProfile().graphemeTable, visible, 0, visible.length, ends)
|
|
66
|
+
let boundaryIndex = 1
|
|
67
|
+
for (let i = 0, projectedEnd = 0; i < count; i++) {
|
|
68
|
+
const start = sourceOffset(projectedEnd)
|
|
69
|
+
projectedEnd = ends[i]
|
|
70
|
+
const end = sourceOffset(projectedEnd - 1) + 1
|
|
71
|
+
while (boundaryIndex < endpoints.length && endpoints[boundaryIndex] <= start) boundaryIndex++
|
|
72
|
+
while (boundaryIndex < endpoints.length && endpoints[boundaryIndex] < end) joined[boundaryIndex++] = 1
|
|
73
|
+
}
|
|
74
|
+
const parts = []
|
|
75
|
+
let start = 0
|
|
76
|
+
for (let index = 1; index < endpoints.length; index++) {
|
|
77
|
+
if (joined[index] === 1) continue
|
|
78
|
+
const end = endpoints[index]
|
|
79
|
+
parts.push({ start, end, observe: defaultIgnorable.test(text.slice(start, end)) })
|
|
80
|
+
start = end
|
|
81
|
+
}
|
|
82
|
+
const leadingEnd = spans.length === 0 ? text.length : spans[0] .start
|
|
83
|
+
if (leadingEnd > 0 && leadingEnd < text.length) {
|
|
84
|
+
let firstVisiblePart = 0
|
|
85
|
+
while (parts[firstVisiblePart] .end <= leadingEnd) firstVisiblePart++
|
|
86
|
+
parts.splice(0, firstVisiblePart + 1, { start: 0, end: parts[firstVisiblePart] .end, observe: true })
|
|
87
|
+
}
|
|
88
|
+
return parts
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// At most 96 original graphemes and three exact head queries per covered entry.
|
|
92
|
+
// Each source grapheme enters at most 3 + 2 + 1 measured prefixes across all
|
|
93
|
+
// starts, so submitted UTF-16 stays at most six times the source length.
|
|
94
|
+
// Preparation retains only numeric geometry for subsequent line walking.
|
|
95
|
+
export function observeSegmentEntries(
|
|
96
|
+
text ,
|
|
97
|
+
advances ,
|
|
98
|
+
letterSpacing ,
|
|
99
|
+
wholeWidth ,
|
|
100
|
+
fitBasis ,
|
|
101
|
+
measure ,
|
|
102
|
+
) {
|
|
103
|
+
if (!defaultIgnorable.test(text) || advances.length > MAX_GRAPHEMES) return null
|
|
104
|
+
const ends = new Int32Array(text.length)
|
|
105
|
+
const count = findGraphemeEnds(getEngineProfile().graphemeTable, text, 0, text.length, ends)
|
|
106
|
+
if (count > MAX_GRAPHEMES) return null
|
|
107
|
+
const endpoints = [0]
|
|
108
|
+
for (let i = 0; i < count; i++) endpoints.push(ends[i] )
|
|
109
|
+
if (endpoints.length !== advances.length + 1) throw new Error('Entry and release grapheme cursors differ')
|
|
110
|
+
const parts = affectedIntervals(text, endpoints)
|
|
111
|
+
const terminalPrefixes = [0]
|
|
112
|
+
for (const advance of advances) terminalPrefixes.push(terminalPrefixes[terminalPrefixes.length - 1] + advance + letterSpacing)
|
|
113
|
+
const entries = Array.from({ length: advances.length }, () => null)
|
|
114
|
+
let partIndex = 0
|
|
115
|
+
let hasEntries = false
|
|
116
|
+
for (let start = 1; start < advances.length; start++) {
|
|
117
|
+
const sourceStart = endpoints[start]
|
|
118
|
+
while (partIndex < parts.length && parts[partIndex] .end <= sourceStart) partIndex++
|
|
119
|
+
const part = parts[partIndex]
|
|
120
|
+
// A start is observed inside an affected interval. The anchor, the first whole grapheme
|
|
121
|
+
// past that interval, is measured after it as its right context, and a line that starts
|
|
122
|
+
// at the anchor takes an entry only where the anchor's own interval is affected.
|
|
123
|
+
if (part === undefined || !part.observe || sourceStart < part.start) continue
|
|
124
|
+
let anchor = start + 1
|
|
125
|
+
while (anchor < advances.length && endpoints[anchor] <= part.end) anchor++
|
|
126
|
+
// An entry needs that whole grapheme. An interval that ends the segment has none, so
|
|
127
|
+
// its starts take no entry: what a line start measures with nothing after it hasn't
|
|
128
|
+
// been checked against a browser. Nor does a start whose head would take more than
|
|
129
|
+
// three prefixes.
|
|
130
|
+
if (endpoints[anchor] <= part.end || anchor - start > MAX_HEAD_ENDPOINTS) continue
|
|
131
|
+
const head = []
|
|
132
|
+
let complete = true
|
|
133
|
+
for (let end = start + 1; end <= anchor; end++) {
|
|
134
|
+
const query = text.slice(sourceStart, endpoints[end])
|
|
135
|
+
const width = measure(query)
|
|
136
|
+
if (width === null || !Number.isFinite(width)) { complete = false; break }
|
|
137
|
+
head.push(width)
|
|
138
|
+
}
|
|
139
|
+
if (!complete) continue
|
|
140
|
+
let admissionFit
|
|
141
|
+
switch (fitBasis) {
|
|
142
|
+
case 'fresh':
|
|
143
|
+
admissionFit = head[head.length - 1] +
|
|
144
|
+
(terminalPrefixes[advances.length] - terminalPrefixes[anchor] )
|
|
145
|
+
break
|
|
146
|
+
case 'original':
|
|
147
|
+
admissionFit = wholeWidth + letterSpacing - terminalPrefixes[start]
|
|
148
|
+
break
|
|
149
|
+
}
|
|
150
|
+
entries[start] = { head, admissionFit }
|
|
151
|
+
hasEntries = true
|
|
152
|
+
}
|
|
153
|
+
return hasEntries ? { terminalPrefixes, entries } : null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Where a fresh line that starts at grapheme `start` of a segment ends, by the entry observed
|
|
157
|
+
// there: past the segment's end (end + 1) where the whole tail is admitted and the line goes on
|
|
158
|
+
// with the text after it, else after the last fresh prefix that fits, keeping the first grapheme.
|
|
159
|
+
// `end` then means the prefixes ran out, and the line ends with the segment.
|
|
160
|
+
export function getFreshLineEnd(geometry , start , end , fitLimit ) {
|
|
161
|
+
if (geometry.entries[start] .admissionFit <= fitLimit) return end + 1
|
|
162
|
+
let g = start + 1
|
|
163
|
+
while (g < end && getSegmentEntryWidth(geometry, start, g + 1) <= fitLimit) g++
|
|
164
|
+
return g
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The width of a segment's graphemes from `start` to `end` on a fresh line that starts at
|
|
168
|
+
// `start`, with the letter spacing after the last of them. Null where no entry was observed,
|
|
169
|
+
// as at the segment's own start; an observed 0 is a width, and the prefixes needn't grow.
|
|
170
|
+
export function getSegmentEntryWidth(
|
|
171
|
+
geometry ,
|
|
172
|
+
start ,
|
|
173
|
+
end ,
|
|
174
|
+
) {
|
|
175
|
+
if (geometry === null) return null
|
|
176
|
+
const entry = geometry.entries[start]
|
|
177
|
+
if (entry === null) return null
|
|
178
|
+
if (end === start) return 0
|
|
179
|
+
const anchor = start + entry.head.length
|
|
180
|
+
if (end <= anchor) return entry.head[end - start - 1]
|
|
181
|
+
return entry.head[entry.head.length - 1] +
|
|
182
|
+
(geometry.terminalPrefixes[end] - geometry.terminalPrefixes[anchor] )
|
|
183
|
+
}
|