From c70306847f236fee4ae131f322eab36dcd4bf3cb Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Sun, 16 Feb 2020 01:21:18 -0500 Subject: [PATCH] add HTML renderer --- src/highlight.js | 14 ++++++++------ src/lib/html_renderer.js | 42 ++++++++++++++++++++++++++++++++++++++++ src/lib/token_tree.js | 12 ++++++++++-- 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/lib/html_renderer.js diff --git a/src/highlight.js b/src/highlight.js index 920dd990ad..97807faa96 100644 --- a/src/highlight.js +++ b/src/highlight.js @@ -522,28 +522,30 @@ const HLJS = function(hljs) { } compileLanguage(language); - var current; var top = continuation || language; var continuations = {}; // keep continuations for sub-languages - var result = ''; + var result; var emitter = new TokenTree(); processContinuations(); var mode_buffer = ''; var relevance = 0; + var match, processedCount, index = 0; + try { - var match, count, index = 0; while (true) { top.terminators.lastIndex = index; match = top.terminators.exec(codeToHighlight); if (!match) break; - count = processLexeme(codeToHighlight.substring(index, match.index), match); - index = match.index + count; + let beforeMatch = codeToHighlight.substring(index, match.index); + processedCount = processLexeme(beforeMatch, match); + index = match.index + processedCount; } processLexeme(codeToHighlight.substr(index)); emitter.closeAllNodes(); - emitter.collapse(); + emitter.finalize(); result = new HTMLRenderer(emitter, options).value(); + return { relevance: relevance, value: result, diff --git a/src/lib/html_renderer.js b/src/lib/html_renderer.js new file mode 100644 index 0000000000..03bd29b1a6 --- /dev/null +++ b/src/lib/html_renderer.js @@ -0,0 +1,42 @@ +const SPAN_CLOSE = ''; + +import {escapeHTML} from './utils'; + +export default class HTMLRenderer { + constructor(tree, options) { + this.buffer = ""; + this.classPrefix = options.classPrefix; + tree.walk(this); + } + + // renderer API + + addText(text) { + this.buffer += escapeHTML(text) + } + + openNode(node) { + let className = node.kind; + if (!node.kind) return; + + if (!node.sublanguage) + className = `${this.classPrefix}${className}`; + this.span(className); + } + + closeNode(node) { + if (!node.kind) return; + + this.buffer += SPAN_CLOSE; + } + + // helpers + + span(className) { + this.buffer += `` + } + + value() { + return this.buffer; + } +} diff --git a/src/lib/token_tree.js b/src/lib/token_tree.js index ab28284186..68d68bba6a 100644 --- a/src/lib/token_tree.js +++ b/src/lib/token_tree.js @@ -3,12 +3,15 @@ export default class TokenTree { this.rootNode = { root: true, children: [] }; this.stack = [ this.rootNode ]; } + get top() { return this.stack[this.stack.length - 1]; } + add(node) { this.top.children.push(node); } + addKeyword(text, kind) { if (text === "") { return; } @@ -17,11 +20,13 @@ export default class TokenTree { children: [ text ] }); } + addText(text) { if (text === "") { return; } this.add(text); } + addSublanguage({rootNode}, name) { let node = rootNode; delete node.root; // no longer a root node @@ -29,25 +34,28 @@ export default class TokenTree { node.sublanguage = true; this.add(node); } + openNode(kind) { var node = { kind, children: [] }; this.add(node); this.stack.push(node); } + closeNode() { if (this.stack.length > 1) this.stack.pop(); } + closeAllNodes() { while (this.stack.length > 1) this.closeNode(); } - toJSON() { return JSON.stringify(this.rootNode, null, 4); } - collapse() { + + finalize() { return; TokenTree._collapse(this.rootNode); }