@peaceroad/markdown-it-renderer-fence 0.3.1 → 0.4.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 +24 -1
- package/index.js +65 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -133,6 +133,25 @@ const longLine = 'This line is long but wraps.'
|
|
|
133
133
|
|
|
134
134
|
When `setPreWrapStyle` is set to false, only `data-pre-wrap="true"` is added and the inline style is omitted.
|
|
135
135
|
|
|
136
|
+
## Mark comment lines in code blocks
|
|
137
|
+
|
|
138
|
+
Add `comment-line` attribute to mark comment lines. Lines that start with the given marker (after leading whitespace) are wrapped with `<span class="pre-comment-line">`.
|
|
139
|
+
|
|
140
|
+
~~~md
|
|
141
|
+
```samp {comment-line="#"}
|
|
142
|
+
# comment
|
|
143
|
+
echo 1
|
|
144
|
+
```
|
|
145
|
+
~~~
|
|
146
|
+
|
|
147
|
+
~~~html
|
|
148
|
+
<pre><samp data-pre-comment-line="#"><span class="pre-comment-line"># comment</span>
|
|
149
|
+
echo 1
|
|
150
|
+
</samp></pre>
|
|
151
|
+
~~~
|
|
152
|
+
|
|
153
|
+
Note: this feature relies on line splitting and is disabled when `useHighlightPre` is true and `<pre><code>` is provided by the highlighter.
|
|
154
|
+
|
|
136
155
|
|
|
137
156
|
## Options
|
|
138
157
|
|
|
@@ -142,8 +161,12 @@ The following options can be specified when initializing the plugin:
|
|
|
142
161
|
- setHighlight: default true — enable calling highlight function (e.g., highlight.js).
|
|
143
162
|
- setLineNumber: default true — wrap lines in spans for line numbers.
|
|
144
163
|
- setEmphasizeLines: default true — enable emphasis based on emphasize-lines attribute.
|
|
145
|
-
-
|
|
164
|
+
- lineEndSpanThreshold: default 0 — character count threshold to append end-of-line span (0 to disable).
|
|
165
|
+
- setLineEndSpan: alias for lineEndSpanThreshold.
|
|
146
166
|
- lineEndSpanClass: default 'pre-lineend-spacer' — CSS class for end-of-line span.
|
|
147
167
|
- setPreWrapStyle: default true — include inline pre-wrap styles on `<pre>` when wrap is enabled.
|
|
168
|
+
- useHighlightPre: default false — if highlight returns `<pre><code>`, keep that wrapper and skip line-splitting features; attributes are still merged.
|
|
169
|
+
|
|
170
|
+
When `useHighlightPre` is true and the highlight output contains `<pre><code>`, line-splitting features are disabled (setLineNumber, setEmphasizeLines, lineEndSpanThreshold, comment-line).
|
|
148
171
|
- sampLang: default 'shell,console' — comma-separated list of languages (in addition to 'samp') that will be rendered using `<samp>`.
|
|
149
172
|
- langPrefix: default md.options.langPrefix || 'language-' — prefix for language class on code blocks.
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const interAttrsSpaceReg = / +/
|
|
|
5
5
|
const tagReg = /<\/?([A-Za-z][A-Za-z0-9-]*)(?:\s+[^>]*?)?\/?\s*>/g
|
|
6
6
|
const preLineTag = '<span class="pre-line">'
|
|
7
7
|
const emphOpenTag = '<span class="pre-lines-emphasis">'
|
|
8
|
+
const commentLineClass = 'pre-comment-line'
|
|
8
9
|
const closeTag = '</span>'
|
|
9
10
|
const closeTagLen = closeTag.length
|
|
10
11
|
const preWrapStyle = 'white-space: pre-wrap; overflow-wrap: anywhere;'
|
|
@@ -95,10 +96,11 @@ const getEmphasizeLines = (attrVal) => {
|
|
|
95
96
|
return lines
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, threshold, lineEndSpanClass, br) => {
|
|
99
|
+
const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, threshold, lineEndSpanClass, br, commentLines, commentClass) => {
|
|
99
100
|
const lines = content.split(br)
|
|
100
101
|
const len = lines.length
|
|
101
102
|
const endSpanTag = needEndSpan ? `<span class="${lineEndSpanClass}"></span>` : ''
|
|
103
|
+
const needComment = !!(commentLines && commentClass)
|
|
102
104
|
const maxLine = len - (lines[len - 1] === '' ? 1 : 0)
|
|
103
105
|
let emIdx = 0
|
|
104
106
|
let emStart
|
|
@@ -167,6 +169,13 @@ const splitFenceBlockToLines = (content, emphasizeLines, needLineNumber, needEmp
|
|
|
167
169
|
lines[n+1] = `<${tagName}>` + (lines[n+1]||'')
|
|
168
170
|
}
|
|
169
171
|
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (needComment && commentLines[n]) {
|
|
175
|
+
line = `<span class="${commentClass}">` + line + closeTag
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (needLineNumber && n !== len - 1) {
|
|
170
179
|
line = preLineTag + line + closeTag
|
|
171
180
|
}
|
|
172
181
|
|
|
@@ -242,15 +251,18 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
242
251
|
let emphasizeLines = []
|
|
243
252
|
let wrapEnabled = false
|
|
244
253
|
let preWrapValue
|
|
254
|
+
let commentLineValue
|
|
245
255
|
|
|
246
256
|
if (token.attrs) {
|
|
247
257
|
const newAttrs = []
|
|
248
258
|
let dataPreStartIndex = -1
|
|
249
259
|
let dataPreEmphasisIndex = -1
|
|
250
260
|
let styleIndex = -1
|
|
261
|
+
let dataPreCommentIndex = -1
|
|
251
262
|
let startValue
|
|
252
263
|
let emphasisValue
|
|
253
264
|
let styleValue
|
|
265
|
+
let sawCommentLine = false
|
|
254
266
|
let sawStartAttr = false
|
|
255
267
|
let sawEmphasisAttr = false
|
|
256
268
|
const appendOrder = []
|
|
@@ -292,6 +304,11 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
292
304
|
dataPreEmphasisIndex = newAttrs.length
|
|
293
305
|
newAttrs.push(attr)
|
|
294
306
|
break
|
|
307
|
+
case 'data-pre-comment-line':
|
|
308
|
+
dataPreCommentIndex = newAttrs.length
|
|
309
|
+
commentLineValue = val
|
|
310
|
+
newAttrs.push(attr)
|
|
311
|
+
break
|
|
295
312
|
case 'em-lines':
|
|
296
313
|
case 'emphasize-lines':
|
|
297
314
|
emphasizeLines = getEmphasizeLines(val)
|
|
@@ -301,6 +318,13 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
301
318
|
sawEmphasisAttr = true
|
|
302
319
|
}
|
|
303
320
|
break
|
|
321
|
+
case 'comment-line':
|
|
322
|
+
commentLineValue = val
|
|
323
|
+
if (!sawCommentLine) {
|
|
324
|
+
appendOrder.push('comment')
|
|
325
|
+
sawCommentLine = true
|
|
326
|
+
}
|
|
327
|
+
break
|
|
304
328
|
case 'data-pre-wrap':
|
|
305
329
|
preWrapValue = val
|
|
306
330
|
if (val === '' || val === 'true') wrapEnabled = true
|
|
@@ -322,6 +346,9 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
322
346
|
if (emphasisValue !== undefined && dataPreEmphasisIndex >= 0) {
|
|
323
347
|
newAttrs[dataPreEmphasisIndex][1] = emphasisValue
|
|
324
348
|
}
|
|
349
|
+
if (commentLineValue !== undefined && dataPreCommentIndex >= 0) {
|
|
350
|
+
newAttrs[dataPreCommentIndex][1] = commentLineValue
|
|
351
|
+
}
|
|
325
352
|
for (const kind of appendOrder) {
|
|
326
353
|
if (kind === 'start') {
|
|
327
354
|
if (dataPreStartIndex === -1 && startValue !== undefined) {
|
|
@@ -331,6 +358,10 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
331
358
|
if (dataPreEmphasisIndex === -1 && emphasisValue !== undefined) {
|
|
332
359
|
newAttrs.push(['data-pre-emphasis', emphasisValue])
|
|
333
360
|
}
|
|
361
|
+
} else if (kind === 'comment') {
|
|
362
|
+
if (dataPreCommentIndex === -1 && commentLineValue !== undefined) {
|
|
363
|
+
newAttrs.push(['data-pre-comment-line', commentLineValue])
|
|
364
|
+
}
|
|
334
365
|
}
|
|
335
366
|
}
|
|
336
367
|
if (startNumber !== -1) {
|
|
@@ -345,6 +376,19 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
345
376
|
token.attrs = newAttrs
|
|
346
377
|
}
|
|
347
378
|
|
|
379
|
+
const isSamp = opt._sampReg.test(lang)
|
|
380
|
+
let commentLines
|
|
381
|
+
let needComment = false
|
|
382
|
+
if (commentLineValue) {
|
|
383
|
+
const rawLines = token.content.split(/\r?\n/)
|
|
384
|
+
commentLines = new Array(rawLines.length)
|
|
385
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
386
|
+
const isComment = rawLines[i].trimStart().startsWith(commentLineValue)
|
|
387
|
+
commentLines[i] = isComment
|
|
388
|
+
if (isComment) needComment = true
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
348
392
|
if (opt.setHighlight && md.options.highlight) {
|
|
349
393
|
if (lang && lang !== 'samp' ) {
|
|
350
394
|
content = md.options.highlight(content, lang)
|
|
@@ -356,9 +400,12 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
356
400
|
}
|
|
357
401
|
|
|
358
402
|
let preAttrsFromHighlight
|
|
359
|
-
|
|
403
|
+
let hasHighlightPre = false
|
|
404
|
+
const hasPreTag = (content.indexOf('<pre') !== -1 || content.indexOf('<PRE') !== -1)
|
|
405
|
+
if (hasPreTag) {
|
|
360
406
|
const preMatch = content.match(preCodeWrapperReg)
|
|
361
407
|
if (preMatch) {
|
|
408
|
+
hasHighlightPre = true
|
|
362
409
|
preAttrsFromHighlight = parseHtmlAttrs(preMatch[1])
|
|
363
410
|
const codeAttrsFromHighlight = parseHtmlAttrs(preMatch[2])
|
|
364
411
|
content = preMatch[3]
|
|
@@ -368,6 +415,9 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
368
415
|
}
|
|
369
416
|
}
|
|
370
417
|
}
|
|
418
|
+
if (opt.useHighlightPre && hasPreTag && !hasHighlightPre) {
|
|
419
|
+
return content.endsWith('\n') ? content : content + '\n'
|
|
420
|
+
}
|
|
371
421
|
orderTokenAttrs(token, opt)
|
|
372
422
|
|
|
373
423
|
let preAttrs = preAttrsFromHighlight ? preAttrsFromHighlight.slice() : []
|
|
@@ -392,14 +442,15 @@ const getFenceHtml = (tokens, idx, md, opt, slf) => {
|
|
|
392
442
|
|
|
393
443
|
const needLineNumber = opt.setLineNumber && startNumber >= 0
|
|
394
444
|
const needEmphasis = opt.setEmphasizeLines && emphasizeLines.length > 0
|
|
395
|
-
const needEndSpan = opt.
|
|
396
|
-
|
|
445
|
+
const needEndSpan = opt.lineEndSpanThreshold > 0
|
|
446
|
+
const useHighlightPre = opt.useHighlightPre && hasHighlightPre
|
|
447
|
+
if (!useHighlightPre && (needLineNumber || needEmphasis || needEndSpan || needComment)) {
|
|
397
448
|
const nlIndex = content.indexOf('\n')
|
|
398
449
|
const br = nlIndex > 0 && content[nlIndex - 1] === '\r' ? '\r\n' : '\n'
|
|
399
|
-
content = splitFenceBlockToLines(content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, opt.
|
|
450
|
+
content = splitFenceBlockToLines(content, emphasizeLines, needLineNumber, needEmphasis, needEndSpan, opt.lineEndSpanThreshold, opt.lineEndSpanClass, br, commentLines, commentLineClass)
|
|
400
451
|
}
|
|
401
452
|
|
|
402
|
-
const tag =
|
|
453
|
+
const tag = isSamp ? 'samp' : 'code'
|
|
403
454
|
return `<pre${preAttrsText}><${tag}${slf.renderAttrs(token)}>${content}</${tag}></pre>\n`
|
|
404
455
|
}
|
|
405
456
|
|
|
@@ -409,13 +460,19 @@ const mditRendererFence = (md, option) => {
|
|
|
409
460
|
setHighlight: true,
|
|
410
461
|
setLineNumber: true,
|
|
411
462
|
setEmphasizeLines: true,
|
|
412
|
-
|
|
463
|
+
lineEndSpanThreshold: 0,
|
|
413
464
|
lineEndSpanClass: 'pre-lineend-spacer',
|
|
414
465
|
setPreWrapStyle: true,
|
|
466
|
+
useHighlightPre: false,
|
|
415
467
|
sampLang: 'shell,console',
|
|
416
468
|
langPrefix: md.options.langPrefix || 'language-',
|
|
417
469
|
}
|
|
418
|
-
if (option)
|
|
470
|
+
if (option) {
|
|
471
|
+
Object.assign(opt, option)
|
|
472
|
+
if (option.lineEndSpanThreshold == null && option.setLineEndSpan != null) {
|
|
473
|
+
opt.lineEndSpanThreshold = option.setLineEndSpan
|
|
474
|
+
}
|
|
475
|
+
}
|
|
419
476
|
|
|
420
477
|
opt._sampReg = new RegExp('^(?:samp|' + opt.sampLang.split(',').join('|') + ')$')
|
|
421
478
|
opt._langReg = new RegExp(opt.langPrefix + '([A-Za-z0-9-]+)')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peaceroad/markdown-it-renderer-fence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "In code blocks, the `<samp>` tag is used with the language keywords `samp`, `shell`, and `console`, and provides an option to display line numbers.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"repository": "https://github.com/peaceroad/p7d-markdown-it-renderer-fence",
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@peaceroad/markdown-it-figure-with-p-caption": "^0.15.
|
|
19
|
+
"@peaceroad/markdown-it-figure-with-p-caption": "^0.15.2",
|
|
20
20
|
"highlight.js": "^11.11.1",
|
|
21
21
|
"markdown-it": "^14.1.0",
|
|
22
22
|
"markdown-it-attrs": "^4.3.1",
|