-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Command Line: Some refactoring (#2290)
- Loading branch information
1 parent
06495f9
commit 8c9c289
Showing
2 changed files
with
158 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,140 +1,182 @@ | ||
(function() { | ||
(function () { | ||
|
||
if (typeof self === 'undefined' || !self.Prism || !self.document) { | ||
return; | ||
} | ||
|
||
var clsReg = /(?:^|\s)command-line(?:\s|$)/; | ||
|
||
Prism.hooks.add('before-highlight', function (env) { | ||
var vars = env.vars = env.vars || {}; | ||
var commandLine = vars['command-line'] = vars['command-line'] || {}; | ||
|
||
if (commandLine.complete || !env.code) { | ||
commandLine.complete = true; | ||
if (typeof self === 'undefined' || !self.Prism || !self.document) { | ||
return; | ||
} | ||
|
||
// Works only for <code> wrapped inside <pre> (not inline). | ||
var pre = env.element.parentNode; | ||
if (!pre || !/pre/i.test(pre.nodeName) || // Abort only if neither the <pre> nor the <code> have the class | ||
(!clsReg.test(pre.className) && !clsReg.test(env.element.className))) { | ||
commandLine.complete = true; | ||
return; | ||
var CLASS_PATTERN = /(?:^|\s)command-line(?:\s|$)/; | ||
var PROMPT_CLASS = 'command-line-prompt'; | ||
|
||
/** @type {(str: string, prefix: string) => boolean} */ | ||
var startsWith = "".startsWith | ||
? function (s, p) { return s.startsWith(p); } | ||
: function (s, p) { return s.indexOf(p) === 0; }; | ||
|
||
/** | ||
* Repeats the given string some number of times. | ||
* | ||
* This is just a polyfill for `String.prototype.repeat`. | ||
* | ||
* @param {string} str | ||
* @param {number} times | ||
* @returns {string} | ||
*/ | ||
function repeat(str, times) { | ||
var s = ""; | ||
for (var i = 0; i < times; i++) { | ||
s += str; | ||
} | ||
return s; | ||
} | ||
|
||
// The element might be highlighted multiple times, so we just remove the previous prompt | ||
var existingPrompt = env.element.querySelector('.command-line-prompt'); | ||
if (existingPrompt) { | ||
existingPrompt.remove(); | ||
/** | ||
* Returns the command line info object from the given hook environment. | ||
* | ||
* @param {any} env | ||
* @returns {CommandLineInfo} | ||
* | ||
* @typedef CommandLineInfo | ||
* @property {boolean} [complete] | ||
* @property {number} [numberOfLines] | ||
* @property {string[]} [outputLines] | ||
*/ | ||
function getCommandLineInfo(env) { | ||
var vars = env.vars = env.vars || {}; | ||
return vars['command-line'] = vars['command-line'] || {}; | ||
} | ||
|
||
var codeLines = env.code.split('\n'); | ||
commandLine.numberOfLines = codeLines.length; | ||
var outputLines = commandLine.outputLines = []; | ||
|
||
var outputSections = pre.getAttribute('data-output'); | ||
var outputFilter = pre.getAttribute('data-filter-output'); | ||
if (outputSections || outputSections === '') { // The user specified the output lines. -- cwells | ||
outputSections = outputSections.split(','); | ||
for (var i = 0; i < outputSections.length; i++) { // Parse the output sections into start/end ranges. -- cwells | ||
var range = outputSections[i].split('-'); | ||
var outputStart = parseInt(range[0], 10); | ||
var outputEnd = (range.length === 2 ? parseInt(range[1], 10) : outputStart); | ||
|
||
if (!isNaN(outputStart) && !isNaN(outputEnd)) { | ||
if (outputStart < 1) { | ||
outputStart = 1; | ||
} | ||
if (outputEnd > codeLines.length) { | ||
outputEnd = codeLines.length; | ||
|
||
Prism.hooks.add('before-highlight', function (env) { | ||
var commandLine = getCommandLineInfo(env); | ||
|
||
if (commandLine.complete || !env.code) { | ||
commandLine.complete = true; | ||
return; | ||
} | ||
|
||
// Works only for <code> wrapped inside <pre> (not inline). | ||
var pre = env.element.parentElement; | ||
if (!pre || !/pre/i.test(pre.nodeName) || // Abort only if neither the <pre> nor the <code> have the class | ||
(!CLASS_PATTERN.test(pre.className) && !CLASS_PATTERN.test(env.element.className))) { | ||
commandLine.complete = true; | ||
return; | ||
} | ||
|
||
// The element might be highlighted multiple times, so we just remove the previous prompt | ||
var existingPrompt = env.element.querySelector('.' + PROMPT_CLASS); | ||
if (existingPrompt) { | ||
existingPrompt.remove(); | ||
} | ||
|
||
var codeLines = env.code.split('\n'); | ||
commandLine.numberOfLines = codeLines.length; | ||
/** @type {string[]} */ | ||
var outputLines = commandLine.outputLines = []; | ||
|
||
var outputSections = pre.getAttribute('data-output'); | ||
var outputFilter = pre.getAttribute('data-filter-output'); | ||
if (outputSections !== null) { // The user specified the output lines. -- cwells | ||
outputSections.split(',').forEach(function (section) { | ||
var range = section.split('-'); | ||
var outputStart = parseInt(range[0], 10); | ||
var outputEnd = range.length === 2 ? parseInt(range[1], 10) : outputStart; | ||
|
||
if (!isNaN(outputStart) && !isNaN(outputEnd)) { | ||
if (outputStart < 1) { | ||
outputStart = 1; | ||
} | ||
if (outputEnd > codeLines.length) { | ||
outputEnd = codeLines.length; | ||
} | ||
// Convert start and end to 0-based to simplify the arrays. -- cwells | ||
outputStart--; | ||
outputEnd--; | ||
// Save the output line in an array and clear it in the code so it's not highlighted. -- cwells | ||
for (var j = outputStart; j <= outputEnd; j++) { | ||
outputLines[j] = codeLines[j]; | ||
codeLines[j] = ''; | ||
} | ||
} | ||
// Convert start and end to 0-based to simplify the arrays. -- cwells | ||
outputStart--; | ||
outputEnd--; | ||
// Save the output line in an array and clear it in the code so it's not highlighted. -- cwells | ||
for (var j = outputStart; j <= outputEnd; j++) { | ||
outputLines[j] = codeLines[j]; | ||
codeLines[j] = ''; | ||
}); | ||
} else if (outputFilter) { // Treat lines beginning with this string as output. -- cwells | ||
for (var i = 0; i < codeLines.length; i++) { | ||
if (startsWith(codeLines[i], outputFilter)) { // This line is output. -- cwells | ||
outputLines[i] = codeLines[i].slice(outputFilter.length); | ||
codeLines[i] = ''; | ||
} | ||
} | ||
} | ||
} else if (outputFilter) { // Treat lines beginning with this string as output. -- cwells | ||
for (var i = 0; i < codeLines.length; i++) { | ||
if (codeLines[i].indexOf(outputFilter) === 0) { // This line is output. -- cwells | ||
outputLines[i] = codeLines[i].slice(outputFilter.length); | ||
codeLines[i] = ''; | ||
} | ||
|
||
env.code = codeLines.join('\n'); | ||
}); | ||
|
||
Prism.hooks.add('before-insert', function (env) { | ||
var commandLine = getCommandLineInfo(env); | ||
|
||
if (commandLine.complete) { | ||
return; | ||
} | ||
} | ||
|
||
env.code = codeLines.join('\n'); | ||
}); | ||
// Reinsert the output lines into the highlighted code. -- cwells | ||
var codeLines = env.highlightedCode.split('\n'); | ||
var outputLines = commandLine.outputLines || []; | ||
for (var i = 0, l = outputLines.length; i < l; i++) { | ||
if (outputLines.hasOwnProperty(i)) { | ||
codeLines[i] = outputLines[i]; | ||
} | ||
} | ||
env.highlightedCode = codeLines.join('\n'); | ||
}); | ||
|
||
Prism.hooks.add('before-insert', function (env) { | ||
var vars = env.vars = env.vars || {}; | ||
var commandLine = vars['command-line'] = vars['command-line'] || {}; | ||
if (commandLine.complete) { | ||
return; | ||
} | ||
Prism.hooks.add('complete', function (env) { | ||
var commandLine = getCommandLineInfo(env); | ||
|
||
// Reinsert the output lines into the highlighted code. -- cwells | ||
var codeLines = env.highlightedCode.split('\n'); | ||
for (var i = 0, l = (commandLine.outputLines || []).length; i < l; i++) { | ||
if (commandLine.outputLines.hasOwnProperty(i)) { | ||
codeLines[i] = commandLine.outputLines[i]; | ||
if (commandLine.complete) { | ||
return; | ||
} | ||
} | ||
env.highlightedCode = codeLines.join('\n'); | ||
}); | ||
|
||
Prism.hooks.add('complete', function (env) { | ||
var vars = env.vars = env.vars || {}; | ||
var commandLine = vars['command-line'] = vars['command-line'] || {}; | ||
if (commandLine.complete) { | ||
return; | ||
} | ||
var pre = env.element.parentElement; | ||
if (CLASS_PATTERN.test(env.element.className)) { // Remove the class "command-line" from the <code> | ||
env.element.className = env.element.className.replace(CLASS_PATTERN, ' '); | ||
} | ||
if (!CLASS_PATTERN.test(pre.className)) { // Add the class "command-line" to the <pre> | ||
pre.className += ' command-line'; | ||
} | ||
|
||
var pre = env.element.parentNode; | ||
if (clsReg.test(env.element.className)) { // Remove the class "command-line" from the <code> | ||
env.element.className = env.element.className.replace(clsReg, ' '); | ||
} | ||
if (!clsReg.test(pre.className)) { // Add the class "command-line" to the <pre> | ||
pre.className += ' command-line'; | ||
} | ||
function getAttribute(key, defaultValue) { | ||
return (pre.getAttribute(key) || defaultValue).replace(/"/g, '"'); | ||
} | ||
|
||
var getAttribute = function(key, defaultValue) { | ||
return (pre.getAttribute(key) || defaultValue).replace(/"/g, '"'); | ||
}; | ||
|
||
// Create the "rows" that will become the command-line prompts. -- cwells | ||
var promptLines = new Array((commandLine.numberOfLines || 0) + 1); | ||
var promptText = getAttribute('data-prompt', ''); | ||
if (promptText !== '') { | ||
promptLines = promptLines.join('<span data-prompt="' + promptText + '"></span>'); | ||
} else { | ||
var user = getAttribute('data-user', 'user'); | ||
var host = getAttribute('data-host', 'localhost'); | ||
promptLines = promptLines.join('<span data-user="' + user + '" data-host="' + host + '"></span>'); | ||
} | ||
// Create the "rows" that will become the command-line prompts. -- cwells | ||
var promptLines; | ||
var rowCount = commandLine.numberOfLines || 0; | ||
var promptText = getAttribute('data-prompt', ''); | ||
if (promptText !== '') { | ||
promptLines = repeat('<span data-prompt="' + promptText + '"></span>', rowCount); | ||
} else { | ||
var user = getAttribute('data-user', 'user'); | ||
var host = getAttribute('data-host', 'localhost'); | ||
promptLines = repeat('<span data-user="' + user + '" data-host="' + host + '"></span>', rowCount); | ||
} | ||
|
||
// Create the wrapper element. -- cwells | ||
var prompt = document.createElement('span'); | ||
prompt.className = 'command-line-prompt'; | ||
prompt.innerHTML = promptLines; | ||
|
||
// Remove the prompt from the output lines. -- cwells | ||
for (var i = 0, l = (commandLine.outputLines || []).length; i < l; i++) { | ||
if (commandLine.outputLines.hasOwnProperty(i)) { | ||
var node = prompt.children[i]; | ||
node.removeAttribute('data-user'); | ||
node.removeAttribute('data-host'); | ||
node.removeAttribute('data-prompt'); | ||
// Create the wrapper element. -- cwells | ||
var prompt = document.createElement('span'); | ||
prompt.className = PROMPT_CLASS; | ||
prompt.innerHTML = promptLines; | ||
|
||
// Remove the prompt from the output lines. -- cwells | ||
var outputLines = commandLine.outputLines || []; | ||
for (var i = 0, l = outputLines.length; i < l; i++) { | ||
if (outputLines.hasOwnProperty(i)) { | ||
var node = prompt.children[i]; | ||
node.removeAttribute('data-user'); | ||
node.removeAttribute('data-host'); | ||
node.removeAttribute('data-prompt'); | ||
} | ||
} | ||
} | ||
|
||
env.element.insertBefore(prompt, env.element.firstChild); | ||
commandLine.complete = true; | ||
}); | ||
env.element.insertBefore(prompt, env.element.firstChild); | ||
commandLine.complete = true; | ||
}); | ||
|
||
}()); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.