vendor/assets/javascripts/prism.js in highlighting-0.1.2 vs vendor/assets/javascripts/prism.js in highlighting-0.1.3

- old
+ new

@@ -18,11 +18,12 @@ */ var Prism = (function(){ // Private helper vars -var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i; +var lang = /\blang(?:uage)?-(\w+)\b/i; +var uniqueId = 0; var _ = _self.Prism = { util: { encode: function (tokens) { if (tokens instanceof Token) { @@ -36,10 +37,17 @@ type: function (o) { return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1]; }, + objId: function (obj) { + if (!obj['__id']) { + Object.defineProperty(obj, '__id', { value: ++uniqueId }); + } + return obj['__id']; + }, + // Deep clone a language definition (e.g. to extend it) clone: function (o) { var type = _.util.type(o); switch (type) { @@ -84,23 +92,23 @@ * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted. */ insertBefore: function (inside, before, insert, root) { root = root || _.languages; var grammar = root[inside]; - + if (arguments.length == 2) { insert = arguments[1]; - + for (var newToken in insert) { if (insert.hasOwnProperty(newToken)) { grammar[newToken] = insert[newToken]; } } - + return grammar; } - + var ret = {}; for (var token in grammar) { if (grammar.hasOwnProperty(token)) { @@ -116,11 +124,11 @@ } ret[token] = grammar[token]; } } - + // Update references in other language definitions _.languages.DFS(_.languages, function(key, value) { if (value === root[inside] && key != inside) { this[key] = ret; } @@ -128,32 +136,42 @@ return root[inside] = ret; }, // Traverse a language definition with Depth First Search - DFS: function(o, callback, type) { + DFS: function(o, callback, type, visited) { + visited = visited || {}; for (var i in o) { if (o.hasOwnProperty(i)) { callback.call(o, i, o[i], type || i); - if (_.util.type(o[i]) === 'Object') { - _.languages.DFS(o[i], callback); + if (_.util.type(o[i]) === 'Object' && !visited[_.util.objId(o[i])]) { + visited[_.util.objId(o[i])] = true; + _.languages.DFS(o[i], callback, null, visited); } - else if (_.util.type(o[i]) === 'Array') { - _.languages.DFS(o[i], callback, i); + else if (_.util.type(o[i]) === 'Array' && !visited[_.util.objId(o[i])]) { + visited[_.util.objId(o[i])] = true; + _.languages.DFS(o[i], callback, i, visited); } } } } }, plugins: {}, - + highlightAll: function(async, callback) { - var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'); + var env = { + callback: callback, + selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' + }; + _.hooks.run("before-highlightall", env); + + var elements = env.elements || document.querySelectorAll(env.selector); + for (var i=0, element; element = elements[i++];) { - _.highlightElement(element, async === true, callback); + _.highlightElement(element, async === true, env.callback); } }, highlightElement: function(element, async, callback) { // Find language @@ -185,11 +203,13 @@ language: language, grammar: grammar, code: code }; - if (!code || !grammar) { + _.hooks.run('before-sanity-check', env); + + if (!env.code || !env.grammar) { _.hooks.run('complete', env); return; } _.hooks.run('before-highlight', env); @@ -259,10 +279,11 @@ for (var j = 0; j < patterns.length; ++j) { var pattern = patterns[j], inside = pattern.inside, lookbehind = !!pattern.lookbehind, + greedy = !!pattern.greedy, lookbehindLength = 0, alias = pattern.alias; pattern = pattern.pattern || pattern; @@ -279,40 +300,80 @@ continue; } pattern.lastIndex = 0; - var match = pattern.exec(str); + var match = pattern.exec(str), + delNum = 1; - if (match) { - if(lookbehind) { - lookbehindLength = match[1].length; + // Greedy patterns can override/remove up to two previously matched tokens + if (!match && greedy && i != strarr.length - 1) { + // Reconstruct the original text using the next two tokens + var nextToken = strarr[i + 1].matchedStr || strarr[i + 1], + combStr = str + nextToken; + + if (i < strarr.length - 2) { + combStr += strarr[i + 2].matchedStr || strarr[i + 2]; } - var from = match.index - 1 + lookbehindLength, - match = match[0].slice(lookbehindLength), - len = match.length, - to = from + len, - before = str.slice(0, from + 1), - after = str.slice(to + 1); + // Try the pattern again on the reconstructed text + pattern.lastIndex = 0; + match = pattern.exec(combStr); + if (!match) { + continue; + } - var args = [i, 1]; + var from = match.index + (lookbehind ? match[1].length : 0); + // To be a valid candidate, the new match has to start inside of str + if (from >= str.length) { + continue; + } + var to = match.index + match[0].length, + len = str.length + nextToken.length; - if (before) { - args.push(before); + // Number of tokens to delete and replace with the new match + delNum = 3; + + if (to <= len) { + if (strarr[i + 1].greedy) { + continue; + } + delNum = 2; + combStr = combStr.slice(0, len); } + str = combStr; + } - var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias); + if (!match) { + continue; + } - args.push(wrapped); + if(lookbehind) { + lookbehindLength = match[1].length; + } - if (after) { - args.push(after); - } + var from = match.index + lookbehindLength, + match = match[0].slice(lookbehindLength), + to = from + match.length, + before = str.slice(0, from), + after = str.slice(to); - Array.prototype.splice.apply(strarr, args); + var args = [i, delNum]; + + if (before) { + args.push(before); } + + var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy); + + args.push(wrapped); + + if (after) { + args.push(after); + } + + Array.prototype.splice.apply(strarr, args); } } } return strarr; @@ -341,14 +402,17 @@ } } } }; -var Token = _.Token = function(type, content, alias) { +var Token = _.Token = function(type, content, alias, matchedStr, greedy) { this.type = type; this.content = content; this.alias = alias; + // Copy of the full string this token was created from + this.matchedStr = matchedStr || null; + this.greedy = !!greedy; }; Token.stringify = function(o, language, parent) { if (typeof o == 'string') { return o; @@ -410,15 +474,13 @@ }, false); return _self.Prism; } -// Get current script and highlight -var script = document.getElementsByTagName('script'); +//Get current script and highlight +var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop(); -script = script[script.length - 1]; - if (script) { _.filename = script.src; if (document.addEventListener && !script.hasAttribute('data-manual')) { document.addEventListener('DOMContentLoaded', _.highlightAll); @@ -557,11 +619,14 @@ { pattern: /(^|[^\\:])\/\/.*/, lookbehind: true } ], - 'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + 'string': { + pattern: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + greedy: true + }, 'class-name': { pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i, lookbehind: true, inside: { punctuation: /(\.|\\)/ @@ -588,17 +653,19 @@ }); Prism.languages.insertBefore('javascript', 'keyword', { 'regex': { pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/, - lookbehind: true + lookbehind: true, + greedy: true } }); Prism.languages.insertBefore('javascript', 'class-name', { 'template-string': { - pattern: /`(?:\\`|\\?[^`])*`/, + pattern: /`(?:\\\\|\\?[^\\])*?`/, + greedy: true, inside: { 'interpolation': { pattern: /\$\{[^}]+\}/, inside: { 'interpolation-punctuation': { @@ -637,17 +704,18 @@ self.Prism.fileHighlight = function() { var Extensions = { 'js': 'javascript', - 'html': 'markup', - 'svg': 'markup', - 'xml': 'markup', 'py': 'python', 'rb': 'ruby', 'ps1': 'powershell', - 'psm1': 'powershell' + 'psm1': 'powershell', + 'sh': 'bash', + 'bat': 'batch', + 'h': 'c', + 'tex': 'latex' }; if(Array.prototype.forEach) { // Check to prevent error in IE8 Array.prototype.slice.call(document.querySelectorAll('pre[data-src]')).forEach(function (pre) { var src = pre.getAttribute('data-src'); @@ -701,8 +769,8 @@ }); } }; - self.Prism.fileHighlight(); + document.addEventListener('DOMContentLoaded', self.Prism.fileHighlight); })();