/
backtick_code_block.ts
81 lines (65 loc) · 2.63 KB
/
backtick_code_block.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import type Hexo from '../../../hexo';
import type { RenderData } from '../../../types';
const rBacktick = /^((?:[^\S\r\n]*>){0,3}[^\S\r\n]*)(`{3,}|~{3,})[^\S\r\n]*((?:.*?[^`\s])?)[^\S\r\n]*\n((?:[\s\S]*?\n)?)(?:(?:[^\S\r\n]*>){0,3}[^\S\r\n]*)\2[^\S\r\n]?(\n+|$)/gm;
const rAllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/;
const rLangCaption = /([^\s]+)\s*(.+)?/;
const escapeSwigTag = (str: string) => str.replace(/{/g, '{').replace(/}/g, '}');
interface Options {
lang: string,
caption: string,
lines_length: number,
firstLineNumber?: string | number
}
export = (ctx: Hexo): (data: RenderData) => void => {
return function backtickCodeBlock(data: RenderData): void {
const dataContent = data.content;
if ((!dataContent.includes('```') && !dataContent.includes('~~~')) || !ctx.extend.highlight.query(ctx.config.syntax_highlighter)) return;
data.content = dataContent.replace(rBacktick, ($0, start, $2, _args, _content, end) => {
let content = _content.replace(/\n$/, '');
// neither highlight or prismjs is enabled, return escaped content directly.
if (!ctx.extend.highlight.query(ctx.config.syntax_highlighter)) return escapeSwigTag($0);
// Extract language and caption of code blocks
const args = _args.split('=').shift();
let lang: string, caption: string;
if (args) {
const match = rAllOptions.exec(args) || rLangCaption.exec(args);
if (match) {
lang = match[1];
if (match[2]) {
caption = `<span>${match[2]}</span>`;
if (match[3]) {
caption += `<a href="${match[3]}">${match[4] ? match[4] : 'link'}</a>`;
}
}
}
}
// PR #3765
if (start.includes('>')) {
// heading of last line is already removed by the top RegExp "rBacktick"
const depth = start.split('>').length - 1;
const regexp = new RegExp(`^([^\\S\\r\\n]*>){0,${depth}}([^\\S\\r\\n]|$)`, 'mg');
content = content.replace(regexp, '');
}
const options: Options = {
lang,
caption,
lines_length: content.split('\n').length
};
// setup line number by inline
_args = _args.replace('=+', '=');
// setup firstLineNumber;
if (_args.includes('=')) {
options.firstLineNumber = _args.split('=')[1] || 1;
}
content = ctx.extend.highlight.exec(ctx.config.syntax_highlighter, {
context: ctx,
args: [content, options]
});
return start
+ '<hexoPostRenderCodeBlock>'
+ escapeSwigTag(content)
+ '</hexoPostRenderCodeBlock>'
+ end;
});
};
};