forked from hexojs/hexo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.ts
More file actions
147 lines (129 loc) · 4.33 KB
/
code.ts
File metadata and controls
147 lines (129 loc) · 4.33 KB
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Based on: https://raw.github.com/imathis/octopress/master/plugins/code_block.rb
import { escapeHTML } from 'hexo-util';
import type Hexo from '../../hexo';
import type { HighlightOptions } from '../../extend/syntax_highlight';
const rCaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+)\s+(.+)/i;
const rCaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/\S+)/i;
const rCaption = /\S[\S\s]*/;
/**
* Code block tag
* Syntax:
* {% codeblock [options] %}
* code snippet
* {% endcodeblock %}
* @param {String} title Caption text
* @param {Object} lang Specify language
* @param {String} url Source link
* @param {String} link_text Text of the link
* @param {Object} line_number Show line number, value must be a boolean
* @param {Object} highlight Enable code highlighting, value must be a boolean
* @param {Object} first_line Specify the first line number, value must be a number
* @param {Object} mark Line highlight specific line(s), each value separated by a comma. Specify number range using a dash
* Example: `mark:1,4-7,10` will mark line 1, 4 to 7 and 10.
* @param {Object} wrap Wrap the code block in <table>, value must be a boolean
* @returns {String} Code snippet with code highlighting
*/
function parseArgs(args: string[]): HighlightOptions {
const _else = [];
const len = args.length;
let lang: string, language_attr: boolean,
line_number: boolean, line_threshold: number, wrap: boolean;
let firstLine = 1;
const mark = [];
for (let i = 0; i < len; i++) {
const colon = args[i].indexOf(':');
if (colon === -1) {
_else.push(args[i]);
continue;
}
const key = args[i].slice(0, colon);
const value = args[i].slice(colon + 1);
switch (key) {
case 'lang':
lang = value;
break;
case 'line_number':
line_number = value === 'true';
break;
case 'line_threshold':
if (!isNaN(Number(value))) line_threshold = +value;
break;
case 'first_line':
if (!isNaN(Number(value))) firstLine = +value;
break;
case 'wrap':
wrap = value === 'true';
break;
case 'mark': {
for (const cur of value.split(',')) {
const hyphen = cur.indexOf('-');
if (hyphen !== -1) {
let a = +cur.slice(0, hyphen);
let b = +cur.slice(hyphen + 1);
if (Number.isNaN(a) || Number.isNaN(b)) continue;
if (b < a) { // switch a & b
[a, b] = [b, a];
}
for (; a <= b; a++) {
mark.push(a);
}
}
if (!isNaN(Number(cur))) mark.push(+cur);
}
break;
}
case 'language_attr': {
language_attr = value === 'true';
break;
}
default: {
_else.push(args[i]);
}
}
}
const arg = _else.join(' ');
// eslint-disable-next-line one-var
let match, caption = '';
if ((match = arg.match(rCaptionUrlTitle)) != null) {
caption = `<span>${match[1]}</span><a href="${match[2]}">${match[3]}</a>`;
} else if ((match = arg.match(rCaptionUrl)) != null) {
caption = `<span>${match[1]}</span><a href="${match[2]}">link</a>`;
} else if ((match = arg.match(rCaption)) != null) {
caption = `<span>${match[0]}</span>`;
}
return {
lang,
language_attr,
firstLine,
caption,
line_number,
line_threshold,
mark,
wrap
};
}
export = (ctx: Hexo) => function codeTag(args: string[], content: string) {
// If neither highlight.js nor prism.js is enabled, return escaped code directly
if (!ctx.extend.highlight.query(ctx.config.syntax_highlighter)) {
return `<pre><code>${escapeHTML(content)}</code></pre>`;
}
let index: number;
let enableHighlight = true;
if ((index = args.findIndex(item => item.startsWith('highlight:'))) !== -1) {
const arg = args[index];
const highlightStr = arg.slice(10);
enableHighlight = highlightStr === 'true';
args.splice(index, 1);
}
// If 'highlight: false' is given, return escaped code directly
if (!enableHighlight) {
return `<pre><code>${escapeHTML(content)}</code></pre>`;
}
const options = parseArgs(args);
options.lines_length = content.split('\n').length;
content = ctx.extend.highlight.exec(ctx.config.syntax_highlighter, {
context: ctx,
args: [content, options]
});
return content.replace(/{/g, '{').replace(/}/g, '}');
};