@peaceroad/markdown-it-renderer-fence 0.7.0 → 0.9.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/README.md +179 -470
- package/docs/README.md +37 -0
- package/docs/code-highlighting-design.md +321 -0
- package/docs/custom-highlight-styling-guide.md +210 -0
- package/package.json +25 -13
- package/src/custom-highlight/option-validator.js +5 -5
- package/src/custom-highlight/payload-utils.js +4 -9
- package/src/custom-highlight/{shiki-keyword-rules.js → shiki-role-rules.js} +249 -54
- package/src/custom-highlight/{shiki-keyword.js → shiki-role.js} +107 -99
- package/src/custom-highlight/shiki-theme-role.js +176 -0
- package/src/fence/line-notes.js +27 -9
- package/src/fence/render-api-constants.js +1 -1
- package/src/fence/render-api-provider.js +61 -53
- package/src/fence/render-api-renderer.js +26 -10
- package/src/fence/render-api-runtime.js +29 -10
- package/src/fence/render-api.js +20 -12
- package/src/fence/render-markup.js +34 -24
- package/src/fence/render-shared.js +150 -30
- package/src/utils/attr-utils.js +10 -0
- package/theme/_shared/rf-core.css +170 -0
- package/theme/line-notes.css +94 -0
- package/theme/line-number.css +64 -0
- package/theme/rf-basic/README.md +117 -0
- package/theme/rf-basic/api/highlightjs.css +71 -0
- package/theme/rf-basic/api/shiki.css +67 -0
- package/theme/rf-basic/base.css +5 -0
- package/theme/rf-basic/index.css +7 -0
- package/theme/rf-basic/index.js +164 -0
- package/theme/rf-basic/markup/highlightjs.css +77 -0
- package/theme/rf-basic/markup/shiki.css +11 -0
- package/theme/rf-monochrome/README.md +84 -0
- package/theme/rf-monochrome/base.css +5 -0
- package/theme/rf-monochrome/index.css +5 -0
- package/theme/rf-monochrome/index.js +71 -0
- package/theme/rf-monochrome/markup/highlightjs.css +150 -0
- package/theme/rf-monochrome/markup/shiki.css +38 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendStyleValue,
|
|
3
3
|
createAttrOrderIndexGetter,
|
|
4
|
+
escapeHtmlAttr,
|
|
4
5
|
getInfoAttr,
|
|
5
6
|
getLangFromClassAttr,
|
|
6
7
|
} from '../utils/attr-utils.js'
|
|
@@ -26,6 +27,7 @@ const preWrapStyle = 'white-space: pre-wrap; overflow-wrap: anywhere;'
|
|
|
26
27
|
const voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'])
|
|
27
28
|
const nonNegativeIntReg = /^\d+$/
|
|
28
29
|
const positiveIntReg = /^[1-9]\d*$/
|
|
30
|
+
const attrOrderRankCacheMaxSize = 256
|
|
29
31
|
|
|
30
32
|
const getLineNoteIdPrefix = (token, idx) => {
|
|
31
33
|
const tokenMap = token && Array.isArray(token.map) ? token.map : null
|
|
@@ -103,9 +105,16 @@ const createCommonFenceOptionDefaults = (md) => {
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
const finalizeCommonFenceOption = (opt) => {
|
|
106
|
-
|
|
108
|
+
const sampLangs = ['samp']
|
|
109
|
+
const extraSampLangs = String(opt.sampLang ?? '').split(',')
|
|
110
|
+
for (let i = 0; i < extraSampLangs.length; i++) {
|
|
111
|
+
const lang = extraSampLangs[i].trim()
|
|
112
|
+
if (lang) sampLangs.push(lang)
|
|
113
|
+
}
|
|
114
|
+
opt._sampLangSet = new Set(sampLangs)
|
|
107
115
|
opt._attrOrderIndex = createAttrOrderIndexGetter(opt.attrsOrder || [])
|
|
108
116
|
opt._attrOrderRankCache = new Map()
|
|
117
|
+
opt.lineEndSpanClass = escapeHtmlAttr(opt.lineEndSpanClass)
|
|
109
118
|
return opt
|
|
110
119
|
}
|
|
111
120
|
|
|
@@ -132,6 +141,8 @@ const parsePositiveLineIndex = (val) => {
|
|
|
132
141
|
return num
|
|
133
142
|
}
|
|
134
143
|
|
|
144
|
+
const isTruthyAttrValue = (val) => val !== 'false' && val !== '0'
|
|
145
|
+
|
|
135
146
|
const escapeHtmlText = (value) => {
|
|
136
147
|
return String(value ?? '')
|
|
137
148
|
.replace(/&/g, '&')
|
|
@@ -154,6 +165,62 @@ const getLogicalLineCount = (text) => {
|
|
|
154
165
|
return count
|
|
155
166
|
}
|
|
156
167
|
|
|
168
|
+
const isLineStartWhitespaceCode = (code) => {
|
|
169
|
+
return code <= 32 || code === 160 || code === 0xFEFF
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const lineStartsWithAfterIndent = (str, start, end, marker) => {
|
|
173
|
+
let pos = start
|
|
174
|
+
while (pos < end && isLineStartWhitespaceCode(str.charCodeAt(pos))) pos++
|
|
175
|
+
return str.startsWith(marker, pos)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const scanLogicalLineBounds = (str, onLine) => {
|
|
179
|
+
let lineStart = 0
|
|
180
|
+
let lineIndex = 0
|
|
181
|
+
|
|
182
|
+
for (let i = 0; i <= str.length; i++) {
|
|
183
|
+
const code = i < str.length ? str.charCodeAt(i) : 10
|
|
184
|
+
if (code !== 10 && code !== 13) continue
|
|
185
|
+
onLine(lineStart, i, lineIndex)
|
|
186
|
+
if (code === 13 && i + 1 < str.length && str.charCodeAt(i + 1) === 10) i++
|
|
187
|
+
lineStart = i + 1
|
|
188
|
+
lineIndex++
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const getCommentLineFlags = (text, commentMarkValue) => {
|
|
193
|
+
const str = String(text ?? '')
|
|
194
|
+
const marker = String(commentMarkValue ?? '')
|
|
195
|
+
if (!str || !marker) return null
|
|
196
|
+
const flags = []
|
|
197
|
+
let hasComment = false
|
|
198
|
+
|
|
199
|
+
scanLogicalLineBounds(str, (lineStart, lineEnd, lineIndex) => {
|
|
200
|
+
if (lineStartsWithAfterIndent(str, lineStart, lineEnd, marker)) {
|
|
201
|
+
flags[lineIndex] = true
|
|
202
|
+
hasComment = true
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return hasComment ? flags : null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const getCommentLineRanges = (text, commentMarkValue) => {
|
|
210
|
+
const str = String(text ?? '')
|
|
211
|
+
const marker = String(commentMarkValue ?? '')
|
|
212
|
+
if (!str || !marker) return null
|
|
213
|
+
const ranges = []
|
|
214
|
+
|
|
215
|
+
scanLogicalLineBounds(str, (lineStart, lineEnd) => {
|
|
216
|
+
if (lineEnd > lineStart && lineStartsWithAfterIndent(str, lineStart, lineEnd, marker)) {
|
|
217
|
+
ranges.push([lineStart, lineEnd])
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
return ranges.length ? ranges : null
|
|
222
|
+
}
|
|
223
|
+
|
|
157
224
|
const parseLineRangeList = (attrVal, parseValue) => {
|
|
158
225
|
const str = String(attrVal ?? '')
|
|
159
226
|
if (!str) return []
|
|
@@ -179,14 +246,8 @@ const parseLineRangeList = (attrVal, parseValue) => {
|
|
|
179
246
|
return result
|
|
180
247
|
}
|
|
181
248
|
|
|
182
|
-
const parsePositiveLineNumber = (val) => {
|
|
183
|
-
const num = Number(val)
|
|
184
|
-
if (!Number.isFinite(num) || num <= 0) return null
|
|
185
|
-
return num
|
|
186
|
-
}
|
|
187
|
-
|
|
188
249
|
const getEmphasizeLines = (attrVal) => {
|
|
189
|
-
return parseLineRangeList(attrVal,
|
|
250
|
+
return parseLineRangeList(attrVal, parsePositiveLineIndex)
|
|
190
251
|
}
|
|
191
252
|
|
|
192
253
|
const getLineNumberSkipRanges = (attrVal) => {
|
|
@@ -196,6 +257,8 @@ const getLineNumberSkipRanges = (attrVal) => {
|
|
|
196
257
|
const normalizeEmphasisRanges = (emphasizeLines, maxLine) => {
|
|
197
258
|
const normalized = []
|
|
198
259
|
if (!emphasizeLines || !emphasizeLines.length || maxLine <= 0) return normalized
|
|
260
|
+
let previousStart = -1
|
|
261
|
+
let needsSort = false
|
|
199
262
|
for (const range of emphasizeLines) {
|
|
200
263
|
let s = range[0]
|
|
201
264
|
let e = range[1]
|
|
@@ -209,8 +272,25 @@ const normalizeEmphasisRanges = (emphasizeLines, maxLine) => {
|
|
|
209
272
|
}
|
|
210
273
|
if (s > maxLine || e < 1) continue
|
|
211
274
|
if (e > maxLine) e = maxLine
|
|
275
|
+
if (previousStart > s) needsSort = true
|
|
212
276
|
normalized.push([s, e])
|
|
277
|
+
previousStart = s
|
|
213
278
|
}
|
|
279
|
+
if (normalized.length < 2) return normalized
|
|
280
|
+
if (needsSort) normalized.sort((a, b) => a[0] - b[0] || a[1] - b[1])
|
|
281
|
+
|
|
282
|
+
let writeIndex = 1
|
|
283
|
+
for (let i = 1; i < normalized.length; i++) {
|
|
284
|
+
const previous = normalized[writeIndex - 1]
|
|
285
|
+
const current = normalized[i]
|
|
286
|
+
if (current[0] <= previous[1] + 1) {
|
|
287
|
+
if (current[1] > previous[1]) previous[1] = current[1]
|
|
288
|
+
continue
|
|
289
|
+
}
|
|
290
|
+
normalized[writeIndex] = current
|
|
291
|
+
writeIndex++
|
|
292
|
+
}
|
|
293
|
+
normalized.length = writeIndex
|
|
214
294
|
return normalized
|
|
215
295
|
}
|
|
216
296
|
|
|
@@ -370,9 +450,10 @@ const buildPreLineTags = (hidden, setNumber, lineNote) => {
|
|
|
370
450
|
}
|
|
371
451
|
}
|
|
372
452
|
|
|
373
|
-
const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, threshold, lineEndSpanClass, br, commentLines, commentClass, lineNumberPlan, lineNotePlan) => {
|
|
453
|
+
const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, threshold, lineEndSpanClass, br, commentLines, commentClass, lineNumberPlan, lineNotePlan, wrapLastLine) => {
|
|
374
454
|
const lines = content.split(br)
|
|
375
455
|
const max = lines.length
|
|
456
|
+
const logicalLineMax = wrapLastLine ? max : Math.max(max - 1, 0)
|
|
376
457
|
const lineNumberHidden = lineNumberPlan ? lineNumberPlan.hidden : null
|
|
377
458
|
const lineNumberSets = lineNumberPlan ? lineNumberPlan.sets : null
|
|
378
459
|
const lineNoteAnchors = lineNotePlan ? lineNotePlan.anchors : null
|
|
@@ -381,6 +462,7 @@ const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmp
|
|
|
381
462
|
let emIdx = 0
|
|
382
463
|
let emStart = -1
|
|
383
464
|
let emEnd = -1
|
|
465
|
+
let emphasisOpen = false
|
|
384
466
|
if (needEmphasis && emphasizeLines && emphasizeLines.length) {
|
|
385
467
|
emStart = emphasizeLines[0][0]
|
|
386
468
|
emEnd = emphasizeLines[0][1]
|
|
@@ -392,7 +474,8 @@ const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmp
|
|
|
392
474
|
|
|
393
475
|
for (let n = 0; n < max; n++) {
|
|
394
476
|
let line = lines[n]
|
|
395
|
-
const
|
|
477
|
+
const hasNextLine = n < max - 1
|
|
478
|
+
const isLogicalLine = n < logicalLineMax
|
|
396
479
|
const doComment = commentLines && commentLines[n]
|
|
397
480
|
const hidden = !!(lineNumberHidden && lineNumberHidden[n])
|
|
398
481
|
const setNumber = lineNumberSets ? lineNumberSets[n] : undefined
|
|
@@ -420,7 +503,7 @@ const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmp
|
|
|
420
503
|
}
|
|
421
504
|
}
|
|
422
505
|
|
|
423
|
-
if (needLineWrap &&
|
|
506
|
+
if (needLineWrap && isLogicalLine && hasNextLine) {
|
|
424
507
|
if (!hasLtChecked) {
|
|
425
508
|
hasLt = line.indexOf('<') !== -1
|
|
426
509
|
hasLtChecked = true
|
|
@@ -450,24 +533,31 @@ const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmp
|
|
|
450
533
|
line = `<span class="${commentClass}">` + line + closeTag
|
|
451
534
|
}
|
|
452
535
|
|
|
453
|
-
if (needLineWrap &&
|
|
536
|
+
if (needLineWrap && isLogicalLine) {
|
|
454
537
|
const lineTags = buildPreLineTags(hidden, setNumber, lineNote)
|
|
455
538
|
line = lineTags.open + line + lineTags.close
|
|
456
539
|
}
|
|
457
540
|
|
|
458
|
-
|
|
541
|
+
const opensEmphasis = needEmphasis && emIdx < emphasizeLines.length && emStart === n + 1
|
|
542
|
+
const closesEmphasis = needEmphasis && emIdx < emphasizeLines.length && emEnd === n
|
|
543
|
+
if (opensEmphasis) {
|
|
459
544
|
line = emphOpenTag + line
|
|
460
545
|
}
|
|
461
|
-
if (
|
|
546
|
+
if (closesEmphasis) {
|
|
462
547
|
line = closeTag + line
|
|
463
548
|
emIdx++
|
|
464
549
|
const nextEmphasis = emphasizeLines[emIdx] || []
|
|
465
550
|
emStart = nextEmphasis[0]
|
|
466
551
|
emEnd = nextEmphasis[1]
|
|
467
552
|
}
|
|
553
|
+
if (opensEmphasis) emphasisOpen = true
|
|
554
|
+
else if (closesEmphasis) emphasisOpen = false
|
|
468
555
|
|
|
469
556
|
lines[n] = line
|
|
470
557
|
}
|
|
558
|
+
if (emphasisOpen && logicalLineMax > 0) {
|
|
559
|
+
lines[logicalLineMax - 1] += closeTag
|
|
560
|
+
}
|
|
471
561
|
return lines.join(br)
|
|
472
562
|
}
|
|
473
563
|
|
|
@@ -502,6 +592,7 @@ const orderTokenAttrs = (token, opt) => {
|
|
|
502
592
|
let rank = rankCache.get(name)
|
|
503
593
|
if (rank === undefined) {
|
|
504
594
|
rank = opt._attrOrderIndex(name)
|
|
595
|
+
if (rankCache.size >= attrOrderRankCacheMaxSize) rankCache.clear()
|
|
505
596
|
rankCache.set(name, rank)
|
|
506
597
|
}
|
|
507
598
|
return rank
|
|
@@ -537,11 +628,22 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
537
628
|
let wrapEnabled = false
|
|
538
629
|
let preWrapValue
|
|
539
630
|
let commentMarkValue
|
|
631
|
+
let tagOverride = ''
|
|
540
632
|
const lineNotes = getTokenLineNotes(token)
|
|
541
633
|
const lineNoteIdPrefix = lineNotes && lineNotes.length ? getLineNoteIdPrefix(token, idx) : ''
|
|
542
634
|
const attrNormalizeStartedAt = timingEnabled ? getNowMs() : 0
|
|
543
635
|
|
|
544
|
-
|
|
636
|
+
const classOnlyAttr = !!(
|
|
637
|
+
token.attrs &&
|
|
638
|
+
token.attrs.length === 1 &&
|
|
639
|
+
token.attrs[0][0] === 'class'
|
|
640
|
+
)
|
|
641
|
+
if (classOnlyAttr) {
|
|
642
|
+
const classLang = getLangFromClassAttr(token.attrs[0][1], opt.langPrefix)
|
|
643
|
+
if (classLang) lang = classLang
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (token.attrs && !classOnlyAttr) {
|
|
545
647
|
const newAttrs = []
|
|
546
648
|
let dataPreStartIndex = -1
|
|
547
649
|
let dataPreEmphasisIndex = -1
|
|
@@ -557,7 +659,7 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
557
659
|
let sawEmphasisAttr = false
|
|
558
660
|
let sawLineNumberSkipAttr = false
|
|
559
661
|
let sawLineNumberSetAttr = false
|
|
560
|
-
|
|
662
|
+
let appendOrder = null
|
|
561
663
|
|
|
562
664
|
for (const attr of token.attrs) {
|
|
563
665
|
const name = attr[0]
|
|
@@ -576,7 +678,7 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
576
678
|
newAttrs.push(attr)
|
|
577
679
|
break
|
|
578
680
|
case 'data-pre-start':
|
|
579
|
-
startNumber = parseStartNumber(val) ?? -1
|
|
681
|
+
if (opt.setLineNumber) startNumber = parseStartNumber(val) ?? -1
|
|
580
682
|
startValue = val
|
|
581
683
|
dataPreStartIndex = newAttrs.length
|
|
582
684
|
newAttrs.push(attr)
|
|
@@ -584,14 +686,16 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
584
686
|
case 'line-number-start':
|
|
585
687
|
case 'start':
|
|
586
688
|
case 'pre-start':
|
|
587
|
-
startNumber = parseStartNumber(val) ?? -1
|
|
689
|
+
if (opt.setLineNumber) startNumber = parseStartNumber(val) ?? -1
|
|
588
690
|
startValue = val
|
|
589
691
|
if (!sawStartAttr) {
|
|
692
|
+
if (!appendOrder) appendOrder = []
|
|
590
693
|
appendOrder.push('start')
|
|
591
694
|
sawStartAttr = true
|
|
592
695
|
}
|
|
593
696
|
break
|
|
594
697
|
case 'data-pre-emphasis':
|
|
698
|
+
if (opt.setEmphasizeLines) emphasizeLines = getEmphasizeLines(val)
|
|
595
699
|
dataPreEmphasisIndex = newAttrs.length
|
|
596
700
|
newAttrs.push(attr)
|
|
597
701
|
break
|
|
@@ -617,6 +721,7 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
617
721
|
if (opt.setEmphasizeLines) emphasizeLines = getEmphasizeLines(val)
|
|
618
722
|
emphasisValue = val
|
|
619
723
|
if (!sawEmphasisAttr) {
|
|
724
|
+
if (!appendOrder) appendOrder = []
|
|
620
725
|
appendOrder.push('emphasis')
|
|
621
726
|
sawEmphasisAttr = true
|
|
622
727
|
}
|
|
@@ -624,14 +729,22 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
624
729
|
case 'comment-mark':
|
|
625
730
|
commentMarkValue = val
|
|
626
731
|
if (!sawCommentMark) {
|
|
732
|
+
if (!appendOrder) appendOrder = []
|
|
627
733
|
appendOrder.push('comment')
|
|
628
734
|
sawCommentMark = true
|
|
629
735
|
}
|
|
630
736
|
break
|
|
737
|
+
case 'samp':
|
|
738
|
+
tagOverride = isTruthyAttrValue(val) ? 'samp' : ''
|
|
739
|
+
break
|
|
740
|
+
case 'code':
|
|
741
|
+
tagOverride = isTruthyAttrValue(val) ? 'code' : ''
|
|
742
|
+
break
|
|
631
743
|
case 'line-number-skip':
|
|
632
744
|
case 'pre-line-number-skip':
|
|
633
745
|
lineNumberSkipValue = val
|
|
634
746
|
if (!sawLineNumberSkipAttr) {
|
|
747
|
+
if (!appendOrder) appendOrder = []
|
|
635
748
|
appendOrder.push('line-number-skip')
|
|
636
749
|
sawLineNumberSkipAttr = true
|
|
637
750
|
}
|
|
@@ -640,6 +753,7 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
640
753
|
case 'pre-line-number-set':
|
|
641
754
|
lineNumberSetValue = val
|
|
642
755
|
if (!sawLineNumberSetAttr) {
|
|
756
|
+
if (!appendOrder) appendOrder = []
|
|
643
757
|
appendOrder.push('line-number-set')
|
|
644
758
|
sawLineNumberSetAttr = true
|
|
645
759
|
}
|
|
@@ -666,21 +780,23 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
666
780
|
if (lineNumberSkipValue !== undefined && dataPreLineNumberSkipIndex >= 0) newAttrs[dataPreLineNumberSkipIndex][1] = lineNumberSkipValue
|
|
667
781
|
if (lineNumberSetValue !== undefined && dataPreLineNumberSetIndex >= 0) newAttrs[dataPreLineNumberSetIndex][1] = lineNumberSetValue
|
|
668
782
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
783
|
+
if (appendOrder) {
|
|
784
|
+
for (const kind of appendOrder) {
|
|
785
|
+
if (kind === 'start' && dataPreStartIndex === -1 && startValue !== undefined) {
|
|
786
|
+
newAttrs.push(['data-pre-start', startValue])
|
|
787
|
+
} else if (kind === 'emphasis' && dataPreEmphasisIndex === -1 && emphasisValue !== undefined) {
|
|
788
|
+
newAttrs.push(['data-pre-emphasis', emphasisValue])
|
|
789
|
+
} else if (kind === 'comment' && dataPreCommentIndex === -1 && commentMarkValue !== undefined) {
|
|
790
|
+
newAttrs.push(['data-pre-comment-mark', commentMarkValue])
|
|
791
|
+
} else if (kind === 'line-number-skip' && dataPreLineNumberSkipIndex === -1 && lineNumberSkipValue !== undefined) {
|
|
792
|
+
newAttrs.push(['data-pre-line-number-skip', lineNumberSkipValue])
|
|
793
|
+
} else if (kind === 'line-number-set' && dataPreLineNumberSetIndex === -1 && lineNumberSetValue !== undefined) {
|
|
794
|
+
newAttrs.push(['data-pre-line-number-set', lineNumberSetValue])
|
|
795
|
+
}
|
|
680
796
|
}
|
|
681
797
|
}
|
|
682
798
|
|
|
683
|
-
if (startNumber !== -1) {
|
|
799
|
+
if (startNumber !== -1 && opt.setLineNumber) {
|
|
684
800
|
styleValue = appendStyleValue(styleValue, 'counter-set:pre-line-number ' + startNumber + ';')
|
|
685
801
|
}
|
|
686
802
|
if (styleIndex >= 0) {
|
|
@@ -695,10 +811,12 @@ const prepareFenceRenderContext = (tokens, idx, opt) => {
|
|
|
695
811
|
|
|
696
812
|
if (timingEnabled) addTimingMs(timings, 'attrNormalizeMs', getNowMs() - attrNormalizeStartedAt)
|
|
697
813
|
if (lineNotes && lineNotes.length) token.attrSet('data-pre-line-notes', 'true')
|
|
814
|
+
const isSamp = tagOverride ? tagOverride === 'samp' : opt._sampLangSet.has(lang)
|
|
698
815
|
|
|
699
816
|
return {
|
|
700
817
|
token,
|
|
701
818
|
lang,
|
|
819
|
+
isSamp,
|
|
702
820
|
startNumber,
|
|
703
821
|
emphasizeLines,
|
|
704
822
|
lineNumberSkipValue,
|
|
@@ -722,6 +840,8 @@ export {
|
|
|
722
840
|
emitFenceDecision,
|
|
723
841
|
finalizeCommonFenceOption,
|
|
724
842
|
finalizeFenceTimings,
|
|
843
|
+
getCommentLineFlags,
|
|
844
|
+
getCommentLineRanges,
|
|
725
845
|
getLogicalLineCount,
|
|
726
846
|
getNowMs,
|
|
727
847
|
getEmphasizeLines,
|
package/src/utils/attr-utils.js
CHANGED
|
@@ -35,6 +35,15 @@ const appendStyleValue = (style, addition) => {
|
|
|
35
35
|
return base + separator + next
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const escapeHtmlAttr = (value) => {
|
|
39
|
+
return String(value ?? '')
|
|
40
|
+
.replace(/&/g, '&')
|
|
41
|
+
.replace(/"/g, '"')
|
|
42
|
+
.replace(/'/g, ''')
|
|
43
|
+
.replace(/</g, '<')
|
|
44
|
+
.replace(/>/g, '>')
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
const parseHtmlAttrs = (attrText) => {
|
|
39
48
|
const attrs = []
|
|
40
49
|
if (!attrText) return attrs
|
|
@@ -113,6 +122,7 @@ const getLangFromClassAttr = (classText, langPrefix) => {
|
|
|
113
122
|
export {
|
|
114
123
|
appendStyleValue,
|
|
115
124
|
createAttrOrderIndexGetter,
|
|
125
|
+
escapeHtmlAttr,
|
|
116
126
|
getInfoAttr,
|
|
117
127
|
getLangFromClassAttr,
|
|
118
128
|
mergeAttrSets,
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/*! Renderer Fence shared base | MIT License */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--rf-code-color-scheme: light;
|
|
5
|
+
--rf-samp-color-scheme: dark;
|
|
6
|
+
|
|
7
|
+
--rf-code-bg: oklch(99.4% 0 0);
|
|
8
|
+
--rf-code-fg: oklch(4% 0 0);
|
|
9
|
+
--rf-code-muted: oklch(42% 0 0);
|
|
10
|
+
--rf-code-border: oklch(86% 0 0);
|
|
11
|
+
|
|
12
|
+
--rf-samp-bg: oklch(18% 0 0);
|
|
13
|
+
--rf-samp-fg: oklch(95% 0 0);
|
|
14
|
+
--rf-samp-muted: oklch(76% 0 0);
|
|
15
|
+
--rf-samp-border: oklch(41% 0 0);
|
|
16
|
+
--rf-samp-prompt: oklch(78% 0.13 285);
|
|
17
|
+
|
|
18
|
+
--rf-accent: oklch(50% 0.18 285);
|
|
19
|
+
--rf-accent-soft: oklch(94% 0.035 285);
|
|
20
|
+
--rf-accent-border: oklch(82% 0.08 285);
|
|
21
|
+
|
|
22
|
+
--rf-syntax-keyword: oklch(38% 0.255 25);
|
|
23
|
+
--rf-syntax-string: oklch(34% 0.235 250);
|
|
24
|
+
--rf-syntax-number: oklch(36% 0.245 260);
|
|
25
|
+
--rf-syntax-comment: oklch(39% 0.026 255);
|
|
26
|
+
--rf-syntax-type: oklch(38% 0.235 295);
|
|
27
|
+
--rf-syntax-title: oklch(39% 0.27 305);
|
|
28
|
+
--rf-syntax-variable: oklch(37% 0.205 80);
|
|
29
|
+
--rf-syntax-literal: oklch(36% 0.245 260);
|
|
30
|
+
--rf-syntax-tag: oklch(34% 0.18 150);
|
|
31
|
+
--rf-syntax-attribute: oklch(36% 0.23 260);
|
|
32
|
+
--rf-syntax-punctuation: oklch(12% 0.018 255);
|
|
33
|
+
--rf-syntax-meta: oklch(12% 0.018 255);
|
|
34
|
+
|
|
35
|
+
--rf-samp-syntax-keyword: oklch(78% 0.08 25);
|
|
36
|
+
--rf-samp-syntax-string: oklch(82% 0.055 250);
|
|
37
|
+
--rf-samp-syntax-number: oklch(80% 0.07 255);
|
|
38
|
+
--rf-samp-syntax-comment: oklch(75% 0.01 255);
|
|
39
|
+
--rf-samp-syntax-type: oklch(81% 0.06 295);
|
|
40
|
+
--rf-samp-syntax-title: oklch(82% 0.07 305);
|
|
41
|
+
--rf-samp-syntax-variable: oklch(82% 0.075 90);
|
|
42
|
+
--rf-samp-syntax-literal: oklch(80% 0.07 255);
|
|
43
|
+
--rf-samp-syntax-tag: oklch(81% 0.065 150);
|
|
44
|
+
--rf-samp-syntax-attribute: oklch(80% 0.07 255);
|
|
45
|
+
--rf-samp-syntax-punctuation: oklch(86% 0.012 255);
|
|
46
|
+
|
|
47
|
+
--rf-line-emphasis-bg: color-mix(in oklch, var(--rf-accent-soft) 70%, transparent);
|
|
48
|
+
--rf-line-number-fg: var(--rf-code-muted);
|
|
49
|
+
--rf-line-number-rule: color-mix(in oklch, var(--rf-code-border) 85%, transparent);
|
|
50
|
+
--rf-line-comment-bg: color-mix(in oklch, var(--rf-syntax-comment) 12%, transparent);
|
|
51
|
+
--rf-line-note-bg: oklch(100% 0 0);
|
|
52
|
+
--rf-line-note-border: var(--rf-accent-border);
|
|
53
|
+
--rf-line-note-fg: var(--rf-code-muted);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media (prefers-color-scheme: dark) {
|
|
57
|
+
:root {
|
|
58
|
+
--rf-code-color-scheme: dark;
|
|
59
|
+
--rf-samp-color-scheme: light;
|
|
60
|
+
|
|
61
|
+
--rf-code-bg: oklch(18% 0 0);
|
|
62
|
+
--rf-code-fg: oklch(95% 0 0);
|
|
63
|
+
--rf-code-muted: oklch(76% 0 0);
|
|
64
|
+
--rf-code-border: oklch(38% 0 0);
|
|
65
|
+
|
|
66
|
+
--rf-samp-bg: oklch(99.4% 0 0);
|
|
67
|
+
--rf-samp-fg: oklch(4% 0 0);
|
|
68
|
+
--rf-samp-muted: oklch(42% 0 0);
|
|
69
|
+
--rf-samp-border: oklch(86% 0 0);
|
|
70
|
+
--rf-samp-prompt: oklch(50% 0.18 285);
|
|
71
|
+
|
|
72
|
+
--rf-accent: oklch(78% 0.13 285);
|
|
73
|
+
--rf-accent-soft: oklch(27% 0.05 285);
|
|
74
|
+
--rf-accent-border: oklch(48% 0.11 285);
|
|
75
|
+
|
|
76
|
+
--rf-syntax-keyword: oklch(78% 0.08 25);
|
|
77
|
+
--rf-syntax-string: oklch(82% 0.055 250);
|
|
78
|
+
--rf-syntax-number: oklch(80% 0.07 255);
|
|
79
|
+
--rf-syntax-comment: oklch(75% 0.01 255);
|
|
80
|
+
--rf-syntax-type: oklch(81% 0.06 295);
|
|
81
|
+
--rf-syntax-title: oklch(82% 0.07 305);
|
|
82
|
+
--rf-syntax-variable: oklch(82% 0.075 90);
|
|
83
|
+
--rf-syntax-literal: oklch(80% 0.07 255);
|
|
84
|
+
--rf-syntax-tag: oklch(81% 0.065 150);
|
|
85
|
+
--rf-syntax-attribute: oklch(80% 0.07 255);
|
|
86
|
+
--rf-syntax-punctuation: oklch(86% 0.012 255);
|
|
87
|
+
--rf-syntax-meta: oklch(86% 0.012 255);
|
|
88
|
+
|
|
89
|
+
--rf-samp-syntax-keyword: oklch(38% 0.255 25);
|
|
90
|
+
--rf-samp-syntax-string: oklch(34% 0.235 250);
|
|
91
|
+
--rf-samp-syntax-number: oklch(36% 0.245 260);
|
|
92
|
+
--rf-samp-syntax-comment: oklch(39% 0.026 255);
|
|
93
|
+
--rf-samp-syntax-type: oklch(38% 0.235 295);
|
|
94
|
+
--rf-samp-syntax-title: oklch(39% 0.27 305);
|
|
95
|
+
--rf-samp-syntax-variable: oklch(37% 0.205 80);
|
|
96
|
+
--rf-samp-syntax-literal: oklch(36% 0.245 260);
|
|
97
|
+
--rf-samp-syntax-tag: oklch(34% 0.18 150);
|
|
98
|
+
--rf-samp-syntax-attribute: oklch(36% 0.23 260);
|
|
99
|
+
--rf-samp-syntax-punctuation: oklch(12% 0.018 255);
|
|
100
|
+
|
|
101
|
+
--rf-line-emphasis-bg: color-mix(in oklch, var(--rf-accent-soft) 70%, transparent);
|
|
102
|
+
--rf-line-number-fg: var(--rf-code-muted);
|
|
103
|
+
--rf-line-number-rule: color-mix(in oklch, var(--rf-code-border) 85%, transparent);
|
|
104
|
+
--rf-line-comment-bg: color-mix(in oklch, var(--rf-syntax-comment) 16%, transparent);
|
|
105
|
+
--rf-line-note-bg: oklch(24% 0.01 255);
|
|
106
|
+
--rf-line-note-border: var(--rf-accent-border);
|
|
107
|
+
--rf-line-note-fg: var(--rf-code-muted);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pre {
|
|
112
|
+
color-scheme: var(--rf-code-color-scheme);
|
|
113
|
+
margin: 0;
|
|
114
|
+
padding: 1rem;
|
|
115
|
+
overflow: auto;
|
|
116
|
+
color: var(--rf-code-fg);
|
|
117
|
+
background: var(--rf-code-bg);
|
|
118
|
+
border: 1px solid var(--rf-code-border);
|
|
119
|
+
border-radius: 0.5rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
pre code,
|
|
123
|
+
pre samp {
|
|
124
|
+
color: inherit;
|
|
125
|
+
background: transparent;
|
|
126
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.pre-lines-emphasis {
|
|
130
|
+
background: var(--rf-line-emphasis-bg);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.pre-line-comment {
|
|
134
|
+
color: var(--rf-syntax-comment);
|
|
135
|
+
background: var(--rf-line-comment-bg);
|
|
136
|
+
padding-block: 0.04em;
|
|
137
|
+
line-height: 1.45;
|
|
138
|
+
-webkit-box-decoration-break: clone;
|
|
139
|
+
box-decoration-break: clone;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
pre:has(> samp) {
|
|
143
|
+
color-scheme: var(--rf-samp-color-scheme);
|
|
144
|
+
--rf-syntax-keyword: var(--rf-samp-syntax-keyword);
|
|
145
|
+
--rf-syntax-string: var(--rf-samp-syntax-string);
|
|
146
|
+
--rf-syntax-number: var(--rf-samp-syntax-number);
|
|
147
|
+
--rf-syntax-comment: var(--rf-samp-syntax-comment);
|
|
148
|
+
--rf-syntax-type: var(--rf-samp-syntax-type);
|
|
149
|
+
--rf-syntax-title: var(--rf-samp-syntax-title);
|
|
150
|
+
--rf-syntax-variable: var(--rf-samp-syntax-variable);
|
|
151
|
+
--rf-syntax-literal: var(--rf-samp-syntax-literal);
|
|
152
|
+
--rf-syntax-tag: var(--rf-samp-syntax-tag);
|
|
153
|
+
--rf-syntax-attribute: var(--rf-samp-syntax-attribute);
|
|
154
|
+
--rf-syntax-punctuation: var(--rf-samp-syntax-punctuation);
|
|
155
|
+
--rf-syntax-meta: var(--rf-samp-syntax-punctuation);
|
|
156
|
+
--line-number-color: var(--rf-samp-muted);
|
|
157
|
+
--line-number-rule-color: var(--rf-samp-border);
|
|
158
|
+
--line-note-color: var(--rf-samp-muted);
|
|
159
|
+
--line-note-label-color: var(--rf-samp-muted);
|
|
160
|
+
--line-note-border-color: var(--rf-samp-border);
|
|
161
|
+
--line-note-background: color-mix(in oklch, var(--rf-samp-bg) 92%, var(--rf-samp-fg));
|
|
162
|
+
color: var(--rf-samp-fg);
|
|
163
|
+
background: var(--rf-samp-bg);
|
|
164
|
+
border-color: var(--rf-samp-border);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pre:has(> samp) .pre-line-comment {
|
|
168
|
+
color: var(--rf-samp-muted);
|
|
169
|
+
background: color-mix(in oklch, var(--rf-samp-muted) 18%, transparent);
|
|
170
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*! Renderer Fence line-notes layout | MIT License */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--line-note-gap: 0.35rem;
|
|
5
|
+
--line-note-inline-gap: 1.25ch;
|
|
6
|
+
--line-note-width: 14rem;
|
|
7
|
+
--line-note-color: var(--rf-line-note-fg, #666);
|
|
8
|
+
--line-note-border-color: var(--rf-line-note-border, #cfcfcf);
|
|
9
|
+
--line-note-background: var(--rf-line-note-bg, rgba(255, 255, 255, 0.72));
|
|
10
|
+
--line-note-font-family: inherit;
|
|
11
|
+
--line-note-font-size: inherit;
|
|
12
|
+
--line-note-line-height: inherit;
|
|
13
|
+
--line-note-padding-block: 0.05rem;
|
|
14
|
+
--line-note-padding-inline: 0.4rem;
|
|
15
|
+
--line-note-anchor-font-size: 0.92em;
|
|
16
|
+
--line-note-anchor-line-height: 1.15;
|
|
17
|
+
--line-note-anchor-padding-block: 0;
|
|
18
|
+
--line-note-anchor-padding-inline: 0.35rem;
|
|
19
|
+
--line-note-radius: 0.25rem;
|
|
20
|
+
--line-note-label-color: var(--line-note-color);
|
|
21
|
+
--line-note-label-prefix: "line ";
|
|
22
|
+
--line-note-label-suffix: ":";
|
|
23
|
+
--line-note-anchor-padding-block-end: 1.25em;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.pre-wrapper-line-notes pre {
|
|
27
|
+
margin-bottom: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.pre-wrapper-line-notes .pre-line-note-layer {
|
|
31
|
+
display: grid;
|
|
32
|
+
gap: var(--line-note-gap);
|
|
33
|
+
margin-top: 0.65rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.pre-wrapper-line-notes .pre-line-note {
|
|
37
|
+
display: grid;
|
|
38
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
39
|
+
align-items: start;
|
|
40
|
+
column-gap: 0.5rem;
|
|
41
|
+
box-sizing: border-box;
|
|
42
|
+
color: var(--line-note-color);
|
|
43
|
+
font-family: var(--line-note-font-family);
|
|
44
|
+
font-size: var(--line-note-font-size);
|
|
45
|
+
line-height: var(--line-note-line-height);
|
|
46
|
+
vertical-align: baseline;
|
|
47
|
+
white-space: pre-wrap;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.pre-wrapper-line-notes .pre-line-note::before {
|
|
51
|
+
content: var(--line-note-label-prefix) attr(data-pre-line-note-label) var(--line-note-label-suffix);
|
|
52
|
+
display: inline-block;
|
|
53
|
+
color: var(--line-note-label-color);
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
font-variant-numeric: tabular-nums;
|
|
56
|
+
white-space: nowrap;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.pre-wrapper-line-notes .pre-line-content {
|
|
60
|
+
display: inline-block;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@supports ((anchor-name: --x) and (position-anchor: --x)) {
|
|
64
|
+
.pre-wrapper-line-notes[data-pre-line-notes-layout="anchor"] {
|
|
65
|
+
position: relative;
|
|
66
|
+
anchor-scope: all;
|
|
67
|
+
padding-block-end: calc(var(--line-note-anchor-padding-block-end) + (var(--pre-line-note-overflow-lines, 0) * 1.5em));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.pre-wrapper-line-notes[data-pre-line-notes-layout="anchor"] .pre-line-note-layer {
|
|
71
|
+
margin-top: 0;
|
|
72
|
+
padding-top: 0;
|
|
73
|
+
border-top: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.pre-wrapper-line-notes[data-pre-line-notes-layout="anchor"] .pre-line-note {
|
|
77
|
+
display: block;
|
|
78
|
+
position: absolute;
|
|
79
|
+
inset-block-start: anchor(top);
|
|
80
|
+
inset-inline-start: calc(anchor(right) + var(--line-note-inline-gap));
|
|
81
|
+
inline-size: clamp(0px, calc(100% - anchor(right) - var(--line-note-inline-gap)), var(--line-note-width));
|
|
82
|
+
padding: var(--line-note-anchor-padding-block) var(--line-note-anchor-padding-inline);
|
|
83
|
+
border: 1px solid var(--line-note-border-color);
|
|
84
|
+
border-radius: var(--line-note-radius);
|
|
85
|
+
background: var(--line-note-background);
|
|
86
|
+
font-size: var(--line-note-anchor-font-size);
|
|
87
|
+
line-height: var(--line-note-anchor-line-height);
|
|
88
|
+
transform: translateY(0.08em);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.pre-wrapper-line-notes[data-pre-line-notes-layout="anchor"] .pre-line-note::before {
|
|
92
|
+
content: none;
|
|
93
|
+
}
|
|
94
|
+
}
|