|
1 | | -const fs = require('fs'); |
2 | | -const vsctm = require('vscode-textmate'); |
3 | | -const onig = require('onigasm'); |
4 | | -const onigWasm = require.resolve('onigasm/lib/onigasm.wasm'); |
| 1 | +const fs = require("fs"); |
| 2 | +const vsctm = require("vscode-textmate"); |
| 3 | +const onig = require("onigasm"); |
| 4 | +const onigWasm = require.resolve("onigasm/lib/onigasm.wasm"); |
5 | 5 |
|
6 | 6 | const wasm = fs.readFileSync(onigWasm).buffer; |
7 | 7 |
|
8 | | -hexo.extend.filter.register('after_init', initialize); |
9 | | -hexo.extend.filter.register('marked:renderer', hookRenderer); |
| 8 | +hexo.extend.filter.register("after_init", initialize); |
| 9 | +hexo.extend.filter.register("marked:renderer", hookRenderer); |
| 10 | + |
| 11 | +function escapeHTML(str) { |
| 12 | + return str.replace( |
| 13 | + /[&<>'"]/g, |
| 14 | + (tag) => |
| 15 | + ({ |
| 16 | + "&": "&", |
| 17 | + "<": "<", |
| 18 | + ">": ">", |
| 19 | + "'": "'", |
| 20 | + '"': """, |
| 21 | + }[tag] || tag) |
| 22 | + ); |
| 23 | +} |
10 | 24 |
|
11 | 25 | async function initialize() { |
12 | 26 | await onig.loadWASM(wasm); |
13 | 27 |
|
14 | 28 | const registry = new vsctm.Registry({ |
15 | 29 | onigLib: Promise.resolve({ |
16 | 30 | createOnigScanner: (sources) => new onig.OnigScanner(sources), |
17 | | - createOnigString: (str) => new onig.OnigString(str) |
| 31 | + createOnigString: (str) => new onig.OnigString(str), |
18 | 32 | }), |
19 | 33 | loadGrammar: async (scopeName) => { |
20 | | - if (scopeName === 'source.grain') { |
21 | | - let path = './grain-language-server/editor-extensions/vscode/syntaxes/grain.json' |
22 | | - let grammar = fs.readFileSync(path) |
23 | | - return vsctm.parseRawGrammar(grammar.toString(), path) |
| 34 | + if (scopeName === "source.grain") { |
| 35 | + let path = |
| 36 | + "./grain-language-server/editor-extensions/vscode/syntaxes/grain.json"; |
| 37 | + let grammar = fs.readFileSync(path); |
| 38 | + return vsctm.parseRawGrammar(grammar.toString(), path); |
24 | 39 | } |
25 | 40 | console.log(`Unknown scope name: ${scopeName}`); |
26 | 41 | return null; |
27 | | - } |
| 42 | + }, |
28 | 43 | }); |
29 | 44 |
|
30 | | - const grammar = await registry.loadGrammar('source.grain'); |
| 45 | + const grammar = await registry.loadGrammar("source.grain"); |
31 | 46 |
|
32 | 47 | this.grain = { registry, grammar }; |
33 | 48 | } |
34 | 49 |
|
35 | 50 | function makeGutter(numLines) { |
36 | | - let line = (num) => `<span class="line">${num}</span><br>` |
37 | | - let lines = [] |
| 51 | + let line = (num) => `<span class="line">${num}</span><br>`; |
| 52 | + let lines = []; |
38 | 53 | for (let i = 1; i <= numLines; i++) { |
39 | | - lines.push(line(i)) |
| 54 | + lines.push(line(i)); |
40 | 55 | } |
41 | | - return `<td class="gutter"><pre>${lines.join('')}</pre></td>` |
| 56 | + return `<td class="gutter"><pre>${lines.join("")}</pre></td>`; |
42 | 57 | } |
43 | 58 |
|
44 | 59 | function hookRenderer(renderer) { |
45 | 60 | const { grammar } = this.grain; |
46 | 61 |
|
47 | 62 | renderer.code = function (code, lang) { |
48 | | - let result = [] |
49 | | - let text = code.split('\n') |
| 63 | + let result = []; |
| 64 | + let text = code.split("\n"); |
50 | 65 |
|
51 | | - if (lang === 'grain' || lang === 'gr') { |
| 66 | + if (lang === "grain" || lang === "gr") { |
52 | 67 | let ruleStack = vsctm.INITIAL; |
53 | 68 | for (let i = 0; i < text.length; i++) { |
54 | 69 | const line = text[i]; |
55 | 70 | const lineTokens = grammar.tokenizeLine(line, ruleStack); |
56 | | - const lineRes = [] |
| 71 | + const lineRes = []; |
57 | 72 | for (let j = 0; j < lineTokens.tokens.length; j++) { |
58 | 73 | const token = lineTokens.tokens[j]; |
59 | | - const tokenString = line.substring(token.startIndex, token.endIndex) |
60 | | - const classString = token.scopes.map(scope => scope.replace(/\./g, ' ')).join(' ') |
61 | | - lineRes.push(`<span class="${classString}">${tokenString}</span>`) |
| 74 | + const tokenString = line.substring(token.startIndex, token.endIndex); |
| 75 | + const classString = token.scopes |
| 76 | + .map((scope) => scope.replace(/\./g, " ")) |
| 77 | + .join(" "); |
| 78 | + lineRes.push(`<span class="${classString}">${tokenString}</span>`); |
62 | 79 | } |
63 | | - result.push(`<span class="line">${lineRes.join('')}</span><br>`) |
| 80 | + result.push(`<span class="line">${lineRes.join("")}</span><br>`); |
64 | 81 | ruleStack = lineTokens.ruleStack; |
65 | 82 | } |
66 | 83 | } else { |
67 | | - result = text.map(line => `<span class="line">${line}</span><br>`) |
| 84 | + result = text.map( |
| 85 | + (line) => `<span class="line">${escapeHTML(line)}</span><br>` |
| 86 | + ); |
68 | 87 | } |
69 | 88 |
|
70 | | - return `<figure class="tm-highlight"><table><tbody><tr>${makeGutter(text.length)}<td class="code"><pre>${result.join('')}</pre></td><td class="code-tools"><a class="code-copy" role="button" alt="copy code"><i class="far fa-clone"></i></a></td></tr></tbody></table></figure>`; |
71 | | - } |
| 89 | + return `<figure class="tm-highlight"><table><tbody><tr>${makeGutter( |
| 90 | + text.length |
| 91 | + )}<td class="code"><pre>${result.join( |
| 92 | + "" |
| 93 | + )}</pre></td><td class="code-tools"><a class="code-copy" role="button" alt="copy code"><i class="far fa-clone"></i></a></td></tr></tbody></table></figure>`; |
| 94 | + }; |
72 | 95 | } |
0 commit comments