UNPKG

prism-code-editor

Version:

Lightweight, extensible code editor component for the web using Prism

163 lines (162 loc) 5.42 kB
//#region src/prism/core.js var plainTextGrammar = {}; var rest = Symbol(); var tokenize = Symbol(); /** @param {*} id */ var resolve = (id) => typeof id == "string" ? languages[id] : id; /** @type {Record<string, any>} */ var languages = { plain: plainTextGrammar, plaintext: plainTextGrammar, text: plainTextGrammar, txt: plainTextGrammar }; /** * @param {string} text * @param {any} grammar */ var tokenizeText = (text, grammar) => (grammar[tokenize] || withoutTokenizer)(text, grammar); /** * @param {string} text * @param {any} grammar */ var withoutTokenizer = (text, grammar) => { /** @type {LinkedListNode} */ var startNode = [text]; var restGrammar; /** @type {(string | Token)[]} */ var array = [], i = 0; while (restGrammar = resolve(grammar[rest])) { delete grammar[rest]; Object.assign(grammar, restGrammar); } matchGrammar(text, grammar, startNode, 0); while (array[i++] = startNode[0], startNode = startNode[1]); return array; }; /** * @param {string} string * @param {RegExp} pattern * @param {string} replacement */ var escapeHtml = (string, pattern, replacement) => { return string.replace(/&/g, "&amp;").replace(pattern, replacement); }; var closingTag = "</span>"; var openingTags = ""; var closingTags = ""; /** @param {(string | Token)[]} tokens */ var highlightTokens = (tokens) => { var str = "", token, i = 0; while (token = tokens[i++]) str += stringify(token); return str; }; /** * @param {string | Token | (string | Token)[]} token * @returns {string} */ var stringify = (token) => { if (token instanceof Token) { var { type, alias, content } = token; var prevOpening = openingTags; var prevClosing = closingTags; var opening = `<span class="token ${type + (alias ? " " + alias : "") + (type == "keyword" && typeof content == "string" ? " keyword-" + content : "")}">`; closingTags += closingTag; openingTags += opening; var contentStr = stringify(content); openingTags = prevOpening; closingTags = prevClosing; return opening + contentStr + closingTag; } if (typeof token != "string") return highlightTokens(token); token = escapeHtml(token, /</g, "&lt;"); if (closingTags && token.includes("\n")) return token.replace(/\n/g, closingTags + "\n" + openingTags); return token; }; /** * @param {string} text * @param {*} ref */ var highlightText = (text, ref) => highlightTokens(tokenizeText(text, resolve(ref))); /** * @param {string} text * @param {any} grammar * @param {LinkedListNode} startNode * @param {number} startPos * @param {[string, number, number]} [rematch] * * @typedef {[string | Token, LinkedListNode?]} LinkedListNode */ var matchGrammar = (text, grammar, startNode, startPos, rematch) => { for (var token in grammar) if (grammar[token]) for (var j = 0, p = grammar[token], patternObj, patterns = Array.isArray(p) ? p : [p]; patternObj = patterns[j]; j++) { if (rematch && rematch[0] == token && rematch[1] == j) return; /** @type {RegExp} */ var pattern = patternObj.pattern || patternObj; var inside = resolve(patternObj.inside); var lookbehind = patternObj.lookbehind; var greedy = pattern.global; var alias = patternObj.alias; for (var currentNode = startNode, pos = startPos; currentNode && (!rematch || pos < rematch[2]); pos += currentNode[0].length, currentNode = currentNode[1]) { var str = currentNode[0]; var removeCount = 0; var match; if (str instanceof Token) continue; pattern.lastIndex = greedy ? pos : 0; match = pattern.exec(greedy ? text : str); if (!match && greedy) break; if (!(match && match[0])) continue; var lookbehindLength = lookbehind && match[1] ? match[1].length : 0; var from = match.index + lookbehindLength; var matchStr = match[0].slice(lookbehindLength); var to = from + matchStr.length; var k, p; if (greedy) { for (; p = pos + currentNode[0].length, from >= p; currentNode = currentNode[1], pos = p); if (currentNode[0] instanceof Token) continue; for (k = currentNode, p = pos; (p += k[0].length) < to; k = k[1], removeCount++); str = text.slice(pos, p); from -= pos; to -= pos; } var after = str.slice(to); var reach = pos + str.length; var newToken = new Token(token, inside ? tokenizeText(matchStr, inside) : matchStr, matchStr, alias); var next = currentNode, i = 0; var nestedRematch; while (next = next[1], i++ < removeCount); if (after) if (!next || next[0] instanceof Token) next = [after, next]; else next[0] = after + next[0]; pos += from; currentNode[0] = from ? str.slice(0, from) : newToken; if (from) currentNode = currentNode[1] = [newToken, next]; else currentNode[1] = next; if (removeCount) { matchGrammar(text, grammar, currentNode, pos, nestedRematch = [ token, j, reach ]); reach = nestedRematch[2]; } if (rematch && reach > rematch[2]) rematch[2] = reach; } } }; /** * Creates a new token. * * @param {string} type * @param {string | any[]} content * @param {string} matchedStr * @param {string} alias * @class */ function Token(type, content, matchedStr, alias) { this.type = type; this.content = content; this.alias = alias; this.length = matchedStr.length; } //#endregion export { languages as a, tokenize as c, highlightTokens as i, tokenizeText as l, escapeHtml as n, resolve as o, highlightText as r, rest as s, Token as t, withoutTokenizer as u }; //# sourceMappingURL=core-8vQkh0Rd.js.map