update
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
$(function () {
|
||||
$('select').change(beautify);
|
||||
});
|
||||
var the = {
|
||||
use_codemirror: (!window.location.href.match(/without-codemirror/)),
|
||||
beautify_in_progress: false,
|
||||
editor: null // codemirror editor
|
||||
};
|
||||
|
||||
function run_tests() {
|
||||
var st = new SanityTest();
|
||||
run_beautifier_tests(st, Urlencoded, js_beautify, html_beautify, css_beautify);
|
||||
JavascriptObfuscator.run_tests(st);
|
||||
P_A_C_K_E_R.run_tests(st);
|
||||
Urlencoded.run_tests(st);
|
||||
MyObfuscate.run_tests(st);
|
||||
var results = st.results_raw()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/\r/g, '·')
|
||||
.replace(/\n/g, '<br>');
|
||||
$('#testresults').html(results).show();
|
||||
}
|
||||
|
||||
|
||||
function any(a, b) {
|
||||
return a || b;
|
||||
}
|
||||
function unpacker_filter(source) {
|
||||
var trailing_comments = '',
|
||||
comment = '',
|
||||
unpacked = '',
|
||||
found = false;
|
||||
|
||||
// cut trailing comments
|
||||
do {
|
||||
found = false;
|
||||
if (/^\s*\/\*/.test(source)) {
|
||||
found = true;
|
||||
comment = source.substr(0, source.indexOf('*/') + 2);
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
} else if (/^\s*\/\//.test(source)) {
|
||||
found = true;
|
||||
comment = source.match(/^\s*\/\/.*/)[0];
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
}
|
||||
} while (found);
|
||||
|
||||
var unpackers = [P_A_C_K_E_R, Urlencoded, /*JavascriptObfuscator,*/MyObfuscate];
|
||||
for (var i = 0; i < unpackers.length; i++) {
|
||||
if (unpackers[i].detect(source)) {
|
||||
unpacked = unpackers[i].unpack(source);
|
||||
if (unpacked != source) {
|
||||
source = unpacker_filter(unpacked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trailing_comments + source;
|
||||
}
|
||||
|
||||
|
||||
function beautify() {
|
||||
if (the.beautify_in_progress) return;
|
||||
|
||||
the.beautify_in_progress = true;
|
||||
|
||||
var source = the.editor ? the.editor.getValue() : $('#code').val(),
|
||||
output,
|
||||
opts = {};
|
||||
|
||||
opts.indent_size = $('#tabsize').val();
|
||||
opts.indent_char = opts.indent_size == 1 ? '\t' : ' ';
|
||||
opts.max_preserve_newlines = $('#max-preserve-newlines').val();
|
||||
opts.preserve_newlines = opts.max_preserve_newlines !== "-1";
|
||||
opts.keep_array_indentation = false;
|
||||
opts.break_chained_methods = false;
|
||||
opts.indent_scripts = "keep";
|
||||
opts.brace_style = $('#brace-style').val();
|
||||
opts.space_before_conditional = false;
|
||||
opts.unescape_strings = false;
|
||||
opts.jslint_happy = false;
|
||||
opts.end_with_newline = false;
|
||||
opts.wrap_line_length = $('#wrap-line-length').val();
|
||||
|
||||
if (looks_like_html(source)) {
|
||||
output = html_beautify(source, opts);
|
||||
} else if (the.editor.options.mode == 'css') {
|
||||
output = css_beautify(source);
|
||||
} else {
|
||||
if ($('#detect-packers').prop('checked')) {
|
||||
source = unpacker_filter(source);
|
||||
}
|
||||
output = js_beautify(source, opts);
|
||||
}
|
||||
if (the.editor) {
|
||||
the.editor.setValue(output);
|
||||
} else {
|
||||
$('#code').val(output);
|
||||
}
|
||||
|
||||
the.beautify_in_progress = false;
|
||||
}
|
||||
|
||||
function looks_like_html(source) {
|
||||
|
||||
var trimmed = source.replace(/^[ \t\n\r]+/, '');
|
||||
var comment_mark = '<' + '!-' + '-';
|
||||
return (trimmed && (trimmed.substring(0, 1) === '<' && trimmed.substring(0, 4) !== comment_mark));
|
||||
}
|
||||
|
||||
function Clean() {
|
||||
$('#code').val("");
|
||||
the.editor.setValue("");
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
CSS Beautifier
|
||||
---------------
|
||||
|
||||
Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
|
||||
Usage:
|
||||
css_beautify(source_text);
|
||||
css_beautify(source_text, options);
|
||||
|
||||
The options are (default in brackets):
|
||||
indent_size (4) — indentation size,
|
||||
indent_char (space) — character to indent with,
|
||||
selector_separator_newline (true) - separate selectors with newline or
|
||||
not (e.g. "a,\nbr" or "a, br")
|
||||
end_with_newline (false) - end with a newline
|
||||
|
||||
e.g
|
||||
|
||||
css_beautify(css_source_text, {
|
||||
'indent_size': 1,
|
||||
'indent_char': '\t',
|
||||
'selector_separator': ' ',
|
||||
'end_with_newline': false,
|
||||
});
|
||||
*/
|
||||
|
||||
// http://www.w3.org/TR/CSS21/syndata.html#tokenization
|
||||
// http://www.w3.org/TR/css3-syntax/
|
||||
|
||||
(function() {
|
||||
function css_beautify(source_text, options) {
|
||||
options = options || {};
|
||||
var indentSize = options.indent_size || 4;
|
||||
var indentCharacter = options.indent_char || ' ';
|
||||
var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline;
|
||||
var end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
|
||||
|
||||
// compatibility
|
||||
if (typeof indentSize === "string") {
|
||||
indentSize = parseInt(indentSize, 10);
|
||||
}
|
||||
|
||||
|
||||
// tokenizer
|
||||
var whiteRe = /^\s+$/;
|
||||
var wordRe = /[\w$\-_]/;
|
||||
|
||||
var pos = -1,
|
||||
ch;
|
||||
|
||||
function next() {
|
||||
ch = source_text.charAt(++pos);
|
||||
return ch || '';
|
||||
}
|
||||
|
||||
function peek(skipWhitespace) {
|
||||
var prev_pos = pos;
|
||||
if (skipWhitespace) {
|
||||
eatWhitespace();
|
||||
}
|
||||
result = source_text.charAt(pos + 1) || '';
|
||||
pos = prev_pos - 1;
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
|
||||
function eatString(endChars) {
|
||||
var start = pos;
|
||||
while (next()) {
|
||||
if (ch === "\\") {
|
||||
next();
|
||||
} else if (endChars.indexOf(ch) !== -1) {
|
||||
break;
|
||||
} else if (ch === "\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return source_text.substring(start, pos + 1);
|
||||
}
|
||||
|
||||
function peekString(endChar) {
|
||||
var prev_pos = pos;
|
||||
var str = eatString(endChar);
|
||||
pos = prev_pos - 1;
|
||||
next();
|
||||
return str;
|
||||
}
|
||||
|
||||
function eatWhitespace() {
|
||||
var result = '';
|
||||
while (whiteRe.test(peek())) {
|
||||
next()
|
||||
result += ch;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function skipWhitespace() {
|
||||
var result = '';
|
||||
if (ch && whiteRe.test(ch)) {
|
||||
result = ch;
|
||||
}
|
||||
while (whiteRe.test(next())) {
|
||||
result += ch
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function eatComment(singleLine) {
|
||||
var start = pos;
|
||||
var singleLine = peek() === "/";
|
||||
next();
|
||||
while (next()) {
|
||||
if (!singleLine && ch === "*" && peek() === "/") {
|
||||
next();
|
||||
break;
|
||||
} else if (singleLine && ch === "\n") {
|
||||
return source_text.substring(start, pos);
|
||||
}
|
||||
}
|
||||
|
||||
return source_text.substring(start, pos) + ch;
|
||||
}
|
||||
|
||||
|
||||
function lookBack(str) {
|
||||
return source_text.substring(pos - str.length, pos).toLowerCase() ===
|
||||
str;
|
||||
}
|
||||
|
||||
// Nested pseudo-class if we are insideRule
|
||||
// and the next special character found opens
|
||||
// a new block
|
||||
function foundNestedPseudoClass() {
|
||||
for (var i = pos + 1; i < source_text.length; i++){
|
||||
var ch = source_text.charAt(i);
|
||||
if (ch === "{"){
|
||||
return true;
|
||||
} else if (ch === ";" || ch === "}" || ch === ")") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// printer
|
||||
var basebaseIndentString = source_text.match(/^[\t ]*/)[0];
|
||||
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
|
||||
var indentLevel = 0;
|
||||
var nestedLevel = 0;
|
||||
|
||||
function indent() {
|
||||
indentLevel++;
|
||||
basebaseIndentString += singleIndent;
|
||||
}
|
||||
|
||||
function outdent() {
|
||||
indentLevel--;
|
||||
basebaseIndentString = basebaseIndentString.slice(0, -indentSize);
|
||||
}
|
||||
|
||||
var print = {};
|
||||
print["{"] = function(ch) {
|
||||
print.singleSpace();
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
};
|
||||
print["}"] = function(ch) {
|
||||
print.newLine();
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
};
|
||||
|
||||
print._lastCharWhitespace = function() {
|
||||
return whiteRe.test(output[output.length - 1]);
|
||||
};
|
||||
|
||||
print.newLine = function(keepWhitespace) {
|
||||
if (!keepWhitespace) {
|
||||
print.trim();
|
||||
}
|
||||
|
||||
if (output.length) {
|
||||
output.push('\n');
|
||||
}
|
||||
if (basebaseIndentString) {
|
||||
output.push(basebaseIndentString);
|
||||
}
|
||||
};
|
||||
print.singleSpace = function() {
|
||||
if (output.length && !print._lastCharWhitespace()) {
|
||||
output.push(' ');
|
||||
}
|
||||
};
|
||||
|
||||
print.trim = function() {
|
||||
while (print._lastCharWhitespace()) {
|
||||
output.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var output = [];
|
||||
if (basebaseIndentString) {
|
||||
output.push(basebaseIndentString);
|
||||
}
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
var insideRule = false;
|
||||
var enteringConditionalGroup = false;
|
||||
var top_ch = '';
|
||||
var last_top_ch = '';
|
||||
|
||||
while (true) {
|
||||
var whitespace = skipWhitespace();
|
||||
var isAfterSpace = whitespace !== '';
|
||||
var isAfterNewline = whitespace.indexOf('\n') !== -1;
|
||||
var last_top_ch = top_ch;
|
||||
var top_ch = ch;
|
||||
|
||||
if (!ch) {
|
||||
break;
|
||||
} else if (ch === '/' && peek() === '*') { /* css comment */
|
||||
var header = lookBack("");
|
||||
print.newLine();
|
||||
output.push(eatComment());
|
||||
print.newLine();
|
||||
if (header) {
|
||||
print.newLine(true);
|
||||
}
|
||||
} else if (ch === '/' && peek() === '/') { // single line comment
|
||||
if (!isAfterNewline && last_top_ch !== '{') {
|
||||
print.trim();
|
||||
}
|
||||
print.singleSpace();
|
||||
output.push(eatComment());
|
||||
print.newLine();
|
||||
} else if (ch === '@') {
|
||||
// pass along the space we found as a separate item
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
output.push(ch);
|
||||
|
||||
// strip trailing space, if present, for hash property checks
|
||||
var variableOrRule = peekString(": ,;{}()[]/='\"").replace(/\s$/, '');
|
||||
|
||||
// might be a nesting at-rule
|
||||
if (variableOrRule in css_beautify.NESTED_AT_RULE) {
|
||||
nestedLevel += 1;
|
||||
if (variableOrRule in css_beautify.CONDITIONAL_GROUP_RULE) {
|
||||
enteringConditionalGroup = true;
|
||||
}
|
||||
} else if (': '.indexOf(variableOrRule[variableOrRule.length -1]) >= 0) {
|
||||
//we have a variable, add it and insert one space before continuing
|
||||
next();
|
||||
variableOrRule = eatString(": ").replace(/\s$/, '');
|
||||
output.push(variableOrRule);
|
||||
print.singleSpace();
|
||||
}
|
||||
} else if (ch === '{') {
|
||||
if (peek(true) === '}') {
|
||||
eatWhitespace();
|
||||
next();
|
||||
print.singleSpace();
|
||||
output.push("{}");
|
||||
} else {
|
||||
indent();
|
||||
print["{"](ch);
|
||||
// when entering conditional groups, only rulesets are allowed
|
||||
if (enteringConditionalGroup) {
|
||||
enteringConditionalGroup = false;
|
||||
insideRule = (indentLevel > nestedLevel);
|
||||
} else {
|
||||
// otherwise, declarations are also allowed
|
||||
insideRule = (indentLevel >= nestedLevel);
|
||||
}
|
||||
}
|
||||
} else if (ch === '}') {
|
||||
outdent();
|
||||
print["}"](ch);
|
||||
insideRule = false;
|
||||
if (nestedLevel) {
|
||||
nestedLevel--;
|
||||
}
|
||||
} else if (ch === ":") {
|
||||
eatWhitespace();
|
||||
if ((insideRule || enteringConditionalGroup) &&
|
||||
!(lookBack("&") || foundNestedPseudoClass())) {
|
||||
// 'property: value' delimiter
|
||||
// which could be in a conditional group query
|
||||
output.push(':');
|
||||
print.singleSpace();
|
||||
} else {
|
||||
// sass/less parent reference don't use a space
|
||||
// sass nested pseudo-class don't use a space
|
||||
if (peek() === ":") {
|
||||
// pseudo-element
|
||||
next();
|
||||
output.push("::");
|
||||
} else {
|
||||
// pseudo-class
|
||||
output.push(':');
|
||||
}
|
||||
}
|
||||
} else if (ch === '"' || ch === '\'') {
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
output.push(eatString(ch));
|
||||
} else if (ch === ';') {
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
} else if (ch === '(') { // may be a url
|
||||
if (lookBack("url")) {
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
if (next()) {
|
||||
if (ch !== ')' && ch !== '"' && ch !== '\'') {
|
||||
output.push(eatString(')'));
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
}
|
||||
} else if (ch === ')') {
|
||||
output.push(ch);
|
||||
} else if (ch === ',') {
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
if (!insideRule && selectorSeparatorNewline) {
|
||||
print.newLine();
|
||||
} else {
|
||||
print.singleSpace();
|
||||
}
|
||||
} else if (ch === ']') {
|
||||
output.push(ch);
|
||||
} else if (ch === '[') {
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
output.push(ch);
|
||||
} else if (ch === '=') { // no whitespace before or after
|
||||
eatWhitespace();
|
||||
output.push(ch);
|
||||
} else {
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
|
||||
output.push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var sweetCode = output.join('').replace(/[\r\n\t ]+$/, '');
|
||||
|
||||
// establish end_with_newline
|
||||
if (end_with_newline) {
|
||||
sweetCode += "\n";
|
||||
}
|
||||
|
||||
return sweetCode;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
||||
css_beautify.NESTED_AT_RULE = {
|
||||
"@page": true,
|
||||
"@font-face": true,
|
||||
"@keyframes": true,
|
||||
// also in CONDITIONAL_GROUP_RULE below
|
||||
"@media": true,
|
||||
"@supports": true,
|
||||
"@document": true
|
||||
};
|
||||
css_beautify.CONDITIONAL_GROUP_RULE = {
|
||||
"@media": true,
|
||||
"@supports": true,
|
||||
"@document": true
|
||||
};
|
||||
|
||||
/*global define */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return {
|
||||
css_beautify: css_beautify
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
exports.css_beautify = css_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.css_beautify = css_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.css_beautify = css_beautify;
|
||||
}
|
||||
|
||||
}());
|
||||
@@ -0,0 +1,880 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
Style HTML
|
||||
---------------
|
||||
|
||||
Written by Nochum Sossonko, (nsossonko@hotmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
|
||||
Usage:
|
||||
style_html(html_source);
|
||||
|
||||
style_html(html_source, options);
|
||||
|
||||
The options are:
|
||||
indent_inner_html (default false) — indent <head> and <body> sections,
|
||||
indent_size (default 4) — indentation size,
|
||||
indent_char (default space) — character to indent with,
|
||||
wrap_line_length (default 250) - maximum amount of characters per line (0 = disable)
|
||||
brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none"
|
||||
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are.
|
||||
unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
|
||||
indent_scripts (default normal) - "keep"|"separate"|"normal"
|
||||
preserve_newlines (default true) - whether existing line breaks before elements should be preserved
|
||||
Only works before elements, not inside tags or for text.
|
||||
max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk
|
||||
indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}}
|
||||
end_with_newline (false) - end with a newline
|
||||
|
||||
|
||||
e.g.
|
||||
|
||||
style_html(html_source, {
|
||||
'indent_inner_html': false,
|
||||
'indent_size': 2,
|
||||
'indent_char': ' ',
|
||||
'wrap_line_length': 78,
|
||||
'brace_style': 'expand',
|
||||
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'],
|
||||
'preserve_newlines': true,
|
||||
'max_preserve_newlines': 5,
|
||||
'indent_handlebars': false
|
||||
});
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
function trim(s) {
|
||||
return s.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
function ltrim(s) {
|
||||
return s.replace(/^\s+/g, '');
|
||||
}
|
||||
|
||||
function rtrim(s) {
|
||||
return s.replace(/\s+$/g,'');
|
||||
}
|
||||
|
||||
function style_html(html_source, options, js_beautify, css_beautify) {
|
||||
//Wrapper function to invoke all the necessary constructors and deal with the output.
|
||||
|
||||
var multi_parser,
|
||||
indent_inner_html,
|
||||
indent_size,
|
||||
indent_character,
|
||||
wrap_line_length,
|
||||
brace_style,
|
||||
unformatted,
|
||||
preserve_newlines,
|
||||
max_preserve_newlines,
|
||||
indent_handlebars,
|
||||
end_with_newline;
|
||||
|
||||
options = options || {};
|
||||
|
||||
// backwards compatibility to 1.3.4
|
||||
if ((options.wrap_line_length === undefined || parseInt(options.wrap_line_length, 10) === 0) &&
|
||||
(options.max_char !== undefined && parseInt(options.max_char, 10) !== 0)) {
|
||||
options.wrap_line_length = options.max_char;
|
||||
}
|
||||
|
||||
indent_inner_html = (options.indent_inner_html === undefined) ? false : options.indent_inner_html;
|
||||
indent_size = (options.indent_size === undefined) ? 4 : parseInt(options.indent_size, 10);
|
||||
indent_character = (options.indent_char === undefined) ? ' ' : options.indent_char;
|
||||
brace_style = (options.brace_style === undefined) ? 'collapse' : options.brace_style;
|
||||
wrap_line_length = parseInt(options.wrap_line_length, 10) === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10);
|
||||
unformatted = options.unformatted || ['a', 'span', 'img', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
||||
preserve_newlines = (options.preserve_newlines === undefined) ? true : options.preserve_newlines;
|
||||
max_preserve_newlines = preserve_newlines ?
|
||||
(isNaN(parseInt(options.max_preserve_newlines, 10)) ? 32786 : parseInt(options.max_preserve_newlines, 10))
|
||||
: 0;
|
||||
indent_handlebars = (options.indent_handlebars === undefined) ? false : options.indent_handlebars;
|
||||
end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
|
||||
|
||||
function Parser() {
|
||||
|
||||
this.pos = 0; //Parser position
|
||||
this.token = '';
|
||||
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
|
||||
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
|
||||
parent: 'parent1',
|
||||
parentcount: 1,
|
||||
parent1: ''
|
||||
};
|
||||
this.tag_type = '';
|
||||
this.token_text = this.last_token = this.last_text = this.token_type = '';
|
||||
this.newlines = 0;
|
||||
this.indent_content = indent_inner_html;
|
||||
|
||||
this.Utils = { //Uilities made available to the various functions
|
||||
whitespace: "\n\r\t ".split(''),
|
||||
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML
|
||||
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
|
||||
in_array: function(what, arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (what === arr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Return true iff the given text is composed entirely of
|
||||
// whitespace.
|
||||
this.is_whitespace = function(text) {
|
||||
for (var n = 0; n < text.length; text++) {
|
||||
if (!this.Utils.in_array(text.charAt(n), this.Utils.whitespace)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
this.traverse_whitespace = function() {
|
||||
var input_char = '';
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
this.newlines = 0;
|
||||
while (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
if (preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) {
|
||||
this.newlines += 1;
|
||||
}
|
||||
|
||||
this.pos++;
|
||||
input_char = this.input.charAt(this.pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Append a space to the given content (string array) or, if we are
|
||||
// at the wrap_line_length, append a newline/indentation.
|
||||
this.space_or_wrap = function(content) {
|
||||
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached
|
||||
this.print_newline(false, content);
|
||||
this.print_indentation(content);
|
||||
} else {
|
||||
this.line_char_count++;
|
||||
content.push(' ');
|
||||
}
|
||||
};
|
||||
|
||||
this.get_content = function() { //function to capture regular content between tags
|
||||
var input_char = '',
|
||||
content = [],
|
||||
space = false; //if a space is needed
|
||||
|
||||
while (this.input.charAt(this.pos) !== '<') {
|
||||
if (this.pos >= this.input.length) {
|
||||
return content.length ? content.join('') : ['', 'TK_EOF'];
|
||||
}
|
||||
|
||||
if (this.traverse_whitespace()) {
|
||||
this.space_or_wrap(content);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indent_handlebars) {
|
||||
// Handlebars parsing is complicated.
|
||||
// {{#foo}} and {{/foo}} are formatted tags.
|
||||
// {{something}} should get treated as content, except:
|
||||
// {{else}} specifically behaves like {{#if}} and {{/if}}
|
||||
var peek3 = this.input.substr(this.pos, 3);
|
||||
if (peek3 === '{{#' || peek3 === '{{/') {
|
||||
// These are tags and not content.
|
||||
break;
|
||||
} else if (this.input.substr(this.pos, 2) === '{{') {
|
||||
if (this.get_tag(true) === '{{else}}') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
this.line_char_count++;
|
||||
content.push(input_char); //letter at-a-time (or string) inserted to an array
|
||||
}
|
||||
return content.length ? content.join('') : '';
|
||||
};
|
||||
|
||||
this.get_contents_to = function(name) { //get the full content of a script or style to pass to js_beautify
|
||||
if (this.pos === this.input.length) {
|
||||
return ['', 'TK_EOF'];
|
||||
}
|
||||
var input_char = '';
|
||||
var content = '';
|
||||
var reg_match = new RegExp('</' + name + '\\s*>', 'igm');
|
||||
reg_match.lastIndex = this.pos;
|
||||
var reg_array = reg_match.exec(this.input);
|
||||
var end_script = reg_array ? reg_array.index : this.input.length; //absolute end of script
|
||||
if (this.pos < end_script) { //get everything in between the script tags
|
||||
content = this.input.substring(this.pos, end_script);
|
||||
this.pos = end_script;
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
this.record_tag = function(tag) { //function to record a tag and its parent in this.tags Object
|
||||
if (this.tags[tag + 'count']) { //check for the existence of this tag type
|
||||
this.tags[tag + 'count']++;
|
||||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
||||
} else { //otherwise initialize this tag type
|
||||
this.tags[tag + 'count'] = 1;
|
||||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
||||
}
|
||||
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
|
||||
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
|
||||
};
|
||||
|
||||
this.retrieve_tag = function(tag) { //function to retrieve the opening tag to the corresponding closer
|
||||
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
|
||||
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
|
||||
while (temp_parent) { //till we reach '' (the initial value);
|
||||
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
|
||||
break;
|
||||
}
|
||||
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
|
||||
}
|
||||
if (temp_parent) { //if we caught something
|
||||
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
|
||||
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
|
||||
}
|
||||
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
|
||||
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
|
||||
if (this.tags[tag + 'count'] === 1) {
|
||||
delete this.tags[tag + 'count'];
|
||||
} else {
|
||||
this.tags[tag + 'count']--;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.indent_to_tag = function(tag) {
|
||||
// Match the indentation level to the last use of this tag, but don't remove it.
|
||||
if (!this.tags[tag + 'count']) {
|
||||
return;
|
||||
}
|
||||
var temp_parent = this.tags.parent;
|
||||
while (temp_parent) {
|
||||
if (tag + this.tags[tag + 'count'] === temp_parent) {
|
||||
break;
|
||||
}
|
||||
temp_parent = this.tags[temp_parent + 'parent'];
|
||||
}
|
||||
if (temp_parent) {
|
||||
this.indent_level = this.tags[tag + this.tags[tag + 'count']];
|
||||
}
|
||||
};
|
||||
|
||||
this.get_tag = function(peek) { //function to get a full tag and parse its type
|
||||
var input_char = '',
|
||||
content = [],
|
||||
comment = '',
|
||||
space = false,
|
||||
tag_start, tag_end,
|
||||
tag_start_char,
|
||||
orig_pos = this.pos,
|
||||
orig_line_char_count = this.line_char_count;
|
||||
|
||||
peek = peek !== undefined ? peek : false;
|
||||
|
||||
do {
|
||||
if (this.pos >= this.input.length) {
|
||||
if (peek) {
|
||||
this.pos = orig_pos;
|
||||
this.line_char_count = orig_line_char_count;
|
||||
}
|
||||
return content.length ? content.join('') : ['', 'TK_EOF'];
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
|
||||
space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input_char === "'" || input_char === '"') {
|
||||
input_char += this.get_unformatted(input_char);
|
||||
space = true;
|
||||
|
||||
}
|
||||
|
||||
if (input_char === '=') { //no space before =
|
||||
space = false;
|
||||
}
|
||||
|
||||
if (content.length && content[content.length - 1] !== '=' && input_char !== '>' && space) {
|
||||
//no space after = or before >
|
||||
this.space_or_wrap(content);
|
||||
space = false;
|
||||
}
|
||||
|
||||
if (indent_handlebars && tag_start_char === '<') {
|
||||
// When inside an angle-bracket tag, put spaces around
|
||||
// handlebars not inside of strings.
|
||||
if ((input_char + this.input.charAt(this.pos)) === '{{') {
|
||||
input_char += this.get_unformatted('}}');
|
||||
if (content.length && content[content.length - 1] !== ' ' && content[content.length - 1] !== '<') {
|
||||
input_char = ' ' + input_char;
|
||||
}
|
||||
space = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_char === '<' && !tag_start_char) {
|
||||
tag_start = this.pos - 1;
|
||||
tag_start_char = '<';
|
||||
}
|
||||
|
||||
if (indent_handlebars && !tag_start_char) {
|
||||
if (content.length >= 2 && content[content.length - 1] === '{' && content[content.length - 2] == '{') {
|
||||
if (input_char === '#' || input_char === '/') {
|
||||
tag_start = this.pos - 3;
|
||||
} else {
|
||||
tag_start = this.pos - 2;
|
||||
}
|
||||
tag_start_char = '{';
|
||||
}
|
||||
}
|
||||
|
||||
this.line_char_count++;
|
||||
content.push(input_char); //inserts character at-a-time (or string)
|
||||
|
||||
if (content[1] && content[1] === '!') { //if we're in a comment, do something special
|
||||
// We treat all comments as literals, even more than preformatted tags
|
||||
// we just look for the appropriate close tag
|
||||
content = [this.get_comment(tag_start)];
|
||||
break;
|
||||
}
|
||||
|
||||
if (indent_handlebars && tag_start_char === '{' && content.length > 2 && content[content.length - 2] === '}' && content[content.length - 1] === '}') {
|
||||
break;
|
||||
}
|
||||
} while (input_char !== '>');
|
||||
|
||||
var tag_complete = content.join('');
|
||||
var tag_index;
|
||||
var tag_offset;
|
||||
|
||||
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends
|
||||
tag_index = tag_complete.indexOf(' ');
|
||||
} else if (tag_complete[0] === '{') {
|
||||
tag_index = tag_complete.indexOf('}');
|
||||
} else { //otherwise go with the tag ending
|
||||
tag_index = tag_complete.indexOf('>');
|
||||
}
|
||||
if (tag_complete[0] === '<' || !indent_handlebars) {
|
||||
tag_offset = 1;
|
||||
} else {
|
||||
tag_offset = tag_complete[2] === '#' ? 3 : 2;
|
||||
}
|
||||
var tag_check = tag_complete.substring(tag_offset, tag_index).toLowerCase();
|
||||
if (tag_complete.charAt(tag_complete.length - 2) === '/' ||
|
||||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
|
||||
if (!peek) {
|
||||
this.tag_type = 'SINGLE';
|
||||
}
|
||||
} else if (indent_handlebars && tag_complete[0] === '{' && tag_check === 'else') {
|
||||
if (!peek) {
|
||||
this.indent_to_tag('if');
|
||||
this.tag_type = 'HANDLEBARS_ELSE';
|
||||
this.indent_content = true;
|
||||
this.traverse_whitespace();
|
||||
}
|
||||
} else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags
|
||||
comment = this.get_unformatted('</' + tag_check + '>', tag_complete); //...delegate to get_unformatted function
|
||||
content.push(comment);
|
||||
tag_end = this.pos - 1;
|
||||
this.tag_type = 'SINGLE';
|
||||
} else if (tag_check === 'script' &&
|
||||
(tag_complete.search('type') === -1 ||
|
||||
(tag_complete.search('type') > -1 &&
|
||||
tag_complete.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript)/) > -1))) {
|
||||
if (!peek) {
|
||||
this.record_tag(tag_check);
|
||||
this.tag_type = 'SCRIPT';
|
||||
}
|
||||
} else if (tag_check === 'style' &&
|
||||
(tag_complete.search('type') === -1 ||
|
||||
(tag_complete.search('type') > -1 && tag_complete.search('text/css') > -1))) {
|
||||
if (!peek) {
|
||||
this.record_tag(tag_check);
|
||||
this.tag_type = 'STYLE';
|
||||
}
|
||||
} else if (tag_check.charAt(0) === '!') { //peek for <! comment
|
||||
// for comments content is already correct.
|
||||
if (!peek) {
|
||||
this.tag_type = 'SINGLE';
|
||||
this.traverse_whitespace();
|
||||
}
|
||||
} else if (!peek) {
|
||||
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
|
||||
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
|
||||
this.tag_type = 'END';
|
||||
} else { //otherwise it's a start-tag
|
||||
this.record_tag(tag_check); //push it on the tag stack
|
||||
if (tag_check.toLowerCase() !== 'html') {
|
||||
this.indent_content = true;
|
||||
}
|
||||
this.tag_type = 'START';
|
||||
}
|
||||
|
||||
// Allow preserving of newlines after a start or end tag
|
||||
if (this.traverse_whitespace()) {
|
||||
this.space_or_wrap(content);
|
||||
}
|
||||
|
||||
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
|
||||
this.print_newline(false, this.output);
|
||||
if (this.output.length && this.output[this.output.length - 2] !== '\n') {
|
||||
this.print_newline(true, this.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (peek) {
|
||||
this.pos = orig_pos;
|
||||
this.line_char_count = orig_line_char_count;
|
||||
}
|
||||
|
||||
return content.join(''); //returns fully formatted tag
|
||||
};
|
||||
|
||||
this.get_comment = function(start_pos) { //function to return comment content in its entirety
|
||||
// this is will have very poor perf, but will work for now.
|
||||
var comment = '',
|
||||
delimiter = '>',
|
||||
matched = false;
|
||||
|
||||
this.pos = start_pos;
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
while (this.pos <= this.input.length) {
|
||||
comment += input_char;
|
||||
|
||||
// only need to check for the delimiter if the last chars match
|
||||
if (comment[comment.length - 1] === delimiter[delimiter.length - 1] &&
|
||||
comment.indexOf(delimiter) !== -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// only need to search for custom delimiter for the first few characters
|
||||
if (!matched && comment.length < 10) {
|
||||
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment
|
||||
delimiter = '<![endif]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment...
|
||||
delimiter = ']]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ...
|
||||
delimiter = ']>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ...
|
||||
delimiter = '-->';
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
return comment;
|
||||
};
|
||||
|
||||
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
|
||||
|
||||
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
|
||||
return '';
|
||||
}
|
||||
var input_char = '';
|
||||
var content = '';
|
||||
var min_index = 0;
|
||||
var space = true;
|
||||
do {
|
||||
|
||||
if (this.pos >= this.input.length) {
|
||||
return content;
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
if (!space) {
|
||||
this.line_char_count--;
|
||||
continue;
|
||||
}
|
||||
if (input_char === '\n' || input_char === '\r') {
|
||||
content += '\n';
|
||||
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
|
||||
for (var i=0; i<this.indent_level; i++) {
|
||||
content += this.indent_string;
|
||||
}
|
||||
space = false; //...and make sure other indentation is erased
|
||||
*/
|
||||
this.line_char_count = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
content += input_char;
|
||||
this.line_char_count++;
|
||||
space = true;
|
||||
|
||||
if (indent_handlebars && input_char === '{' && content.length && content[content.length - 2] === '{') {
|
||||
// Handlebars expressions in strings should also be unformatted.
|
||||
content += this.get_unformatted('}}');
|
||||
// These expressions are opaque. Ignore delimiters found in them.
|
||||
min_index = content.length;
|
||||
}
|
||||
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1);
|
||||
return content;
|
||||
};
|
||||
|
||||
this.get_token = function() { //initial handler for token-retrieval
|
||||
var token;
|
||||
|
||||
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
|
||||
var type = this.last_token.substr(7);
|
||||
token = this.get_contents_to(type);
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
}
|
||||
return [token, 'TK_' + type];
|
||||
}
|
||||
if (this.current_mode === 'CONTENT') {
|
||||
token = this.get_content();
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
} else {
|
||||
return [token, 'TK_CONTENT'];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.current_mode === 'TAG') {
|
||||
token = this.get_tag();
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
} else {
|
||||
var tag_name_type = 'TK_TAG_' + this.tag_type;
|
||||
return [token, tag_name_type];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.get_full_indent = function(level) {
|
||||
level = this.indent_level + level || 0;
|
||||
if (level < 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Array(level + 1).join(this.indent_string);
|
||||
};
|
||||
|
||||
this.is_unformatted = function(tag_check, unformatted) {
|
||||
//is this an HTML5 block-level link?
|
||||
if (!this.Utils.in_array(tag_check, unformatted)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//at this point we have an tag; is its first child something we want to remain
|
||||
//unformatted?
|
||||
var next_tag = this.get_tag(true /* peek. */ );
|
||||
|
||||
// test next_tag to see if it is just html tag (no external content)
|
||||
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);
|
||||
|
||||
// if next_tag comes back but is not an isolated tag, then
|
||||
// let's treat the 'a' tag as having content
|
||||
// and respect the unformatted option
|
||||
if (!tag || this.Utils.in_array(tag, unformatted)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.printer = function(js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions
|
||||
|
||||
this.input = js_source || ''; //gets the input for the Parser
|
||||
this.output = [];
|
||||
this.indent_character = indent_character;
|
||||
this.indent_string = '';
|
||||
this.indent_size = indent_size;
|
||||
this.brace_style = brace_style;
|
||||
this.indent_level = 0;
|
||||
this.wrap_line_length = wrap_line_length;
|
||||
this.line_char_count = 0; //count to see if wrap_line_length was exceeded
|
||||
|
||||
for (var i = 0; i < this.indent_size; i++) {
|
||||
this.indent_string += this.indent_character;
|
||||
}
|
||||
|
||||
this.print_newline = function(force, arr) {
|
||||
this.line_char_count = 0;
|
||||
if (!arr || !arr.length) {
|
||||
return;
|
||||
}
|
||||
if (force || (arr[arr.length - 1] !== '\n')) { //we might want the extra line
|
||||
if ((arr[arr.length - 1] !== '\n')) {
|
||||
arr[arr.length - 1] = rtrim(arr[arr.length - 1]);
|
||||
}
|
||||
arr.push('\n');
|
||||
}
|
||||
};
|
||||
|
||||
this.print_indentation = function(arr) {
|
||||
for (var i = 0; i < this.indent_level; i++) {
|
||||
arr.push(this.indent_string);
|
||||
this.line_char_count += this.indent_string.length;
|
||||
}
|
||||
};
|
||||
|
||||
this.print_token = function(text) {
|
||||
// Avoid printing initial whitespace.
|
||||
if (this.is_whitespace(text) && !this.output.length) {
|
||||
return;
|
||||
}
|
||||
if (text || text !== '') {
|
||||
if (this.output.length && this.output[this.output.length - 1] === '\n') {
|
||||
this.print_indentation(this.output);
|
||||
text = ltrim(text);
|
||||
}
|
||||
}
|
||||
this.print_token_raw(text);
|
||||
};
|
||||
|
||||
this.print_token_raw = function(text) {
|
||||
// If we are going to print newlines, truncate trailing
|
||||
// whitespace, as the newlines will represent the space.
|
||||
if (this.newlines > 0) {
|
||||
text = rtrim(text);
|
||||
}
|
||||
|
||||
if (text && text !== '') {
|
||||
if (text.length > 1 && text[text.length - 1] === '\n') {
|
||||
// unformatted tags can grab newlines as their last character
|
||||
this.output.push(text.slice(0, -1));
|
||||
this.print_newline(false, this.output);
|
||||
} else {
|
||||
this.output.push(text);
|
||||
}
|
||||
}
|
||||
|
||||
for (var n = 0; n < this.newlines; n++) {
|
||||
this.print_newline(n > 0, this.output);
|
||||
}
|
||||
this.newlines = 0;
|
||||
};
|
||||
|
||||
this.indent = function() {
|
||||
this.indent_level++;
|
||||
};
|
||||
|
||||
this.unindent = function() {
|
||||
if (this.indent_level > 0) {
|
||||
this.indent_level--;
|
||||
}
|
||||
};
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
multi_parser = new Parser(); //wrapping functions Parser
|
||||
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values
|
||||
|
||||
while (true) {
|
||||
var t = multi_parser.get_token();
|
||||
multi_parser.token_text = t[0];
|
||||
multi_parser.token_type = t[1];
|
||||
|
||||
if (multi_parser.token_type === 'TK_EOF') {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (multi_parser.token_type) {
|
||||
case 'TK_TAG_START':
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
if (multi_parser.indent_content) {
|
||||
multi_parser.indent();
|
||||
multi_parser.indent_content = false;
|
||||
}
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_STYLE':
|
||||
case 'TK_TAG_SCRIPT':
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_END':
|
||||
//Print new line only if the tag has no content and has child
|
||||
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
|
||||
var tag_name = multi_parser.token_text.match(/\w+/)[0];
|
||||
var tag_extracted_from_last_output = null;
|
||||
if (multi_parser.output.length) {
|
||||
tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/(?:<|{{#)\s*(\w+)/);
|
||||
}
|
||||
if (tag_extracted_from_last_output === null ||
|
||||
tag_extracted_from_last_output[1] !== tag_name) {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
}
|
||||
}
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_SINGLE':
|
||||
// Don't add a newline before elements that should remain unformatted.
|
||||
var tag_check = multi_parser.token_text.match(/^\s*<([a-z-]+)/i);
|
||||
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)) {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
}
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_HANDLEBARS_ELSE':
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
if (multi_parser.indent_content) {
|
||||
multi_parser.indent();
|
||||
multi_parser.indent_content = false;
|
||||
}
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_CONTENT':
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'TAG';
|
||||
break;
|
||||
case 'TK_STYLE':
|
||||
case 'TK_SCRIPT':
|
||||
if (multi_parser.token_text !== '') {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
var text = multi_parser.token_text,
|
||||
_beautifier,
|
||||
script_indent_level = 1;
|
||||
if (multi_parser.token_type === 'TK_SCRIPT') {
|
||||
_beautifier = typeof js_beautify === 'function' && js_beautify;
|
||||
} else if (multi_parser.token_type === 'TK_STYLE') {
|
||||
_beautifier = typeof css_beautify === 'function' && css_beautify;
|
||||
}
|
||||
|
||||
if (options.indent_scripts === "keep") {
|
||||
script_indent_level = 0;
|
||||
} else if (options.indent_scripts === "separate") {
|
||||
script_indent_level = -multi_parser.indent_level;
|
||||
}
|
||||
|
||||
var indentation = multi_parser.get_full_indent(script_indent_level);
|
||||
if (_beautifier) {
|
||||
// call the Beautifier if avaliable
|
||||
text = _beautifier(text.replace(/^\s*/, indentation), options);
|
||||
} else {
|
||||
// simply indent the string otherwise
|
||||
var white = text.match(/^\s*/)[0];
|
||||
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
|
||||
var reindent = multi_parser.get_full_indent(script_indent_level - _level);
|
||||
text = text.replace(/^\s*/, indentation)
|
||||
.replace(/\r\n|\r|\n/g, '\n' + reindent)
|
||||
.replace(/\s+$/, '');
|
||||
}
|
||||
if (text) {
|
||||
multi_parser.print_token_raw(text);
|
||||
multi_parser.print_newline(true, multi_parser.output);
|
||||
}
|
||||
}
|
||||
multi_parser.current_mode = 'TAG';
|
||||
break;
|
||||
default:
|
||||
// We should not be getting here but we don't want to drop input on the floor
|
||||
// Just output the text and move on
|
||||
if (multi_parser.token_text !== '') {
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
multi_parser.last_token = multi_parser.token_type;
|
||||
multi_parser.last_text = multi_parser.token_text;
|
||||
}
|
||||
var sweet_code = multi_parser.output.join('').replace(/[\r\n\t ]+$/, '');
|
||||
if (end_with_newline) {
|
||||
sweet_code += '\n';
|
||||
}
|
||||
return sweet_code;
|
||||
}
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define(["require", "./beautify", "./beautify-css"], function(requireamd) {
|
||||
var js_beautify = requireamd("./beautify");
|
||||
var css_beautify = requireamd("./beautify-css");
|
||||
|
||||
return {
|
||||
html_beautify: function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
var js_beautify = require('./beautify.js');
|
||||
var css_beautify = require('./beautify-css.js');
|
||||
|
||||
exports.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
};
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, window.js_beautify, window.css_beautify);
|
||||
};
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, global.js_beautify, global.css_beautify);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,451 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("clike", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit,
|
||||
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
|
||||
dontAlignCalls = parserConfig.dontAlignCalls,
|
||||
keywords = parserConfig.keywords || {},
|
||||
builtin = parserConfig.builtin || {},
|
||||
blockKeywords = parserConfig.blockKeywords || {},
|
||||
atoms = parserConfig.atoms || {},
|
||||
hooks = parserConfig.hooks || {},
|
||||
multiLineStrings = parserConfig.multiLineStrings;
|
||||
var isOperatorChar = /[+\-*&%=<>!?|\/]/;
|
||||
|
||||
var curPunc;
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (hooks[ch]) {
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
curPunc = ch;
|
||||
return null;
|
||||
}
|
||||
if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w\.]/);
|
||||
return "number";
|
||||
}
|
||||
if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
}
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return "operator";
|
||||
}
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
var cur = stream.current();
|
||||
if (keywords.propertyIsEnumerable(cur)) {
|
||||
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
|
||||
return "keyword";
|
||||
}
|
||||
if (builtin.propertyIsEnumerable(cur)) {
|
||||
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
|
||||
return "builtin";
|
||||
}
|
||||
if (atoms.propertyIsEnumerable(cur)) return "atom";
|
||||
return "variable";
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) {end = true; break;}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (end || !(escaped || multiLineStrings))
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
|
||||
function Context(indented, column, type, align, prev) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.align = align;
|
||||
this.prev = prev;
|
||||
}
|
||||
function pushContext(state, col, type) {
|
||||
var indent = state.indented;
|
||||
if (state.context && state.context.type == "statement")
|
||||
indent = state.context.indented;
|
||||
return state.context = new Context(indent, col, type, null, state.context);
|
||||
}
|
||||
function popContext(state) {
|
||||
var t = state.context.type;
|
||||
if (t == ")" || t == "]" || t == "}")
|
||||
state.indented = state.context.indented;
|
||||
return state.context = state.context.prev;
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: null,
|
||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
|
||||
indented: 0,
|
||||
startOfLine: true
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var ctx = state.context;
|
||||
if (stream.sol()) {
|
||||
if (ctx.align == null) ctx.align = false;
|
||||
state.indented = stream.indentation();
|
||||
state.startOfLine = true;
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
curPunc = null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style == "comment" || style == "meta") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
|
||||
else if (curPunc == "{") pushContext(state, stream.column(), "}");
|
||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
||||
else if (curPunc == "}") {
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
if (ctx.type == "}") ctx = popContext(state);
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
}
|
||||
else if (curPunc == ctx.type) popContext(state);
|
||||
else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
|
||||
pushContext(state, stream.column(), "statement");
|
||||
state.startOfLine = false;
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
|
||||
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
|
||||
if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
|
||||
var closing = firstChar == ctx.type;
|
||||
if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
|
||||
else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1);
|
||||
else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
|
||||
else return ctx.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricChars: "{}",
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
lineComment: "//",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function words(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
|
||||
"double static else struct entry switch extern typedef float union for unsigned " +
|
||||
"goto while enum void const signed volatile";
|
||||
|
||||
function cppHook(stream, state) {
|
||||
if (!state.startOfLine) return false;
|
||||
for (;;) {
|
||||
if (stream.skipTo("\\")) {
|
||||
stream.next();
|
||||
if (stream.eol()) {
|
||||
state.tokenize = cppHook;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
}
|
||||
|
||||
function cpp11StringHook(stream, state) {
|
||||
stream.backUp(1);
|
||||
// Raw strings.
|
||||
if (stream.match(/(R|u8R|uR|UR|LR)/)) {
|
||||
var match = stream.match(/"([^\s\\()]{0,16})\(/);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
state.cpp11RawStringDelim = match[1];
|
||||
state.tokenize = tokenRawString;
|
||||
return tokenRawString(stream, state);
|
||||
}
|
||||
// Unicode strings/chars.
|
||||
if (stream.match(/(u8|u|U|L)/)) {
|
||||
if (stream.match(/["']/, /* eat */ false)) {
|
||||
return "string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Ignore this hook.
|
||||
stream.next();
|
||||
return false;
|
||||
}
|
||||
|
||||
// C#-style strings where "" escapes a quote.
|
||||
function tokenAtString(stream, state) {
|
||||
var next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == '"' && !stream.eat('"')) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
// C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
|
||||
// <delim> can be a string up to 16 characters long.
|
||||
function tokenRawString(stream, state) {
|
||||
// Escape characters that have special regex meanings.
|
||||
var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&');
|
||||
var match = stream.match(new RegExp(".*?\\)" + delim + '"'));
|
||||
if (match)
|
||||
state.tokenize = null;
|
||||
else
|
||||
stream.skipToEnd();
|
||||
return "string";
|
||||
}
|
||||
|
||||
function def(mimes, mode) {
|
||||
if (typeof mimes == "string") mimes = [mimes];
|
||||
var words = [];
|
||||
function add(obj) {
|
||||
if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
|
||||
words.push(prop);
|
||||
}
|
||||
add(mode.keywords);
|
||||
add(mode.builtin);
|
||||
add(mode.atoms);
|
||||
if (words.length) {
|
||||
mode.helperType = mimes[0];
|
||||
CodeMirror.registerHelper("hintWords", mimes[0], words);
|
||||
}
|
||||
|
||||
for (var i = 0; i < mimes.length; ++i)
|
||||
CodeMirror.defineMIME(mimes[i], mode);
|
||||
}
|
||||
|
||||
def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords),
|
||||
blockKeywords: words("case do else for if switch while struct"),
|
||||
atoms: words("null"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def(["text/x-c++src", "text/x-c++hdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
|
||||
"static_cast typeid catch operator template typename class friend private " +
|
||||
"this using const_cast inline public throw virtual delete mutable protected " +
|
||||
"wchar_t alignas alignof constexpr decltype nullptr noexcept thread_local final " +
|
||||
"static_assert override"),
|
||||
blockKeywords: words("catch class do else finally for if struct switch try while"),
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"u": cpp11StringHook,
|
||||
"U": cpp11StringHook,
|
||||
"L": cpp11StringHook,
|
||||
"R": cpp11StringHook
|
||||
},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
def("text/x-java", {
|
||||
name: "clike",
|
||||
keywords: words("abstract assert boolean break byte case catch char class const continue default " +
|
||||
"do double else enum extends final finally float for goto if implements import " +
|
||||
"instanceof int interface long native new package private protected public " +
|
||||
"return short static strictfp super switch synchronized this throw throws transient " +
|
||||
"try void volatile while"),
|
||||
blockKeywords: words("catch class do else finally for if switch try while"),
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
},
|
||||
modeProps: {fold: ["brace", "import"]}
|
||||
});
|
||||
def("text/x-csharp", {
|
||||
name: "clike",
|
||||
keywords: words("abstract as base break case catch checked class const continue" +
|
||||
" default delegate do else enum event explicit extern finally fixed for" +
|
||||
" foreach goto if implicit in interface internal is lock namespace new" +
|
||||
" operator out override params private protected public readonly ref return sealed" +
|
||||
" sizeof stackalloc static struct switch this throw try typeof unchecked" +
|
||||
" unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
|
||||
" global group into join let orderby partial remove select set value var yield"),
|
||||
blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
|
||||
builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
|
||||
" Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
|
||||
" UInt64 bool byte char decimal double short int long object" +
|
||||
" sbyte float string ushort uint ulong"),
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"@": function(stream, state) {
|
||||
if (stream.eat('"')) {
|
||||
state.tokenize = tokenAtString;
|
||||
return tokenAtString(stream, state);
|
||||
}
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
}
|
||||
});
|
||||
def("text/x-scala", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
|
||||
/* scala */
|
||||
"abstract case catch class def do else extends false final finally for forSome if " +
|
||||
"implicit import lazy match new null object override package private protected return " +
|
||||
"sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
|
||||
"<% >: # @ " +
|
||||
|
||||
/* package scala */
|
||||
"assert assume require print println printf readLine readBoolean readByte readShort " +
|
||||
"readChar readInt readLong readFloat readDouble " +
|
||||
|
||||
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
|
||||
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
|
||||
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
|
||||
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
|
||||
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
|
||||
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
|
||||
|
||||
|
||||
),
|
||||
multiLineStrings: true,
|
||||
blockKeywords: words("catch class do else finally for forSome if match switch try while"),
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
}
|
||||
});
|
||||
def(["x-shader/x-vertex", "x-shader/x-fragment"], {
|
||||
name: "clike",
|
||||
keywords: words("float int bool void " +
|
||||
"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
|
||||
"mat2 mat3 mat4 " +
|
||||
"sampler1D sampler2D sampler3D samplerCube " +
|
||||
"sampler1DShadow sampler2DShadow" +
|
||||
"const attribute uniform varying " +
|
||||
"break continue discard return " +
|
||||
"for while do if else struct " +
|
||||
"in out inout"),
|
||||
blockKeywords: words("for while do if else struct"),
|
||||
builtin: words("radians degrees sin cos tan asin acos atan " +
|
||||
"pow exp log exp2 sqrt inversesqrt " +
|
||||
"abs sign floor ceil fract mod min max clamp mix step smootstep " +
|
||||
"length distance dot cross normalize ftransform faceforward " +
|
||||
"reflect refract matrixCompMult " +
|
||||
"lessThan lessThanEqual greaterThan greaterThanEqual " +
|
||||
"equal notEqual any all not " +
|
||||
"texture1D texture1DProj texture1DLod texture1DProjLod " +
|
||||
"texture2D texture2DProj texture2DLod texture2DProjLod " +
|
||||
"texture3D texture3DProj texture3DLod texture3DProjLod " +
|
||||
"textureCube textureCubeLod " +
|
||||
"shadow1D shadow2D shadow1DProj shadow2DProj " +
|
||||
"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
|
||||
"dFdx dFdy fwidth " +
|
||||
"noise1 noise2 noise3 noise4"),
|
||||
atoms: words("true false " +
|
||||
"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
|
||||
"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
|
||||
"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
|
||||
"gl_FogCoord " +
|
||||
"gl_Position gl_PointSize gl_ClipVertex " +
|
||||
"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
|
||||
"gl_TexCoord gl_FogFragCoord " +
|
||||
"gl_FragCoord gl_FrontFacing " +
|
||||
"gl_FragColor gl_FragData gl_FragDepth " +
|
||||
"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
|
||||
"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
|
||||
"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
|
||||
"gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
|
||||
"gl_ProjectionMatrixInverseTranspose " +
|
||||
"gl_ModelViewProjectionMatrixInverseTranspose " +
|
||||
"gl_TextureMatrixInverseTranspose " +
|
||||
"gl_NormalScale gl_DepthRange gl_ClipPlane " +
|
||||
"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
|
||||
"gl_FrontLightModelProduct gl_BackLightModelProduct " +
|
||||
"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
|
||||
"gl_FogParameters " +
|
||||
"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
|
||||
"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
|
||||
"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
|
||||
"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
|
||||
"gl_MaxDrawBuffers"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-nesc", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
|
||||
"implementation includes interface module new norace nx_struct nx_union post provides " +
|
||||
"signal task uses abstract extends"),
|
||||
blockKeywords: words("case do else for if switch while struct"),
|
||||
atoms: words("null"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,309 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
border:1px solid #ddd;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
/* Set scrolling behaviour here */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
}
|
||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cm-animate-fat-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
@keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
div.CodeMirror-overwrite div.CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; }
|
||||
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actuall scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
padding-bottom: 30px;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
padding-bottom: 30px;
|
||||
margin-bottom: -32px;
|
||||
display: inline-block;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-wrap .CodeMirror-scroll {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,717 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
|
||||
|
||||
var indentUnit = config.indentUnit,
|
||||
tokenHooks = parserConfig.tokenHooks,
|
||||
mediaTypes = parserConfig.mediaTypes || {},
|
||||
mediaFeatures = parserConfig.mediaFeatures || {},
|
||||
propertyKeywords = parserConfig.propertyKeywords || {},
|
||||
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
|
||||
colorKeywords = parserConfig.colorKeywords || {},
|
||||
valueKeywords = parserConfig.valueKeywords || {},
|
||||
fontProperties = parserConfig.fontProperties || {},
|
||||
allowNested = parserConfig.allowNested;
|
||||
|
||||
var type, override;
|
||||
function ret(style, tp) { type = tp; return style; }
|
||||
|
||||
// Tokenizers
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (tokenHooks[ch]) {
|
||||
var result = tokenHooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == "@") {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("def", stream.current());
|
||||
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
|
||||
return ret(null, "compare");
|
||||
} else if (ch == "\"" || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("atom", "hash");
|
||||
} else if (ch == "!") {
|
||||
stream.match(/^\s*\w*/);
|
||||
return ret("keyword", "important");
|
||||
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
} else if (ch === "-") {
|
||||
if (/[\d.]/.test(stream.peek())) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
} else if (stream.match(/^\w+-/)) {
|
||||
return ret("meta", "meta");
|
||||
}
|
||||
} else if (/[,+>*\/]/.test(ch)) {
|
||||
return ret(null, "select-op");
|
||||
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
|
||||
return ret("qualifier", "qualifier");
|
||||
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
|
||||
return ret(null, ch);
|
||||
} else if (ch == "u" && stream.match("rl(")) {
|
||||
stream.backUp(1);
|
||||
state.tokenize = tokenParenthesized;
|
||||
return ret("property", "word");
|
||||
} else if (/[\w\\\-]/.test(ch)) {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("property", "word");
|
||||
} else {
|
||||
return ret(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped) {
|
||||
if (quote == ")") stream.backUp(1);
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenParenthesized(stream, state) {
|
||||
stream.next(); // Must be '('
|
||||
if (!stream.match(/\s*[\"\')]/, false))
|
||||
state.tokenize = tokenString(")");
|
||||
else
|
||||
state.tokenize = null;
|
||||
return ret(null, "(");
|
||||
}
|
||||
|
||||
// Context management
|
||||
|
||||
function Context(type, indent, prev) {
|
||||
this.type = type;
|
||||
this.indent = indent;
|
||||
this.prev = prev;
|
||||
}
|
||||
|
||||
function pushContext(state, stream, type) {
|
||||
state.context = new Context(type, stream.indentation() + indentUnit, state.context);
|
||||
return type;
|
||||
}
|
||||
|
||||
function popContext(state) {
|
||||
state.context = state.context.prev;
|
||||
return state.context.type;
|
||||
}
|
||||
|
||||
function pass(type, stream, state) {
|
||||
return states[state.context.type](type, stream, state);
|
||||
}
|
||||
function popAndPass(type, stream, state, n) {
|
||||
for (var i = n || 1; i > 0; i--)
|
||||
state.context = state.context.prev;
|
||||
return pass(type, stream, state);
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
function wordAsValue(stream) {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (valueKeywords.hasOwnProperty(word))
|
||||
override = "atom";
|
||||
else if (colorKeywords.hasOwnProperty(word))
|
||||
override = "keyword";
|
||||
else
|
||||
override = "variable";
|
||||
}
|
||||
|
||||
var states = {};
|
||||
|
||||
states.top = function(type, stream, state) {
|
||||
if (type == "{") {
|
||||
return pushContext(state, stream, "block");
|
||||
} else if (type == "}" && state.context.prev) {
|
||||
return popContext(state);
|
||||
} else if (type == "@media") {
|
||||
return pushContext(state, stream, "media");
|
||||
} else if (type == "@font-face") {
|
||||
return "font_face_before";
|
||||
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
|
||||
return "keyframes";
|
||||
} else if (type && type.charAt(0) == "@") {
|
||||
return pushContext(state, stream, "at");
|
||||
} else if (type == "hash") {
|
||||
override = "builtin";
|
||||
} else if (type == "word") {
|
||||
override = "tag";
|
||||
} else if (type == "variable-definition") {
|
||||
return "maybeprop";
|
||||
} else if (type == "interpolation") {
|
||||
return pushContext(state, stream, "interpolation");
|
||||
} else if (type == ":") {
|
||||
return "pseudo";
|
||||
} else if (allowNested && type == "(") {
|
||||
return pushContext(state, stream, "parens");
|
||||
}
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.block = function(type, stream, state) {
|
||||
if (type == "word") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (propertyKeywords.hasOwnProperty(word)) {
|
||||
override = "property";
|
||||
return "maybeprop";
|
||||
} else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
|
||||
override = "string-2";
|
||||
return "maybeprop";
|
||||
} else if (allowNested) {
|
||||
override = stream.match(/^\s*:/, false) ? "property" : "tag";
|
||||
return "block";
|
||||
} else {
|
||||
override += " error";
|
||||
return "maybeprop";
|
||||
}
|
||||
} else if (type == "meta") {
|
||||
return "block";
|
||||
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
|
||||
override = "error";
|
||||
return "block";
|
||||
} else {
|
||||
return states.top(type, stream, state);
|
||||
}
|
||||
};
|
||||
|
||||
states.maybeprop = function(type, stream, state) {
|
||||
if (type == ":") return pushContext(state, stream, "prop");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.prop = function(type, stream, state) {
|
||||
if (type == ";") return popContext(state);
|
||||
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
|
||||
if (type == "}" || type == "{") return popAndPass(type, stream, state);
|
||||
if (type == "(") return pushContext(state, stream, "parens");
|
||||
|
||||
if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
|
||||
override += " error";
|
||||
} else if (type == "word") {
|
||||
wordAsValue(stream);
|
||||
} else if (type == "interpolation") {
|
||||
return pushContext(state, stream, "interpolation");
|
||||
}
|
||||
return "prop";
|
||||
};
|
||||
|
||||
states.propBlock = function(type, _stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "word") { override = "property"; return "maybeprop"; }
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.parens = function(type, stream, state) {
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state);
|
||||
if (type == ")") return popContext(state);
|
||||
if (type == "(") return pushContext(state, stream, "parens");
|
||||
if (type == "word") wordAsValue(stream);
|
||||
return "parens";
|
||||
};
|
||||
|
||||
states.pseudo = function(type, stream, state) {
|
||||
if (type == "word") {
|
||||
override = "variable-3";
|
||||
return state.context.type;
|
||||
}
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.media = function(type, stream, state) {
|
||||
if (type == "(") return pushContext(state, stream, "media_parens");
|
||||
if (type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
|
||||
|
||||
if (type == "word") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (word == "only" || word == "not" || word == "and")
|
||||
override = "keyword";
|
||||
else if (mediaTypes.hasOwnProperty(word))
|
||||
override = "attribute";
|
||||
else if (mediaFeatures.hasOwnProperty(word))
|
||||
override = "property";
|
||||
else
|
||||
override = "error";
|
||||
}
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.media_parens = function(type, stream, state) {
|
||||
if (type == ")") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
|
||||
return states.media(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face_before = function(type, stream, state) {
|
||||
if (type == "{")
|
||||
return pushContext(state, stream, "font_face");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face = function(type, stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "word") {
|
||||
if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
|
||||
override = "error";
|
||||
else
|
||||
override = "property";
|
||||
return "maybeprop";
|
||||
}
|
||||
return "font_face";
|
||||
};
|
||||
|
||||
states.keyframes = function(type, stream, state) {
|
||||
if (type == "word") { override = "variable"; return "keyframes"; }
|
||||
if (type == "{") return pushContext(state, stream, "top");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.at = function(type, stream, state) {
|
||||
if (type == ";") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "word") override = "tag";
|
||||
else if (type == "hash") override = "builtin";
|
||||
return "at";
|
||||
};
|
||||
|
||||
states.interpolation = function(type, stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "{" || type == ";") return popAndPass(type, stream, state);
|
||||
if (type != "variable") override = "error";
|
||||
return "interpolation";
|
||||
};
|
||||
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: null,
|
||||
state: "top",
|
||||
context: new Context("top", base || 0, null)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tokenize && stream.eatSpace()) return null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style && typeof style == "object") {
|
||||
type = style[1];
|
||||
style = style[0];
|
||||
}
|
||||
override = style;
|
||||
state.state = states[state.state](type, stream, state);
|
||||
return override;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var cx = state.context, ch = textAfter && textAfter.charAt(0);
|
||||
var indent = cx.indent;
|
||||
if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
|
||||
if (cx.prev &&
|
||||
(ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
|
||||
ch == ")" && (cx.type == "parens" || cx.type == "media_parens") ||
|
||||
ch == "{" && (cx.type == "at" || cx.type == "media"))) {
|
||||
indent = cx.indent - indentUnit;
|
||||
cx = cx.prev;
|
||||
}
|
||||
return indent;
|
||||
},
|
||||
|
||||
electricChars: "}",
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function keySet(array) {
|
||||
var keys = {};
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
keys[array[i]] = true;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
var mediaTypes_ = [
|
||||
"all", "aural", "braille", "handheld", "print", "projection", "screen",
|
||||
"tty", "tv", "embossed"
|
||||
], mediaTypes = keySet(mediaTypes_);
|
||||
|
||||
var mediaFeatures_ = [
|
||||
"width", "min-width", "max-width", "height", "min-height", "max-height",
|
||||
"device-width", "min-device-width", "max-device-width", "device-height",
|
||||
"min-device-height", "max-device-height", "aspect-ratio",
|
||||
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
|
||||
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
|
||||
"max-color", "color-index", "min-color-index", "max-color-index",
|
||||
"monochrome", "min-monochrome", "max-monochrome", "resolution",
|
||||
"min-resolution", "max-resolution", "scan", "grid"
|
||||
], mediaFeatures = keySet(mediaFeatures_);
|
||||
|
||||
var propertyKeywords_ = [
|
||||
"align-content", "align-items", "align-self", "alignment-adjust",
|
||||
"alignment-baseline", "anchor-point", "animation", "animation-delay",
|
||||
"animation-direction", "animation-duration", "animation-fill-mode",
|
||||
"animation-iteration-count", "animation-name", "animation-play-state",
|
||||
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
|
||||
"background", "background-attachment", "background-clip", "background-color",
|
||||
"background-image", "background-origin", "background-position",
|
||||
"background-repeat", "background-size", "baseline-shift", "binding",
|
||||
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
|
||||
"bookmark-target", "border", "border-bottom", "border-bottom-color",
|
||||
"border-bottom-left-radius", "border-bottom-right-radius",
|
||||
"border-bottom-style", "border-bottom-width", "border-collapse",
|
||||
"border-color", "border-image", "border-image-outset",
|
||||
"border-image-repeat", "border-image-slice", "border-image-source",
|
||||
"border-image-width", "border-left", "border-left-color",
|
||||
"border-left-style", "border-left-width", "border-radius", "border-right",
|
||||
"border-right-color", "border-right-style", "border-right-width",
|
||||
"border-spacing", "border-style", "border-top", "border-top-color",
|
||||
"border-top-left-radius", "border-top-right-radius", "border-top-style",
|
||||
"border-top-width", "border-width", "bottom", "box-decoration-break",
|
||||
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
|
||||
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
|
||||
"column-fill", "column-gap", "column-rule", "column-rule-color",
|
||||
"column-rule-style", "column-rule-width", "column-span", "column-width",
|
||||
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
|
||||
"cue-after", "cue-before", "cursor", "direction", "display",
|
||||
"dominant-baseline", "drop-initial-after-adjust",
|
||||
"drop-initial-after-align", "drop-initial-before-adjust",
|
||||
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
|
||||
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
|
||||
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
|
||||
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
|
||||
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
|
||||
"font-stretch", "font-style", "font-synthesis", "font-variant",
|
||||
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
|
||||
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
|
||||
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
|
||||
"grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
|
||||
"grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
|
||||
"grid-template", "grid-template-areas", "grid-template-columns",
|
||||
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
|
||||
"icon", "image-orientation", "image-rendering", "image-resolution",
|
||||
"inline-box-align", "justify-content", "left", "letter-spacing",
|
||||
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
|
||||
"line-stacking-shift", "line-stacking-strategy", "list-style",
|
||||
"list-style-image", "list-style-position", "list-style-type", "margin",
|
||||
"margin-bottom", "margin-left", "margin-right", "margin-top",
|
||||
"marker-offset", "marks", "marquee-direction", "marquee-loop",
|
||||
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
|
||||
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
|
||||
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
|
||||
"opacity", "order", "orphans", "outline",
|
||||
"outline-color", "outline-offset", "outline-style", "outline-width",
|
||||
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
|
||||
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
|
||||
"page", "page-break-after", "page-break-before", "page-break-inside",
|
||||
"page-policy", "pause", "pause-after", "pause-before", "perspective",
|
||||
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
|
||||
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
|
||||
"region-break-before", "region-break-inside", "region-fragment",
|
||||
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
|
||||
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
|
||||
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
|
||||
"shape-outside", "size", "speak", "speak-as", "speak-header",
|
||||
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
|
||||
"tab-size", "table-layout", "target", "target-name", "target-new",
|
||||
"target-position", "text-align", "text-align-last", "text-decoration",
|
||||
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
|
||||
"text-decoration-style", "text-emphasis", "text-emphasis-color",
|
||||
"text-emphasis-position", "text-emphasis-style", "text-height",
|
||||
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
|
||||
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
|
||||
"text-wrap", "top", "transform", "transform-origin", "transform-style",
|
||||
"transition", "transition-delay", "transition-duration",
|
||||
"transition-property", "transition-timing-function", "unicode-bidi",
|
||||
"vertical-align", "visibility", "voice-balance", "voice-duration",
|
||||
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
|
||||
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
|
||||
"word-spacing", "word-wrap", "z-index",
|
||||
// SVG-specific
|
||||
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
|
||||
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
|
||||
"color-interpolation", "color-interpolation-filters",
|
||||
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
|
||||
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
|
||||
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
|
||||
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
|
||||
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
|
||||
"glyph-orientation-vertical", "text-anchor", "writing-mode"
|
||||
], propertyKeywords = keySet(propertyKeywords_);
|
||||
|
||||
var nonStandardPropertyKeywords_ = [
|
||||
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
|
||||
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
|
||||
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
|
||||
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
|
||||
"searchfield-results-decoration", "zoom"
|
||||
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
|
||||
|
||||
var colorKeywords_ = [
|
||||
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
|
||||
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
|
||||
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
|
||||
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
|
||||
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
|
||||
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
|
||||
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
|
||||
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
|
||||
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
|
||||
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
|
||||
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
|
||||
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
|
||||
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
|
||||
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
|
||||
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
|
||||
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
|
||||
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
|
||||
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
|
||||
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
|
||||
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
|
||||
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
|
||||
"purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
|
||||
"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
|
||||
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
|
||||
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
|
||||
"whitesmoke", "yellow", "yellowgreen"
|
||||
], colorKeywords = keySet(colorKeywords_);
|
||||
|
||||
var valueKeywords_ = [
|
||||
"above", "absolute", "activeborder", "activecaption", "afar",
|
||||
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
|
||||
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
|
||||
"arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
|
||||
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
|
||||
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
|
||||
"both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
|
||||
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
|
||||
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
|
||||
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
|
||||
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
|
||||
"col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
|
||||
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
|
||||
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
|
||||
"decimal-leading-zero", "default", "default-button", "destination-atop",
|
||||
"destination-in", "destination-out", "destination-over", "devanagari",
|
||||
"disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
|
||||
"double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
|
||||
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
|
||||
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
|
||||
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
|
||||
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
|
||||
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
|
||||
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
|
||||
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
|
||||
"ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
|
||||
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
|
||||
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
|
||||
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
|
||||
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
|
||||
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
|
||||
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
|
||||
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
|
||||
"inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
|
||||
"italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
|
||||
"landscape", "lao", "large", "larger", "left", "level", "lighter",
|
||||
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
|
||||
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
|
||||
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
|
||||
"lower-roman", "lowercase", "ltr", "malayalam", "match",
|
||||
"media-controls-background", "media-current-time-display",
|
||||
"media-fullscreen-button", "media-mute-button", "media-play-button",
|
||||
"media-return-to-realtime-button", "media-rewind-button",
|
||||
"media-seek-back-button", "media-seek-forward-button", "media-slider",
|
||||
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
|
||||
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
|
||||
"menu", "menulist", "menulist-button", "menulist-text",
|
||||
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
|
||||
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
|
||||
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
|
||||
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
|
||||
"ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
|
||||
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
|
||||
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
|
||||
"painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
|
||||
"polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
|
||||
"radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
|
||||
"relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
|
||||
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
|
||||
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
|
||||
"searchfield-cancel-button", "searchfield-decoration",
|
||||
"searchfield-results-button", "searchfield-results-decoration",
|
||||
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
|
||||
"single", "skip-white-space", "slide", "slider-horizontal",
|
||||
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
|
||||
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
|
||||
"source-atop", "source-in", "source-out", "source-over", "space", "square",
|
||||
"square-button", "start", "static", "status-bar", "stretch", "stroke",
|
||||
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
|
||||
"table-caption", "table-cell", "table-column", "table-column-group",
|
||||
"table-footer-group", "table-header-group", "table-row", "table-row-group",
|
||||
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
|
||||
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
|
||||
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
|
||||
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
|
||||
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
|
||||
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
|
||||
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
|
||||
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
|
||||
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
|
||||
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
|
||||
"xx-large", "xx-small"
|
||||
], valueKeywords = keySet(valueKeywords_);
|
||||
|
||||
var fontProperties_ = [
|
||||
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
|
||||
"font-stretch", "font-weight", "font-style"
|
||||
], fontProperties = keySet(fontProperties_);
|
||||
|
||||
var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_)
|
||||
.concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
|
||||
CodeMirror.registerHelper("hintWords", "css", allWords);
|
||||
|
||||
function tokenCComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (maybeEnd && ch == "/") {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
function tokenSGMLComment(stream, state) {
|
||||
if (stream.skipTo("-->")) {
|
||||
stream.match("-->");
|
||||
state.tokenize = null;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
CodeMirror.defineMIME("text/css", {
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
tokenHooks: {
|
||||
"<": function(stream, state) {
|
||||
if (!stream.match("!--")) return false;
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
},
|
||||
"/": function(stream, state) {
|
||||
if (!stream.eat("*")) return false;
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
},
|
||||
name: "css"
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-scss", {
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
tokenHooks: {
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ["comment", "comment"];
|
||||
} else if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
} else {
|
||||
return ["operator", "operator"];
|
||||
}
|
||||
},
|
||||
":": function(stream) {
|
||||
if (stream.match(/\s*\{/))
|
||||
return [null, "{"];
|
||||
return false;
|
||||
},
|
||||
"$": function(stream) {
|
||||
stream.match(/^[\w-]+/);
|
||||
if (stream.match(/^\s*:/, false))
|
||||
return ["variable-2", "variable-definition"];
|
||||
return ["variable-2", "variable"];
|
||||
},
|
||||
"#": function(stream) {
|
||||
if (!stream.eat("{")) return false;
|
||||
return [null, "interpolation"];
|
||||
}
|
||||
},
|
||||
name: "css",
|
||||
helperType: "scss"
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-less", {
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
tokenHooks: {
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ["comment", "comment"];
|
||||
} else if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
} else {
|
||||
return ["operator", "operator"];
|
||||
}
|
||||
},
|
||||
"@": function(stream) {
|
||||
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
if (stream.match(/^\s*:/, false))
|
||||
return ["variable-2", "variable-definition"];
|
||||
return ["variable-2", "variable"];
|
||||
},
|
||||
"&": function() {
|
||||
return ["atom", "atom"];
|
||||
}
|
||||
},
|
||||
name: "css",
|
||||
helperType: "less"
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,297 @@
|
||||
// ============== Formatting extensions ============================
|
||||
// A common storage for all mode-specific formatting features
|
||||
if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
|
||||
|
||||
// Returns the extension of the editor's current mode
|
||||
CodeMirror.defineExtension("getModeExt", function () {
|
||||
var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
|
||||
var ext = CodeMirror.modeExtensions[mname];
|
||||
if (!ext) throw new Error("No extensions found for mode " + mname);
|
||||
return ext;
|
||||
});
|
||||
|
||||
// If the current mode is 'htmlmixed', returns the extension of a mode located at
|
||||
// the specified position (can be htmlmixed, css or javascript). Otherwise, simply
|
||||
// returns the extension of the editor's current mode.
|
||||
CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
|
||||
var token = this.getTokenAt(pos);
|
||||
if (token && token.state && token.state.mode)
|
||||
return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
|
||||
else
|
||||
return this.getModeExt();
|
||||
});
|
||||
|
||||
// Comment/uncomment the specified range
|
||||
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
|
||||
var curMode = this.getModeExtAtPos(this.getCursor());
|
||||
if (isComment) { // Comment range
|
||||
var commentedText = this.getRange(from, to);
|
||||
this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
|
||||
, from, to);
|
||||
if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
|
||||
this.setCursor(from.line, from.ch + curMode.commentStart.length);
|
||||
}
|
||||
}
|
||||
else { // Uncomment range
|
||||
var selText = this.getRange(from, to);
|
||||
var startIndex = selText.indexOf(curMode.commentStart);
|
||||
var endIndex = selText.lastIndexOf(curMode.commentEnd);
|
||||
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
|
||||
// Take string till comment start
|
||||
selText = selText.substr(0, startIndex)
|
||||
// From comment start till comment end
|
||||
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
|
||||
// From comment end till string end
|
||||
+ selText.substr(endIndex + curMode.commentEnd.length);
|
||||
}
|
||||
this.replaceRange(selText, from, to);
|
||||
}
|
||||
});
|
||||
|
||||
// Applies automatic mode-aware indentation to the specified range
|
||||
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
|
||||
var cmInstance = this;
|
||||
this.operation(function () {
|
||||
for (var i = from.line; i <= to.line; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic formatting to the specified range
|
||||
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
|
||||
var absStart = this.indexFromPos(from);
|
||||
var absEnd = this.indexFromPos(to);
|
||||
// Insert additional line breaks where necessary according to the
|
||||
// mode's syntax
|
||||
var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
|
||||
var cmInstance = this;
|
||||
|
||||
// Replace and auto-indent the range
|
||||
this.operation(function () {
|
||||
cmInstance.replaceRange(res, from, to);
|
||||
var startLine = cmInstance.posFromIndex(absStart).line;
|
||||
var endLine = cmInstance.posFromIndex(absStart + res.length).line;
|
||||
for (var i = startLine; i <= endLine; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Define extensions for a few modes
|
||||
|
||||
CodeMirror.modeExtensions["css"] = {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
wordWrapChars: [";", "\\{", "\\}"],
|
||||
autoFormatLineBreaks: function (text, startPos, endPos) {
|
||||
text = text.substring(startPos, endPos);
|
||||
return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["javascript"] = {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
wordWrapChars: [";", "\\{", "\\}"],
|
||||
|
||||
getNonBreakableBlocks: function (text) {
|
||||
var nonBreakableRegexes = [
|
||||
new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
|
||||
new RegExp("'([\\s\\S]*?)('|$)"),
|
||||
new RegExp("\"([\\s\\S]*?)(\"|$)"),
|
||||
new RegExp("//.*([\r\n]|$)")
|
||||
];
|
||||
var nonBreakableBlocks = new Array();
|
||||
for (var i = 0; i < nonBreakableRegexes.length; i++) {
|
||||
var curPos = 0;
|
||||
while (curPos < text.length) {
|
||||
var m = text.substr(curPos).match(nonBreakableRegexes[i]);
|
||||
if (m != null) {
|
||||
nonBreakableBlocks.push({
|
||||
start: curPos + m.index,
|
||||
end: curPos + m.index + m[0].length
|
||||
});
|
||||
curPos += m.index + Math.max(1, m[0].length);
|
||||
}
|
||||
else { // No more matches
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
nonBreakableBlocks.sort(function (a, b) {
|
||||
return a.start - b.start;
|
||||
});
|
||||
|
||||
return nonBreakableBlocks;
|
||||
},
|
||||
|
||||
autoFormatLineBreaks: function (text, startPos, endPos) {
|
||||
text = text.substring(startPos, endPos);
|
||||
var curPos = 0;
|
||||
var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
|
||||
var nonBreakableBlocks = this.getNonBreakableBlocks(text);
|
||||
if (nonBreakableBlocks != null) {
|
||||
var res = "";
|
||||
for (var i = 0; i < nonBreakableBlocks.length; i++) {
|
||||
if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
|
||||
res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
|
||||
curPos = nonBreakableBlocks[i].start;
|
||||
}
|
||||
if (nonBreakableBlocks[i].start <= curPos
|
||||
&& nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
|
||||
res += text.substring(curPos, nonBreakableBlocks[i].end);
|
||||
curPos = nonBreakableBlocks[i].end;
|
||||
}
|
||||
}
|
||||
if (curPos < text.length - 1) {
|
||||
res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return text.replace(reLinesSplitter, "$1\n$2");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["xml"] = {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
wordWrapChars: [">"],
|
||||
|
||||
autoFormatLineBreaks: function (text, startPos, endPos) {
|
||||
text = text.substring(startPos, endPos);
|
||||
var lines = text.split("\n");
|
||||
var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
|
||||
var reOpenBrackets = new RegExp("<", "g");
|
||||
var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var mToProcess = lines[i].match(reProcessedPortion);
|
||||
if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
|
||||
lines[i] = mToProcess[1]
|
||||
+ mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
|
||||
+ mToProcess[3];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["htmlmixed"] = {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
wordWrapChars: [">", ";", "\\{", "\\}"],
|
||||
|
||||
getModeInfos: function (text, absPos) {
|
||||
var modeInfos = new Array();
|
||||
modeInfos[0] =
|
||||
{
|
||||
pos: 0,
|
||||
modeExt: CodeMirror.modeExtensions["xml"],
|
||||
modeName: "xml"
|
||||
};
|
||||
|
||||
var modeMatchers = new Array();
|
||||
modeMatchers[0] =
|
||||
{
|
||||
regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
|
||||
modeExt: CodeMirror.modeExtensions["css"],
|
||||
modeName: "css"
|
||||
};
|
||||
modeMatchers[1] =
|
||||
{
|
||||
regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
|
||||
modeExt: CodeMirror.modeExtensions["javascript"],
|
||||
modeName: "javascript"
|
||||
};
|
||||
|
||||
var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
|
||||
// Detect modes for the entire text
|
||||
for (var i = 0; i < modeMatchers.length; i++) {
|
||||
var curPos = 0;
|
||||
while (curPos <= lastCharPos) {
|
||||
var m = text.substr(curPos).match(modeMatchers[i].regex);
|
||||
if (m != null) {
|
||||
if (m.length > 1 && m[1].length > 0) {
|
||||
// Push block begin pos
|
||||
var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
|
||||
modeInfos.push(
|
||||
{
|
||||
pos: blockBegin,
|
||||
modeExt: modeMatchers[i].modeExt,
|
||||
modeName: modeMatchers[i].modeName
|
||||
});
|
||||
// Push block end pos
|
||||
modeInfos.push(
|
||||
{
|
||||
pos: blockBegin + m[1].length,
|
||||
modeExt: modeInfos[0].modeExt,
|
||||
modeName: modeInfos[0].modeName
|
||||
});
|
||||
curPos += m.index + m[0].length;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
curPos += m.index + Math.max(m[0].length, 1);
|
||||
}
|
||||
}
|
||||
else { // No more matches
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort mode infos
|
||||
modeInfos.sort(function sortModeInfo(a, b) {
|
||||
return a.pos - b.pos;
|
||||
});
|
||||
|
||||
return modeInfos;
|
||||
},
|
||||
|
||||
autoFormatLineBreaks: function (text, startPos, endPos) {
|
||||
var modeInfos = this.getModeInfos(text);
|
||||
var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
|
||||
var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
|
||||
var res = "";
|
||||
// Use modes info to break lines correspondingly
|
||||
if (modeInfos.length > 1) { // Deal with multi-mode text
|
||||
for (var i = 1; i <= modeInfos.length; i++) {
|
||||
var selStart = modeInfos[i - 1].pos;
|
||||
var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
|
||||
|
||||
if (selStart >= endPos) { // The block starts later than the needed fragment
|
||||
break;
|
||||
}
|
||||
if (selStart < startPos) {
|
||||
if (selEnd <= startPos) { // The block starts earlier than the needed fragment
|
||||
continue;
|
||||
}
|
||||
selStart = startPos;
|
||||
}
|
||||
if (selEnd > endPos) {
|
||||
selEnd = endPos;
|
||||
}
|
||||
var textPortion = text.substring(selStart, selEnd);
|
||||
if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
|
||||
if (!reBlockStartsWithNewline.test(textPortion)
|
||||
&& selStart > 0) { // The block does not start with a line break
|
||||
textPortion = "\n" + textPortion;
|
||||
}
|
||||
if (!reBlockEndsWithNewline.test(textPortion)
|
||||
&& selEnd < text.length - 1) { // The block does not end with a line break
|
||||
textPortion += "\n";
|
||||
}
|
||||
}
|
||||
res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
|
||||
}
|
||||
}
|
||||
else { // Single-mode text
|
||||
res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
|
||||
if (old == CodeMirror.Init) old = false;
|
||||
if (!old == !val) return;
|
||||
if (val) setFullscreen(cm);
|
||||
else setNormal(cm);
|
||||
});
|
||||
|
||||
function setFullscreen(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = "";
|
||||
wrap.style.height = "auto";
|
||||
wrap.className += " CodeMirror-fullscreen";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
cm.refresh();
|
||||
}
|
||||
|
||||
function setNormal(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
|
||||
document.documentElement.style.overflow = "";
|
||||
var info = cm.state.fullScreenRestore;
|
||||
wrap.style.width = info.width; wrap.style.height = info.height;
|
||||
window.scrollTo(info.scrollLeft, info.scrollTop);
|
||||
cm.refresh();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
var htmlMode = CodeMirror.getMode(config, {name: "xml",
|
||||
htmlMode: true,
|
||||
multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
|
||||
multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
|
||||
var cssMode = CodeMirror.getMode(config, "css");
|
||||
|
||||
var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
|
||||
scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
|
||||
mode: CodeMirror.getMode(config, "javascript")});
|
||||
if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
|
||||
var conf = scriptTypesConf[i];
|
||||
scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
|
||||
}
|
||||
scriptTypes.push({matches: /./,
|
||||
mode: CodeMirror.getMode(config, "text/plain")});
|
||||
|
||||
function html(stream, state) {
|
||||
var tagName = state.htmlState.tagName;
|
||||
if (tagName) tagName = tagName.toLowerCase();
|
||||
var style = htmlMode.token(stream, state.htmlState);
|
||||
if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
// Script block: mode to change to depends on type attribute
|
||||
var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
|
||||
scriptType = scriptType ? scriptType[1] : "";
|
||||
if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
|
||||
for (var i = 0; i < scriptTypes.length; ++i) {
|
||||
var tp = scriptTypes[i];
|
||||
if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
|
||||
if (tp.mode) {
|
||||
state.token = script;
|
||||
state.localMode = tp.mode;
|
||||
state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
state.token = css;
|
||||
state.localMode = cssMode;
|
||||
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function maybeBackup(stream, pat, style) {
|
||||
var cur = stream.current();
|
||||
var close = cur.search(pat), m;
|
||||
if (close > -1) stream.backUp(cur.length - close);
|
||||
else if (m = cur.match(/<\/?$/)) {
|
||||
stream.backUp(cur.length);
|
||||
if (!stream.match(pat, false)) stream.match(cur);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function script(stream, state) {
|
||||
if (stream.match(/^<\/\s*script\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*script\s*>/,
|
||||
state.localMode.token(stream, state.localState));
|
||||
}
|
||||
function css(stream, state) {
|
||||
if (stream.match(/^<\/\s*style\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*style\s*>/,
|
||||
cssMode.token(stream, state.localState));
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
var state = htmlMode.startState();
|
||||
return {token: html, localMode: null, localState: null, htmlState: state};
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
if (state.localState)
|
||||
var local = CodeMirror.copyState(state.localMode, state.localState);
|
||||
return {token: state.token, localMode: state.localMode, localState: local,
|
||||
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
return state.token(stream, state);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (!state.localMode || /^\s*<\//.test(textAfter))
|
||||
return htmlMode.indent(state.htmlState, textAfter);
|
||||
else if (state.localMode.indent)
|
||||
return state.localMode.indent(state.localState, textAfter);
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
},
|
||||
|
||||
innerMode: function(state) {
|
||||
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
|
||||
}
|
||||
};
|
||||
}, "xml", "javascript", "css");
|
||||
|
||||
CodeMirror.defineMIME("text/html", "htmlmixed");
|
||||
|
||||
});
|
||||
@@ -0,0 +1,684 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// TODO actually recognize syntax of TypeScript constructs
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "variable-3"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("interface"),
|
||||
"extends": kw("extends"),
|
||||
"constructor": kw("constructor"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("public"),
|
||||
"private": kw("private"),
|
||||
"protected": kw("protected"),
|
||||
"static": kw("static"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "bool": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
readRegexp(stream);
|
||||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
ret("variable", "variable", word);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) break;
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
if (state.context) {
|
||||
cx.marked = "def";
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), expression, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("form"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("form"), afterImport, poplex);
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") { return pass(quasi, maybeop); }
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type) {
|
||||
if (type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(what, proceed);
|
||||
}
|
||||
if (type == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type) {
|
||||
if (type == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type) {
|
||||
if (isTS && type == ":") return cont(typedef);
|
||||
}
|
||||
function typedef(type) {
|
||||
if (type == "variable"){cx.marked = "variable-3"; return cont();}
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "extends") return cont(expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
|
||||
return cont(functiondef, classBody);
|
||||
}
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
}
|
||||
function classGetterSetter(type) {
|
||||
if (type != "variable") return pass();
|
||||
cx.marked = "property";
|
||||
return cont();
|
||||
}
|
||||
function afterModule(type, value) {
|
||||
if (type == "string") return cont(statement);
|
||||
if (type == "variable") { register(value); return cont(maybeFrom); }
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
return pass(statement);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
return cont();
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(expressionNoComma, maybeArrayComprehension);
|
||||
}
|
||||
function maybeArrayComprehension(type) {
|
||||
if (type == "for") return pass(comprehension, expect("]"));
|
||||
if (type == ",") return cont(commasep(expressionNoComma, "]"));
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function comprehension(type) {
|
||||
if (type == "for") return cont(forspec, comprehension);
|
||||
if (type == "if") return cont(expression, comprehension);
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricChars: ":{}",
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with javascriptobfuscator.com
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (JavascriptObfuscator.detect(some_string)) {
|
||||
// var unpacked = JavascriptObfuscator.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var JavascriptObfuscator = {
|
||||
detect: function (str) {
|
||||
return /^var _0x[a-f0-9]+ ?\= ?\[/.test(str);
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (JavascriptObfuscator.detect(str)) {
|
||||
var matches = /var (_0x[a-f\d]+) ?\= ?\[(.*?)\];/.exec(str);
|
||||
if (matches) {
|
||||
var var_name = matches[1];
|
||||
var strings = JavascriptObfuscator._smart_split(matches[2]);
|
||||
str = str.substring(matches[0].length);
|
||||
for (var k in strings) {
|
||||
str = str.replace(new RegExp(var_name + '\\[' + k + '\\]', 'g'),
|
||||
JavascriptObfuscator._fix_quotes(JavascriptObfuscator._unescape(strings[k])));
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
_fix_quotes: function(str) {
|
||||
var matches = /^"(.*)"$/.exec(str);
|
||||
if (matches) {
|
||||
str = matches[1];
|
||||
str = "'" + str.replace(/'/g, "\\'") + "'";
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
_smart_split: function(str) {
|
||||
var strings = [];
|
||||
var pos = 0;
|
||||
while (pos < str.length) {
|
||||
if (str.charAt(pos) == '"') {
|
||||
// new word
|
||||
var word = '';
|
||||
pos += 1;
|
||||
while (pos < str.length) {
|
||||
if (str.charAt(pos) == '"') {
|
||||
break;
|
||||
}
|
||||
if (str.charAt(pos) == '\\') {
|
||||
word += '\\';
|
||||
pos++;
|
||||
}
|
||||
word += str.charAt(pos);
|
||||
pos++;
|
||||
}
|
||||
strings.push('"' + word + '"');
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return strings;
|
||||
},
|
||||
|
||||
|
||||
_unescape: function (str) {
|
||||
// inefficient if used repeatedly or on small strings, but wonderful on single large chunk of text
|
||||
for (var i = 32; i < 128; i++) {
|
||||
str = str.replace(new RegExp('\\\\x' + i.toString(16), 'ig'), String.fromCharCode(i));
|
||||
}
|
||||
str = str.replace(/\\x09/g, "\t");
|
||||
return str;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
|
||||
t.test_function(JavascriptObfuscator._smart_split, "JavascriptObfuscator._smart_split");
|
||||
t.expect('', []);
|
||||
t.expect('"a", "b"', ['"a"', '"b"']);
|
||||
t.expect('"aaa","bbbb"', ['"aaa"', '"bbbb"']);
|
||||
t.expect('"a", "b\\\""', ['"a"', '"b\\\""']);
|
||||
t.test_function(JavascriptObfuscator._unescape, 'JavascriptObfuscator._unescape');
|
||||
t.expect('\\x40', '@');
|
||||
t.expect('\\x10', '\\x10');
|
||||
t.expect('\\x1', '\\x1');
|
||||
t.expect("\\x61\\x62\\x22\\x63\\x64", 'ab"cd');
|
||||
t.test_function(JavascriptObfuscator.detect, 'JavascriptObfuscator.detect');
|
||||
t.expect('', false);
|
||||
t.expect('abcd', false);
|
||||
t.expect('var _0xaaaa', false);
|
||||
t.expect('var _0xaaaa = ["a", "b"]', true);
|
||||
t.expect('var _0xaaaa=["a", "b"]', true);
|
||||
t.expect('var _0x1234=["a","b"]', true);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with myobfuscate.com
|
||||
// You really don't want to obfuscate your scripts there: they're tracking
|
||||
// your unpackings, your script gets turned into something like this,
|
||||
// as of 2011-04-25:
|
||||
/*
|
||||
|
||||
var _escape = 'your_script_escaped';
|
||||
var _111 = document.createElement('script');
|
||||
_111.src = 'http://api.www.myobfuscate.com/?getsrc=ok' +
|
||||
'&ref=' + encodeURIComponent(document.referrer) +
|
||||
'&url=' + encodeURIComponent(document.URL);
|
||||
var 000 = document.getElementsByTagName('head')[0];
|
||||
000.appendChild(_111);
|
||||
document.write(unescape(_escape));
|
||||
|
||||
*/
|
||||
//
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (MyObfuscate.detect(some_string)) {
|
||||
// var unpacked = MyObfuscate.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var MyObfuscate = {
|
||||
detect: function (str) {
|
||||
if (/^var _?[0O1lI]{3}\=('|\[).*\)\)\);/.test(str)) {
|
||||
return true;
|
||||
}
|
||||
if (/^function _?[0O1lI]{3}\(_/.test(str) && /eval\(/.test(str)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (MyObfuscate.detect(str)) {
|
||||
var __eval = eval;
|
||||
try {
|
||||
eval = function (unpacked) {
|
||||
if (MyObfuscate.starts_with(unpacked, 'var _escape')) {
|
||||
// fetch the urlencoded stuff from the script,
|
||||
var matches = /'([^']*)'/.exec(unpacked);
|
||||
var unescaped = unescape(matches[1]);
|
||||
if (MyObfuscate.starts_with(unescaped, '<script>')) {
|
||||
unescaped = unescaped.substr(8, unescaped.length - 8);
|
||||
}
|
||||
if (MyObfuscate.ends_with(unescaped, '</script>')) {
|
||||
unescaped = unescaped.substr(0, unescaped.length - 9);
|
||||
}
|
||||
unpacked = unescaped;
|
||||
}
|
||||
// throw to terminate the script
|
||||
unpacked = "// Unpacker warning: be careful when using myobfuscate.com for your projects:\n" +
|
||||
"// scripts obfuscated by the free online version may call back home.\n" +
|
||||
"\n//\n" + unpacked;
|
||||
throw unpacked;
|
||||
};
|
||||
__eval(str); // should throw
|
||||
} catch (e) {
|
||||
// well, it failed. we'll just return the original, instead of crashing on user.
|
||||
if (typeof e === "string") {
|
||||
str = e;
|
||||
}
|
||||
}
|
||||
eval = __eval;
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
starts_with: function (str, what) {
|
||||
return str.substr(0, what.length) === what;
|
||||
},
|
||||
|
||||
ends_with: function (str, what) {
|
||||
return str.substr(str.length - what.length, what.length) === what;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// Coincidentally, it can defeat a couple of other eval-based compressors.
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (P_A_C_K_E_R.detect(some_string)) {
|
||||
// var unpacked = P_A_C_K_E_R.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var P_A_C_K_E_R = {
|
||||
detect: function (str) {
|
||||
return (P_A_C_K_E_R.get_chunks(str).length > 0);
|
||||
},
|
||||
|
||||
get_chunks: function(str) {
|
||||
var chunks = str.match(/eval\(\(?function\(.*?(,0,\{\}\)\)|split\('\|'\)\)\))($|\n)/g);
|
||||
return chunks ? chunks : [];
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
var chunks = P_A_C_K_E_R.get_chunks(str),
|
||||
chunk;
|
||||
for(var i = 0; i < chunks.length; i++) {
|
||||
chunk = chunks[i].replace(/\n$/, '');
|
||||
str = str.split(chunk).join( P_A_C_K_E_R.unpack_chunk(chunk) );
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
unpack_chunk: function (str) {
|
||||
var unpacked_source = '';
|
||||
var __eval = eval;
|
||||
if (P_A_C_K_E_R.detect(str)) {
|
||||
try {
|
||||
eval = function (s) { unpacked_source += s; return unpacked_source; };
|
||||
__eval(str);
|
||||
if (typeof unpacked_source == 'string' && unpacked_source) {
|
||||
str = unpacked_source;
|
||||
}
|
||||
} catch (e) {
|
||||
// well, it failed. we'll just return the original, instead of crashing on user.
|
||||
}
|
||||
}
|
||||
eval = __eval;
|
||||
return str;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest(),
|
||||
|
||||
pk1 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))",
|
||||
unpk1 = 'var a=1',
|
||||
pk2 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'foo||b'.split('|'),0,{}))",
|
||||
unpk2 = 'foo b=1',
|
||||
pk_broken = "eval(function(p,a,c,k,e,r){BORKBORK;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))";
|
||||
pk3 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1{}))',3,3,'var||a'.split('|'),0,{}))",
|
||||
unpk3 = 'var a=1{}))',
|
||||
|
||||
t.test_function(P_A_C_K_E_R.detect, "P_A_C_K_E_R.detect");
|
||||
t.expect('', false);
|
||||
t.expect('var a = b', false);
|
||||
t.test_function(P_A_C_K_E_R.unpack, "P_A_C_K_E_R.unpack");
|
||||
t.expect(pk_broken, pk_broken);
|
||||
t.expect(pk1, unpk1);
|
||||
t.expect(pk2, unpk2);
|
||||
t.expect(pk3, unpk3);
|
||||
|
||||
var filler = '\nfiller\n';
|
||||
t.expect(filler + pk1 + "\n" + pk_broken + filler + pk2 + filler, filler + unpk1 + "\n" + pk_broken + filler + unpk2 + filler);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,923 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
|
||||
// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
|
||||
|
||||
(function (mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function (CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("perl", function () {
|
||||
// http://perldoc.perl.org
|
||||
var PERL = { // null - magic touch
|
||||
// 1 - keyword
|
||||
// 2 - def
|
||||
// 3 - atom
|
||||
// 4 - operator
|
||||
// 5 - variable-2 (predefined)
|
||||
// [x,y] - x=1,2,3; y=must be defined if x{...}
|
||||
// PERL operators
|
||||
'->': 4,
|
||||
'++': 4,
|
||||
'--': 4,
|
||||
'**': 4,
|
||||
// ! ~ \ and unary + and -
|
||||
'=~': 4,
|
||||
'!~': 4,
|
||||
'*': 4,
|
||||
'/': 4,
|
||||
'%': 4,
|
||||
'x': 4,
|
||||
'+': 4,
|
||||
'-': 4,
|
||||
'.': 4,
|
||||
'<<': 4,
|
||||
'>>': 4,
|
||||
// named unary operators
|
||||
'<': 4,
|
||||
'>': 4,
|
||||
'<=': 4,
|
||||
'>=': 4,
|
||||
'lt': 4,
|
||||
'gt': 4,
|
||||
'le': 4,
|
||||
'ge': 4,
|
||||
'==': 4,
|
||||
'!=': 4,
|
||||
'<=>': 4,
|
||||
'eq': 4,
|
||||
'ne': 4,
|
||||
'cmp': 4,
|
||||
'~~': 4,
|
||||
'&': 4,
|
||||
'|': 4,
|
||||
'^': 4,
|
||||
'&&': 4,
|
||||
'||': 4,
|
||||
'//': 4,
|
||||
'..': 4,
|
||||
'...': 4,
|
||||
'?': 4,
|
||||
':': 4,
|
||||
'=': 4,
|
||||
'+=': 4,
|
||||
'-=': 4,
|
||||
'*=': 4, // etc. ???
|
||||
',': 4,
|
||||
'=>': 4,
|
||||
'::': 4,
|
||||
// list operators (rightward)
|
||||
'not': 4,
|
||||
'and': 4,
|
||||
'or': 4,
|
||||
'xor': 4,
|
||||
// PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
|
||||
'BEGIN': [5, 1],
|
||||
'END': [5, 1],
|
||||
'PRINT': [5, 1],
|
||||
'PRINTF': [5, 1],
|
||||
'GETC': [5, 1],
|
||||
'READ': [5, 1],
|
||||
'READLINE': [5, 1],
|
||||
'DESTROY': [5, 1],
|
||||
'TIE': [5, 1],
|
||||
'TIEHANDLE': [5, 1],
|
||||
'UNTIE': [5, 1],
|
||||
'STDIN': 5,
|
||||
'STDIN_TOP': 5,
|
||||
'STDOUT': 5,
|
||||
'STDOUT_TOP': 5,
|
||||
'STDERR': 5,
|
||||
'STDERR_TOP': 5,
|
||||
'$ARG': 5,
|
||||
'$_': 5,
|
||||
'@ARG': 5,
|
||||
'@_': 5,
|
||||
'$LIST_SEPARATOR': 5,
|
||||
'$"': 5,
|
||||
'$PROCESS_ID': 5,
|
||||
'$PID': 5,
|
||||
'$$': 5,
|
||||
'$REAL_GROUP_ID': 5,
|
||||
'$GID': 5,
|
||||
'$(': 5,
|
||||
'$EFFECTIVE_GROUP_ID': 5,
|
||||
'$EGID': 5,
|
||||
'$)': 5,
|
||||
'$PROGRAM_NAME': 5,
|
||||
'$0': 5,
|
||||
'$SUBSCRIPT_SEPARATOR': 5,
|
||||
'$SUBSEP': 5,
|
||||
'$;': 5,
|
||||
'$REAL_USER_ID': 5,
|
||||
'$UID': 5,
|
||||
'$<': 5,
|
||||
'$EFFECTIVE_USER_ID': 5,
|
||||
'$EUID': 5,
|
||||
'$>': 5,
|
||||
'$a': 5,
|
||||
'$b': 5,
|
||||
'$COMPILING': 5,
|
||||
'$^C': 5,
|
||||
'$DEBUGGING': 5,
|
||||
'$^D': 5,
|
||||
'${^ENCODING}': 5,
|
||||
'$ENV': 5,
|
||||
'%ENV': 5,
|
||||
'$SYSTEM_FD_MAX': 5,
|
||||
'$^F': 5,
|
||||
'@F': 5,
|
||||
'${^GLOBAL_PHASE}': 5,
|
||||
'$^H': 5,
|
||||
'%^H': 5,
|
||||
'@INC': 5,
|
||||
'%INC': 5,
|
||||
'$INPLACE_EDIT': 5,
|
||||
'$^I': 5,
|
||||
'$^M': 5,
|
||||
'$OSNAME': 5,
|
||||
'$^O': 5,
|
||||
'${^OPEN}': 5,
|
||||
'$PERLDB': 5,
|
||||
'$^P': 5,
|
||||
'$SIG': 5,
|
||||
'%SIG': 5,
|
||||
'$BASETIME': 5,
|
||||
'$^T': 5,
|
||||
'${^TAINT}': 5,
|
||||
'${^UNICODE}': 5,
|
||||
'${^UTF8CACHE}': 5,
|
||||
'${^UTF8LOCALE}': 5,
|
||||
'$PERL_VERSION': 5,
|
||||
'$^V': 5,
|
||||
'${^WIN32_SLOPPY_STAT}': 5,
|
||||
'$EXECUTABLE_NAME': 5,
|
||||
'$^X': 5,
|
||||
'$1': 5, // - regexp $1, $2...
|
||||
'$MATCH': 5,
|
||||
'$&': 5,
|
||||
'${^MATCH}': 5,
|
||||
'$PREMATCH': 5,
|
||||
'$`': 5,
|
||||
'${^PREMATCH}': 5,
|
||||
'$POSTMATCH': 5,
|
||||
"$'": 5,
|
||||
'${^POSTMATCH}': 5,
|
||||
'$LAST_PAREN_MATCH': 5,
|
||||
'$+': 5,
|
||||
'$LAST_SUBMATCH_RESULT': 5,
|
||||
'$^N': 5,
|
||||
'@LAST_MATCH_END': 5,
|
||||
'@+': 5,
|
||||
'%LAST_PAREN_MATCH': 5,
|
||||
'%+': 5,
|
||||
'@LAST_MATCH_START': 5,
|
||||
'@-': 5,
|
||||
'%LAST_MATCH_START': 5,
|
||||
'%-': 5,
|
||||
'$LAST_REGEXP_CODE_RESULT': 5,
|
||||
'$^R': 5,
|
||||
'${^RE_DEBUG_FLAGS}': 5,
|
||||
'${^RE_TRIE_MAXBUF}': 5,
|
||||
'$ARGV': 5,
|
||||
'@ARGV': 5,
|
||||
'ARGV': 5,
|
||||
'ARGVOUT': 5,
|
||||
'$OUTPUT_FIELD_SEPARATOR': 5,
|
||||
'$OFS': 5,
|
||||
'$,': 5,
|
||||
'$INPUT_LINE_NUMBER': 5,
|
||||
'$NR': 5,
|
||||
'$.': 5,
|
||||
'$INPUT_RECORD_SEPARATOR': 5,
|
||||
'$RS': 5,
|
||||
'$/': 5,
|
||||
'$OUTPUT_RECORD_SEPARATOR': 5,
|
||||
'$ORS': 5,
|
||||
'$\\': 5,
|
||||
'$OUTPUT_AUTOFLUSH': 5,
|
||||
'$|': 5,
|
||||
'$ACCUMULATOR': 5,
|
||||
'$^A': 5,
|
||||
'$FORMAT_FORMFEED': 5,
|
||||
'$^L': 5,
|
||||
'$FORMAT_PAGE_NUMBER': 5,
|
||||
'$%': 5,
|
||||
'$FORMAT_LINES_LEFT': 5,
|
||||
'$-': 5,
|
||||
'$FORMAT_LINE_BREAK_CHARACTERS': 5,
|
||||
'$:': 5,
|
||||
'$FORMAT_LINES_PER_PAGE': 5,
|
||||
'$=': 5,
|
||||
'$FORMAT_TOP_NAME': 5,
|
||||
'$^': 5,
|
||||
'$FORMAT_NAME': 5,
|
||||
'$~': 5,
|
||||
'${^CHILD_ERROR_NATIVE}': 5,
|
||||
'$EXTENDED_OS_ERROR': 5,
|
||||
'$^E': 5,
|
||||
'$EXCEPTIONS_BEING_CAUGHT': 5,
|
||||
'$^S': 5,
|
||||
'$WARNING': 5,
|
||||
'$^W': 5,
|
||||
'${^WARNING_BITS}': 5,
|
||||
'$OS_ERROR': 5,
|
||||
'$ERRNO': 5,
|
||||
'$!': 5,
|
||||
'%OS_ERROR': 5,
|
||||
'%ERRNO': 5,
|
||||
'%!': 5,
|
||||
'$CHILD_ERROR': 5,
|
||||
'$?': 5,
|
||||
'$EVAL_ERROR': 5,
|
||||
'$@': 5,
|
||||
'$OFMT': 5,
|
||||
'$#': 5,
|
||||
'$*': 5,
|
||||
'$ARRAY_BASE': 5,
|
||||
'$[': 5,
|
||||
'$OLD_PERL_VERSION': 5,
|
||||
'$]': 5,
|
||||
// PERL blocks
|
||||
'if': [1, 1],
|
||||
elsif: [1, 1],
|
||||
'else': [1, 1],
|
||||
'while': [1, 1],
|
||||
unless: [1, 1],
|
||||
'for': [1, 1],
|
||||
foreach: [1, 1],
|
||||
// PERL functions
|
||||
'abs': 1, // - absolute value function
|
||||
accept: 1, // - accept an incoming socket connect
|
||||
alarm: 1, // - schedule a SIGALRM
|
||||
'atan2': 1, // - arctangent of Y/X in the range -PI to PI
|
||||
bind: 1, // - binds an address to a socket
|
||||
binmode: 1, // - prepare binary files for I/O
|
||||
bless: 1, // - create an object
|
||||
bootstrap: 1, //
|
||||
'break': 1, // - break out of a "given" block
|
||||
caller: 1, // - get context of the current subroutine call
|
||||
chdir: 1, // - change your current working directory
|
||||
chmod: 1, // - changes the permissions on a list of files
|
||||
chomp: 1, // - remove a trailing record separator from a string
|
||||
chop: 1, // - remove the last character from a string
|
||||
chown: 1, // - change the owership on a list of files
|
||||
chr: 1, // - get character this number represents
|
||||
chroot: 1, // - make directory new root for path lookups
|
||||
close: 1, // - close file (or pipe or socket) handle
|
||||
closedir: 1, // - close directory handle
|
||||
connect: 1, // - connect to a remote socket
|
||||
'continue': [1, 1], // - optional trailing block in a while or foreach
|
||||
'cos': 1, // - cosine function
|
||||
crypt: 1, // - one-way passwd-style encryption
|
||||
dbmclose: 1, // - breaks binding on a tied dbm file
|
||||
dbmopen: 1, // - create binding on a tied dbm file
|
||||
'default': 1, //
|
||||
defined: 1, // - test whether a value, variable, or function is defined
|
||||
'delete': 1, // - deletes a value from a hash
|
||||
die: 1, // - raise an exception or bail out
|
||||
'do': 1, // - turn a BLOCK into a TERM
|
||||
dump: 1, // - create an immediate core dump
|
||||
each: 1, // - retrieve the next key/value pair from a hash
|
||||
endgrent: 1, // - be done using group file
|
||||
endhostent: 1, // - be done using hosts file
|
||||
endnetent: 1, // - be done using networks file
|
||||
endprotoent: 1, // - be done using protocols file
|
||||
endpwent: 1, // - be done using passwd file
|
||||
endservent: 1, // - be done using services file
|
||||
eof: 1, // - test a filehandle for its end
|
||||
'eval': 1, // - catch exceptions or compile and run code
|
||||
'exec': 1, // - abandon this program to run another
|
||||
exists: 1, // - test whether a hash key is present
|
||||
exit: 1, // - terminate this program
|
||||
'exp': 1, // - raise I to a power
|
||||
fcntl: 1, // - file control system call
|
||||
fileno: 1, // - return file descriptor from filehandle
|
||||
flock: 1, // - lock an entire file with an advisory lock
|
||||
fork: 1, // - create a new process just like this one
|
||||
format: 1, // - declare a picture format with use by the write() function
|
||||
formline: 1, // - internal function used for formats
|
||||
getc: 1, // - get the next character from the filehandle
|
||||
getgrent: 1, // - get next group record
|
||||
getgrgid: 1, // - get group record given group user ID
|
||||
getgrnam: 1, // - get group record given group name
|
||||
gethostbyaddr: 1, // - get host record given its address
|
||||
gethostbyname: 1, // - get host record given name
|
||||
gethostent: 1, // - get next hosts record
|
||||
getlogin: 1, // - return who logged in at this tty
|
||||
getnetbyaddr: 1, // - get network record given its address
|
||||
getnetbyname: 1, // - get networks record given name
|
||||
getnetent: 1, // - get next networks record
|
||||
getpeername: 1, // - find the other end of a socket connection
|
||||
getpgrp: 1, // - get process group
|
||||
getppid: 1, // - get parent process ID
|
||||
getpriority: 1, // - get current nice value
|
||||
getprotobyname: 1, // - get protocol record given name
|
||||
getprotobynumber: 1, // - get protocol record numeric protocol
|
||||
getprotoent: 1, // - get next protocols record
|
||||
getpwent: 1, // - get next passwd record
|
||||
getpwnam: 1, // - get passwd record given user login name
|
||||
getpwuid: 1, // - get passwd record given user ID
|
||||
getservbyname: 1, // - get services record given its name
|
||||
getservbyport: 1, // - get services record given numeric port
|
||||
getservent: 1, // - get next services record
|
||||
getsockname: 1, // - retrieve the sockaddr for a given socket
|
||||
getsockopt: 1, // - get socket options on a given socket
|
||||
given: 1, //
|
||||
glob: 1, // - expand filenames using wildcards
|
||||
gmtime: 1, // - convert UNIX time into record or string using Greenwich time
|
||||
'goto': 1, // - create spaghetti code
|
||||
grep: 1, // - locate elements in a list test true against a given criterion
|
||||
hex: 1, // - convert a string to a hexadecimal number
|
||||
'import': 1, // - patch a module's namespace into your own
|
||||
index: 1, // - find a substring within a string
|
||||
'int': 1, // - get the integer portion of a number
|
||||
ioctl: 1, // - system-dependent device control system call
|
||||
'join': 1, // - join a list into a string using a separator
|
||||
keys: 1, // - retrieve list of indices from a hash
|
||||
kill: 1, // - send a signal to a process or process group
|
||||
last: 1, // - exit a block prematurely
|
||||
lc: 1, // - return lower-case version of a string
|
||||
lcfirst: 1, // - return a string with just the next letter in lower case
|
||||
length: 1, // - return the number of bytes in a string
|
||||
'link': 1, // - create a hard link in the filesytem
|
||||
listen: 1, // - register your socket as a server
|
||||
local: 2, // - create a temporary value for a global variable (dynamic scoping)
|
||||
localtime: 1, // - convert UNIX time into record or string using local time
|
||||
lock: 1, // - get a thread lock on a variable, subroutine, or method
|
||||
'log': 1, // - retrieve the natural logarithm for a number
|
||||
lstat: 1, // - stat a symbolic link
|
||||
m: null, // - match a string with a regular expression pattern
|
||||
map: 1, // - apply a change to a list to get back a new list with the changes
|
||||
mkdir: 1, // - create a directory
|
||||
msgctl: 1, // - SysV IPC message control operations
|
||||
msgget: 1, // - get SysV IPC message queue
|
||||
msgrcv: 1, // - receive a SysV IPC message from a message queue
|
||||
msgsnd: 1, // - send a SysV IPC message to a message queue
|
||||
my: 2, // - declare and assign a local variable (lexical scoping)
|
||||
'new': 1, //
|
||||
next: 1, // - iterate a block prematurely
|
||||
no: 1, // - unimport some module symbols or semantics at compile time
|
||||
oct: 1, // - convert a string to an octal number
|
||||
open: 1, // - open a file, pipe, or descriptor
|
||||
opendir: 1, // - open a directory
|
||||
ord: 1, // - find a character's numeric representation
|
||||
our: 2, // - declare and assign a package variable (lexical scoping)
|
||||
pack: 1, // - convert a list into a binary representation
|
||||
'package': 1, // - declare a separate global namespace
|
||||
pipe: 1, // - open a pair of connected filehandles
|
||||
pop: 1, // - remove the last element from an array and return it
|
||||
pos: 1, // - find or set the offset for the last/next m//g search
|
||||
print: 1, // - output a list to a filehandle
|
||||
printf: 1, // - output a formatted list to a filehandle
|
||||
prototype: 1, // - get the prototype (if any) of a subroutine
|
||||
push: 1, // - append one or more elements to an array
|
||||
q: null, // - singly quote a string
|
||||
qq: null, // - doubly quote a string
|
||||
qr: null, // - Compile pattern
|
||||
quotemeta: null, // - quote regular expression magic characters
|
||||
qw: null, // - quote a list of words
|
||||
qx: null, // - backquote quote a string
|
||||
rand: 1, // - retrieve the next pseudorandom number
|
||||
read: 1, // - fixed-length buffered input from a filehandle
|
||||
readdir: 1, // - get a directory from a directory handle
|
||||
readline: 1, // - fetch a record from a file
|
||||
readlink: 1, // - determine where a symbolic link is pointing
|
||||
readpipe: 1, // - execute a system command and collect standard output
|
||||
recv: 1, // - receive a message over a Socket
|
||||
redo: 1, // - start this loop iteration over again
|
||||
ref: 1, // - find out the type of thing being referenced
|
||||
rename: 1, // - change a filename
|
||||
require: 1, // - load in external functions from a library at runtime
|
||||
reset: 1, // - clear all variables of a given name
|
||||
'return': 1, // - get out of a function early
|
||||
reverse: 1, // - flip a string or a list
|
||||
rewinddir: 1, // - reset directory handle
|
||||
rindex: 1, // - right-to-left substring search
|
||||
rmdir: 1, // - remove a directory
|
||||
s: null, // - replace a pattern with a string
|
||||
say: 1, // - print with newline
|
||||
scalar: 1, // - force a scalar context
|
||||
seek: 1, // - reposition file pointer for random-access I/O
|
||||
seekdir: 1, // - reposition directory pointer
|
||||
select: 1, // - reset default output or do I/O multiplexing
|
||||
semctl: 1, // - SysV semaphore control operations
|
||||
semget: 1, // - get set of SysV semaphores
|
||||
semop: 1, // - SysV semaphore operations
|
||||
send: 1, // - send a message over a socket
|
||||
setgrent: 1, // - prepare group file for use
|
||||
sethostent: 1, // - prepare hosts file for use
|
||||
setnetent: 1, // - prepare networks file for use
|
||||
setpgrp: 1, // - set the process group of a process
|
||||
setpriority: 1, // - set a process's nice value
|
||||
setprotoent: 1, // - prepare protocols file for use
|
||||
setpwent: 1, // - prepare passwd file for use
|
||||
setservent: 1, // - prepare services file for use
|
||||
setsockopt: 1, // - set some socket options
|
||||
shift: 1, // - remove the first element of an array, and return it
|
||||
shmctl: 1, // - SysV shared memory operations
|
||||
shmget: 1, // - get SysV shared memory segment identifier
|
||||
shmread: 1, // - read SysV shared memory
|
||||
shmwrite: 1, // - write SysV shared memory
|
||||
shutdown: 1, // - close down just half of a socket connection
|
||||
'sin': 1, // - return the sine of a number
|
||||
sleep: 1, // - block for some number of seconds
|
||||
socket: 1, // - create a socket
|
||||
socketpair: 1, // - create a pair of sockets
|
||||
'sort': 1, // - sort a list of values
|
||||
splice: 1, // - add or remove elements anywhere in an array
|
||||
'split': 1, // - split up a string using a regexp delimiter
|
||||
sprintf: 1, // - formatted print into a string
|
||||
'sqrt': 1, // - square root function
|
||||
srand: 1, // - seed the random number generator
|
||||
stat: 1, // - get a file's status information
|
||||
state: 1, // - declare and assign a state variable (persistent lexical scoping)
|
||||
study: 1, // - optimize input data for repeated searches
|
||||
'sub': 1, // - declare a subroutine, possibly anonymously
|
||||
'substr': 1, // - get or alter a portion of a stirng
|
||||
symlink: 1, // - create a symbolic link to a file
|
||||
syscall: 1, // - execute an arbitrary system call
|
||||
sysopen: 1, // - open a file, pipe, or descriptor
|
||||
sysread: 1, // - fixed-length unbuffered input from a filehandle
|
||||
sysseek: 1, // - position I/O pointer on handle used with sysread and syswrite
|
||||
system: 1, // - run a separate program
|
||||
syswrite: 1, // - fixed-length unbuffered output to a filehandle
|
||||
tell: 1, // - get current seekpointer on a filehandle
|
||||
telldir: 1, // - get current seekpointer on a directory handle
|
||||
tie: 1, // - bind a variable to an object class
|
||||
tied: 1, // - get a reference to the object underlying a tied variable
|
||||
time: 1, // - return number of seconds since 1970
|
||||
times: 1, // - return elapsed time for self and child processes
|
||||
tr: null, // - transliterate a string
|
||||
truncate: 1, // - shorten a file
|
||||
uc: 1, // - return upper-case version of a string
|
||||
ucfirst: 1, // - return a string with just the next letter in upper case
|
||||
umask: 1, // - set file creation mode mask
|
||||
undef: 1, // - remove a variable or function definition
|
||||
unlink: 1, // - remove one link to a file
|
||||
unpack: 1, // - convert binary structure into normal perl variables
|
||||
unshift: 1, // - prepend more elements to the beginning of a list
|
||||
untie: 1, // - break a tie binding to a variable
|
||||
use: 1, // - load in a module at compile time
|
||||
utime: 1, // - set a file's last access and modify times
|
||||
values: 1, // - return a list of the values in a hash
|
||||
vec: 1, // - test or set particular bits in a string
|
||||
wait: 1, // - wait for any child process to die
|
||||
waitpid: 1, // - wait for a particular child process to die
|
||||
wantarray: 1, // - get void vs scalar vs list context of current subroutine call
|
||||
warn: 1, // - print debugging info
|
||||
when: 1, //
|
||||
write: 1, // - print a picture record
|
||||
y: null
|
||||
}; // - transliterate a string
|
||||
|
||||
var RXstyle = "string-2";
|
||||
var RXmodifiers = /[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
|
||||
|
||||
function tokenChain(stream, state, chain, style, tail) { // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
|
||||
state.chain = null; // 12 3tail
|
||||
state.style = null;
|
||||
state.tail = null;
|
||||
state.tokenize = function (stream, state) {
|
||||
var e = false, c, i = 0;
|
||||
while (c = stream.next()) {
|
||||
if (c === chain[i] && !e) {
|
||||
if (chain[++i] !== undefined) {
|
||||
state.chain = chain[i];
|
||||
state.style = style;
|
||||
state.tail = tail;
|
||||
}
|
||||
else if (tail)
|
||||
stream.eatWhile(tail);
|
||||
state.tokenize = tokenPerl;
|
||||
return style;
|
||||
}
|
||||
e = !e && c == "\\";
|
||||
}
|
||||
return style;
|
||||
};
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
|
||||
function tokenSOMETHING(stream, state, string) {
|
||||
state.tokenize = function (stream, state) {
|
||||
if (stream.string == string)
|
||||
state.tokenize = tokenPerl;
|
||||
stream.skipToEnd();
|
||||
return "string";
|
||||
};
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
|
||||
function tokenPerl(stream, state) {
|
||||
if (stream.eatSpace())
|
||||
return null;
|
||||
if (state.chain)
|
||||
return tokenChain(stream, state, state.chain, state.style, state.tail);
|
||||
if (stream.match(/^\-?[\d\.]/, false))
|
||||
if (stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
|
||||
return 'number';
|
||||
if (stream.match(/^<<(?=\w)/)) { // NOTE: <<SOMETHING\n...\nSOMETHING\n
|
||||
stream.eatWhile(/\w/);
|
||||
return tokenSOMETHING(stream, state, stream.current().substr(2));
|
||||
}
|
||||
if (stream.sol() && stream.match(/^\=item(?!\w)/)) {// NOTE: \n=item...\n=cut\n
|
||||
return tokenSOMETHING(stream, state, '=cut');
|
||||
}
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") { // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
|
||||
if (prefix(stream, 3) == "<<" + ch) {
|
||||
var p = stream.pos;
|
||||
stream.eatWhile(/\w/);
|
||||
var n = stream.current().substr(1);
|
||||
if (n && stream.eat(ch))
|
||||
return tokenSOMETHING(stream, state, n);
|
||||
stream.pos = p;
|
||||
}
|
||||
return tokenChain(stream, state, [ch], "string");
|
||||
}
|
||||
if (ch == "q") {
|
||||
var c = look(stream, -2);
|
||||
if (!(c && /\w/.test(c))) {
|
||||
c = look(stream, 0);
|
||||
if (c == "x") {
|
||||
c = look(stream, 1);
|
||||
if (c == "(") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [")"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "[") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["]"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "{") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["}"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "<") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [">"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [stream.eat(c)], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
else if (c == "q") {
|
||||
c = look(stream, 1);
|
||||
if (c == "(") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [")"], "string");
|
||||
}
|
||||
if (c == "[") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["]"], "string");
|
||||
}
|
||||
if (c == "{") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["}"], "string");
|
||||
}
|
||||
if (c == "<") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [">"], "string");
|
||||
}
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [stream.eat(c)], "string");
|
||||
}
|
||||
}
|
||||
else if (c == "w") {
|
||||
c = look(stream, 1);
|
||||
if (c == "(") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [")"], "bracket");
|
||||
}
|
||||
if (c == "[") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["]"], "bracket");
|
||||
}
|
||||
if (c == "{") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["}"], "bracket");
|
||||
}
|
||||
if (c == "<") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [">"], "bracket");
|
||||
}
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [stream.eat(c)], "bracket");
|
||||
}
|
||||
}
|
||||
else if (c == "r") {
|
||||
c = look(stream, 1);
|
||||
if (c == "(") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [")"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "[") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["]"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "{") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, ["}"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "<") {
|
||||
eatSuffix(stream, 2);
|
||||
return tokenChain(stream, state, [">"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [stream.eat(c)], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
else if (/[\^'"!~\/(\[{<]/.test(c)) {
|
||||
if (c == "(") {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [")"], "string");
|
||||
}
|
||||
if (c == "[") {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, ["]"], "string");
|
||||
}
|
||||
if (c == "{") {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, ["}"], "string");
|
||||
}
|
||||
if (c == "<") {
|
||||
eatSuffix(stream, 1);
|
||||
return tokenChain(stream, state, [">"], "string");
|
||||
}
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
return tokenChain(stream, state, [stream.eat(c)], "string");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == "m") {
|
||||
var c = look(stream, -2);
|
||||
if (!(c && /\w/.test(c))) {
|
||||
c = stream.eat(/[(\[{<\^'"!~\/]/);
|
||||
if (c) {
|
||||
if (/[\^'"!~\/]/.test(c)) {
|
||||
return tokenChain(stream, state, [c], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "(") {
|
||||
return tokenChain(stream, state, [")"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "[") {
|
||||
return tokenChain(stream, state, ["]"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "{") {
|
||||
return tokenChain(stream, state, ["}"], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (c == "<") {
|
||||
return tokenChain(stream, state, [">"], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == "s") {
|
||||
var c = /[\/>\]})\w]/.test(look(stream, -2));
|
||||
if (!c) {
|
||||
c = stream.eat(/[(\[{<\^'"!~\/]/);
|
||||
if (c) {
|
||||
if (c == "[")
|
||||
return tokenChain(stream, state, ["]", "]"], RXstyle, RXmodifiers);
|
||||
if (c == "{")
|
||||
return tokenChain(stream, state, ["}", "}"], RXstyle, RXmodifiers);
|
||||
if (c == "<")
|
||||
return tokenChain(stream, state, [">", ">"], RXstyle, RXmodifiers);
|
||||
if (c == "(")
|
||||
return tokenChain(stream, state, [")", ")"], RXstyle, RXmodifiers);
|
||||
return tokenChain(stream, state, [c, c], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == "y") {
|
||||
var c = /[\/>\]})\w]/.test(look(stream, -2));
|
||||
if (!c) {
|
||||
c = stream.eat(/[(\[{<\^'"!~\/]/);
|
||||
if (c) {
|
||||
if (c == "[")
|
||||
return tokenChain(stream, state, ["]", "]"], RXstyle, RXmodifiers);
|
||||
if (c == "{")
|
||||
return tokenChain(stream, state, ["}", "}"], RXstyle, RXmodifiers);
|
||||
if (c == "<")
|
||||
return tokenChain(stream, state, [">", ">"], RXstyle, RXmodifiers);
|
||||
if (c == "(")
|
||||
return tokenChain(stream, state, [")", ")"], RXstyle, RXmodifiers);
|
||||
return tokenChain(stream, state, [c, c], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == "t") {
|
||||
var c = /[\/>\]})\w]/.test(look(stream, -2));
|
||||
if (!c) {
|
||||
c = stream.eat("r"); if (c) {
|
||||
c = stream.eat(/[(\[{<\^'"!~\/]/);
|
||||
if (c) {
|
||||
if (c == "[")
|
||||
return tokenChain(stream, state, ["]", "]"], RXstyle, RXmodifiers);
|
||||
if (c == "{")
|
||||
return tokenChain(stream, state, ["}", "}"], RXstyle, RXmodifiers);
|
||||
if (c == "<")
|
||||
return tokenChain(stream, state, [">", ">"], RXstyle, RXmodifiers);
|
||||
if (c == "(")
|
||||
return tokenChain(stream, state, [")", ")"], RXstyle, RXmodifiers);
|
||||
return tokenChain(stream, state, [c, c], RXstyle, RXmodifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch == "`") {
|
||||
return tokenChain(stream, state, [ch], "variable-2");
|
||||
}
|
||||
if (ch == "/") {
|
||||
if (!/~\s*$/.test(prefix(stream)))
|
||||
return "operator";
|
||||
else
|
||||
return tokenChain(stream, state, [ch], RXstyle, RXmodifiers);
|
||||
}
|
||||
if (ch == "$") {
|
||||
var p = stream.pos;
|
||||
if (stream.eatWhile(/\d/) || stream.eat("{") && stream.eatWhile(/\d/) && stream.eat("}"))
|
||||
return "variable-2";
|
||||
else
|
||||
stream.pos = p;
|
||||
}
|
||||
if (/[$@%]/.test(ch)) {
|
||||
var p = stream.pos;
|
||||
if (stream.eat("^") && stream.eat(/[A-Z]/) || !/[@$%&]/.test(look(stream, -2)) && stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)) {
|
||||
var c = stream.current();
|
||||
if (PERL[c])
|
||||
return "variable-2";
|
||||
}
|
||||
stream.pos = p;
|
||||
}
|
||||
if (/[$@%&]/.test(ch)) {
|
||||
if (stream.eatWhile(/[\w$\[\]]/) || stream.eat("{") && stream.eatWhile(/[\w$\[\]]/) && stream.eat("}")) {
|
||||
var c = stream.current();
|
||||
if (PERL[c])
|
||||
return "variable-2";
|
||||
else
|
||||
return "variable";
|
||||
}
|
||||
}
|
||||
if (ch == "#") {
|
||||
if (look(stream, -2) != "$") {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
if (/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)) {
|
||||
var p = stream.pos;
|
||||
stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
|
||||
if (PERL[stream.current()])
|
||||
return "operator";
|
||||
else
|
||||
stream.pos = p;
|
||||
}
|
||||
if (ch == "_") {
|
||||
if (stream.pos == 1) {
|
||||
if (suffix(stream, 6) == "_END__") {
|
||||
return tokenChain(stream, state, ['\0'], "comment");
|
||||
}
|
||||
else if (suffix(stream, 7) == "_DATA__") {
|
||||
return tokenChain(stream, state, ['\0'], "variable-2");
|
||||
}
|
||||
else if (suffix(stream, 7) == "_C__") {
|
||||
return tokenChain(stream, state, ['\0'], "string");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (/\w/.test(ch)) {
|
||||
var p = stream.pos;
|
||||
if (look(stream, -2) == "{" && (look(stream, 0) == "}" || stream.eatWhile(/\w/) && look(stream, 0) == "}"))
|
||||
return "string";
|
||||
else
|
||||
stream.pos = p;
|
||||
}
|
||||
if (/[A-Z]/.test(ch)) {
|
||||
var l = look(stream, -2);
|
||||
var p = stream.pos;
|
||||
stream.eatWhile(/[A-Z_]/);
|
||||
if (/[\da-z]/.test(look(stream, 0))) {
|
||||
stream.pos = p;
|
||||
}
|
||||
else {
|
||||
var c = PERL[stream.current()];
|
||||
if (!c)
|
||||
return "meta";
|
||||
if (c[1])
|
||||
c = c[0];
|
||||
if (l != ":") {
|
||||
if (c == 1)
|
||||
return "keyword";
|
||||
else if (c == 2)
|
||||
return "def";
|
||||
else if (c == 3)
|
||||
return "atom";
|
||||
else if (c == 4)
|
||||
return "operator";
|
||||
else if (c == 5)
|
||||
return "variable-2";
|
||||
else
|
||||
return "meta";
|
||||
}
|
||||
else
|
||||
return "meta";
|
||||
}
|
||||
}
|
||||
if (/[a-zA-Z_]/.test(ch)) {
|
||||
var l = look(stream, -2);
|
||||
stream.eatWhile(/\w/);
|
||||
var c = PERL[stream.current()];
|
||||
if (!c)
|
||||
return "meta";
|
||||
if (c[1])
|
||||
c = c[0];
|
||||
if (l != ":") {
|
||||
if (c == 1)
|
||||
return "keyword";
|
||||
else if (c == 2)
|
||||
return "def";
|
||||
else if (c == 3)
|
||||
return "atom";
|
||||
else if (c == 4)
|
||||
return "operator";
|
||||
else if (c == 5)
|
||||
return "variable-2";
|
||||
else
|
||||
return "meta";
|
||||
}
|
||||
else
|
||||
return "meta";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function () {
|
||||
return {
|
||||
tokenize: tokenPerl,
|
||||
chain: null,
|
||||
style: null,
|
||||
tail: null
|
||||
};
|
||||
},
|
||||
token: function (stream, state) {
|
||||
return (state.tokenize || tokenPerl)(stream, state);
|
||||
},
|
||||
electricChars: "{}"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "perl", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/x-perl", "perl");
|
||||
|
||||
// it's like "peek", but need for look-ahead or look-behind if index < 0
|
||||
function look(stream, c) {
|
||||
return stream.string.charAt(stream.pos + (c || 0));
|
||||
}
|
||||
|
||||
// return a part of prefix of current stream from current position
|
||||
function prefix(stream, c) {
|
||||
if (c) {
|
||||
var x = stream.pos - c;
|
||||
return stream.string.substr((x >= 0 ? x : 0), c);
|
||||
}
|
||||
else {
|
||||
return stream.string.substr(0, stream.pos - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// return a part of suffix of current stream from current position
|
||||
function suffix(stream, c) {
|
||||
var y = stream.string.length;
|
||||
var x = y - stream.pos + 1;
|
||||
return stream.string.substr(stream.pos, (c && c < y ? c : x));
|
||||
}
|
||||
|
||||
// eating and vomiting a part of stream from current position
|
||||
function eatSuffix(stream, c) {
|
||||
var x = stream.pos + c;
|
||||
var y;
|
||||
if (x <= 0)
|
||||
stream.pos = 0;
|
||||
else if (x >= (y = stream.string.length - 1))
|
||||
stream.pos = y;
|
||||
else
|
||||
stream.pos = x;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
clearPlaceholder(cm);
|
||||
var wrapper = cm.getWrapperElement();
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm);
|
||||
});
|
||||
|
||||
function clearPlaceholder(cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
|
||||
cm.state.placeholder = null;
|
||||
}
|
||||
}
|
||||
function setPlaceholder(cm) {
|
||||
clearPlaceholder(cm);
|
||||
var elt = cm.state.placeholder = document.createElement("pre");
|
||||
elt.style.cssText = "height: 0; overflow: visible";
|
||||
elt.className = "CodeMirror-placeholder";
|
||||
elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
function onChange(cm) {
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
function isEmpty(cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,346 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function wordRegexp(words) {
|
||||
return new RegExp("^((" + words.join(")|(") + "))\\b");
|
||||
}
|
||||
|
||||
var wordOperators = wordRegexp(["and", "or", "not", "is"]);
|
||||
var commonKeywords = ["as", "assert", "break", "class", "continue",
|
||||
"def", "del", "elif", "else", "except", "finally",
|
||||
"for", "from", "global", "if", "import",
|
||||
"lambda", "pass", "raise", "return",
|
||||
"try", "while", "with", "yield", "in"];
|
||||
var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr",
|
||||
"classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod",
|
||||
"enumerate", "eval", "filter", "float", "format", "frozenset",
|
||||
"getattr", "globals", "hasattr", "hash", "help", "hex", "id",
|
||||
"input", "int", "isinstance", "issubclass", "iter", "len",
|
||||
"list", "locals", "map", "max", "memoryview", "min", "next",
|
||||
"object", "oct", "open", "ord", "pow", "property", "range",
|
||||
"repr", "reversed", "round", "set", "setattr", "slice",
|
||||
"sorted", "staticmethod", "str", "sum", "super", "tuple",
|
||||
"type", "vars", "zip", "__import__", "NotImplemented",
|
||||
"Ellipsis", "__debug__"];
|
||||
var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execfile",
|
||||
"file", "intern", "long", "raw_input", "reduce", "reload",
|
||||
"unichr", "unicode", "xrange", "False", "True", "None"],
|
||||
keywords: ["exec", "print"]};
|
||||
var py3 = {builtins: ["ascii", "bytes", "exec", "print"],
|
||||
keywords: ["nonlocal", "False", "True", "None"]};
|
||||
|
||||
CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonBuiltins));
|
||||
|
||||
function top(state) {
|
||||
return state.scopes[state.scopes.length - 1];
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("python", function(conf, parserConf) {
|
||||
var ERRORCLASS = "error";
|
||||
|
||||
var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
|
||||
var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]");
|
||||
var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
|
||||
var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
|
||||
var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
|
||||
var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
|
||||
var hangingIndent = parserConf.hangingIndent || conf.indentUnit;
|
||||
|
||||
var myKeywords = commonKeywords, myBuiltins = commonBuiltins;
|
||||
if(parserConf.extra_keywords != undefined){
|
||||
myKeywords = myKeywords.concat(parserConf.extra_keywords);
|
||||
}
|
||||
if(parserConf.extra_builtins != undefined){
|
||||
myBuiltins = myBuiltins.concat(parserConf.extra_builtins);
|
||||
}
|
||||
if (parserConf.version && parseInt(parserConf.version, 10) == 3) {
|
||||
myKeywords = myKeywords.concat(py3.keywords);
|
||||
myBuiltins = myBuiltins.concat(py3.builtins);
|
||||
var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
|
||||
} else {
|
||||
myKeywords = myKeywords.concat(py2.keywords);
|
||||
myBuiltins = myBuiltins.concat(py2.builtins);
|
||||
var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
|
||||
}
|
||||
var keywords = wordRegexp(myKeywords);
|
||||
var builtins = wordRegexp(myBuiltins);
|
||||
|
||||
// tokenizers
|
||||
function tokenBase(stream, state) {
|
||||
// Handle scope changes
|
||||
if (stream.sol() && top(state).type == "py") {
|
||||
var scopeOffset = top(state).offset;
|
||||
if (stream.eatSpace()) {
|
||||
var lineOffset = stream.indentation();
|
||||
if (lineOffset > scopeOffset)
|
||||
pushScope(stream, state, "py");
|
||||
else if (lineOffset < scopeOffset && dedent(stream, state))
|
||||
state.errorToken = true;
|
||||
return null;
|
||||
} else {
|
||||
var style = tokenBaseInner(stream, state);
|
||||
if (scopeOffset > 0 && dedent(stream, state))
|
||||
style += " " + ERRORCLASS;
|
||||
return style;
|
||||
}
|
||||
}
|
||||
return tokenBaseInner(stream, state);
|
||||
}
|
||||
|
||||
function tokenBaseInner(stream, state) {
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
var ch = stream.peek();
|
||||
|
||||
// Handle Comments
|
||||
if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
|
||||
// Handle Number Literals
|
||||
if (stream.match(/^[0-9\.]/, false)) {
|
||||
var floatLiteral = false;
|
||||
// Floats
|
||||
if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
|
||||
if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
|
||||
if (stream.match(/^\.\d+/)) { floatLiteral = true; }
|
||||
if (floatLiteral) {
|
||||
// Float literals may be "imaginary"
|
||||
stream.eat(/J/i);
|
||||
return "number";
|
||||
}
|
||||
// Integers
|
||||
var intLiteral = false;
|
||||
// Hex
|
||||
if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true;
|
||||
// Binary
|
||||
if (stream.match(/^0b[01]+/i)) intLiteral = true;
|
||||
// Octal
|
||||
if (stream.match(/^0o[0-7]+/i)) intLiteral = true;
|
||||
// Decimal
|
||||
if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
|
||||
// Decimal literals may be "imaginary"
|
||||
stream.eat(/J/i);
|
||||
// TODO - Can you have imaginary longs?
|
||||
intLiteral = true;
|
||||
}
|
||||
// Zero by itself with no other piece of number.
|
||||
if (stream.match(/^0(?![\dx])/i)) intLiteral = true;
|
||||
if (intLiteral) {
|
||||
// Integer literals may be "long"
|
||||
stream.eat(/L/i);
|
||||
return "number";
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Strings
|
||||
if (stream.match(stringPrefixes)) {
|
||||
state.tokenize = tokenStringFactory(stream.current());
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
|
||||
// Handle operators and Delimiters
|
||||
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters))
|
||||
return null;
|
||||
|
||||
if (stream.match(doubleOperators)
|
||||
|| stream.match(singleOperators)
|
||||
|| stream.match(wordOperators))
|
||||
return "operator";
|
||||
|
||||
if (stream.match(singleDelimiters))
|
||||
return null;
|
||||
|
||||
if (stream.match(keywords))
|
||||
return "keyword";
|
||||
|
||||
if (stream.match(builtins))
|
||||
return "builtin";
|
||||
|
||||
if (stream.match(/^(self|cls)\b/))
|
||||
return "variable-2";
|
||||
|
||||
if (stream.match(identifiers)) {
|
||||
if (state.lastToken == "def" || state.lastToken == "class")
|
||||
return "def";
|
||||
return "variable";
|
||||
}
|
||||
|
||||
// Handle non-detected items
|
||||
stream.next();
|
||||
return ERRORCLASS;
|
||||
}
|
||||
|
||||
function tokenStringFactory(delimiter) {
|
||||
while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
|
||||
delimiter = delimiter.substr(1);
|
||||
|
||||
var singleline = delimiter.length == 1;
|
||||
var OUTCLASS = "string";
|
||||
|
||||
function tokenString(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
stream.eatWhile(/[^'"\\]/);
|
||||
if (stream.eat("\\")) {
|
||||
stream.next();
|
||||
if (singleline && stream.eol())
|
||||
return OUTCLASS;
|
||||
} else if (stream.match(delimiter)) {
|
||||
state.tokenize = tokenBase;
|
||||
return OUTCLASS;
|
||||
} else {
|
||||
stream.eat(/['"]/);
|
||||
}
|
||||
}
|
||||
if (singleline) {
|
||||
if (parserConf.singleLineStringErrors)
|
||||
return ERRORCLASS;
|
||||
else
|
||||
state.tokenize = tokenBase;
|
||||
}
|
||||
return OUTCLASS;
|
||||
}
|
||||
tokenString.isString = true;
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
function pushScope(stream, state, type) {
|
||||
var offset = 0, align = null;
|
||||
if (type == "py") {
|
||||
while (top(state).type != "py")
|
||||
state.scopes.pop();
|
||||
}
|
||||
offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent);
|
||||
if (type != "py" && !stream.match(/^(\s|#.*)*$/, false))
|
||||
align = stream.column() + 1;
|
||||
state.scopes.push({offset: offset, type: type, align: align});
|
||||
}
|
||||
|
||||
function dedent(stream, state) {
|
||||
var indented = stream.indentation();
|
||||
while (top(state).offset > indented) {
|
||||
if (top(state).type != "py") return true;
|
||||
state.scopes.pop();
|
||||
}
|
||||
return top(state).offset != indented;
|
||||
}
|
||||
|
||||
function tokenLexer(stream, state) {
|
||||
var style = state.tokenize(stream, state);
|
||||
var current = stream.current();
|
||||
|
||||
// Handle '.' connected identifiers
|
||||
if (current == ".") {
|
||||
style = stream.match(identifiers, false) ? null : ERRORCLASS;
|
||||
if (style == null && state.lastStyle == "meta") {
|
||||
// Apply 'meta' style to '.' connected identifiers when
|
||||
// appropriate.
|
||||
style = "meta";
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
// Handle decorators
|
||||
if (current == "@")
|
||||
return stream.match(identifiers, false) ? "meta" : ERRORCLASS;
|
||||
|
||||
if ((style == "variable" || style == "builtin")
|
||||
&& state.lastStyle == "meta")
|
||||
style = "meta";
|
||||
|
||||
// Handle scope changes.
|
||||
if (current == "pass" || current == "return")
|
||||
state.dedent += 1;
|
||||
|
||||
if (current == "lambda") state.lambda = true;
|
||||
if (current == ":" && !state.lambda && top(state).type == "py")
|
||||
pushScope(stream, state, "py");
|
||||
|
||||
var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1;
|
||||
if (delimiter_index != -1)
|
||||
pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
|
||||
|
||||
delimiter_index = "])}".indexOf(current);
|
||||
if (delimiter_index != -1) {
|
||||
if (top(state).type == current) state.scopes.pop();
|
||||
else return ERRORCLASS;
|
||||
}
|
||||
if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
|
||||
if (state.scopes.length > 1) state.scopes.pop();
|
||||
state.dedent -= 1;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
var external = {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: tokenBase,
|
||||
scopes: [{offset: basecolumn || 0, type: "py", align: null}],
|
||||
lastStyle: null,
|
||||
lastToken: null,
|
||||
lambda: false,
|
||||
dedent: 0
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var addErr = state.errorToken;
|
||||
if (addErr) state.errorToken = false;
|
||||
var style = tokenLexer(stream, state);
|
||||
|
||||
state.lastStyle = style;
|
||||
|
||||
var current = stream.current();
|
||||
if (current && style)
|
||||
state.lastToken = current;
|
||||
|
||||
if (stream.eol() && state.lambda)
|
||||
state.lambda = false;
|
||||
return addErr ? style + " " + ERRORCLASS : style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != tokenBase)
|
||||
return state.tokenize.isString ? CodeMirror.Pass : 0;
|
||||
|
||||
var scope = top(state);
|
||||
var closing = textAfter && textAfter.charAt(0) == scope.type;
|
||||
if (scope.align != null)
|
||||
return scope.align - (closing ? 1 : 0);
|
||||
else if (closing && state.scopes.length > 1)
|
||||
return state.scopes[state.scopes.length - 2].offset;
|
||||
else
|
||||
return scope.offset;
|
||||
},
|
||||
|
||||
lineComment: "#",
|
||||
fold: "indent"
|
||||
};
|
||||
return external;
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-python", "python");
|
||||
|
||||
var words = function(str) { return str.split(" "); };
|
||||
|
||||
CodeMirror.defineMIME("text/x-cython", {
|
||||
name: "python",
|
||||
extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
|
||||
"extern gil include nogil property public"+
|
||||
"readonly struct union DEF IF ELIF ELSE")
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,285 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function (mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function (CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("ruby", function (config) {
|
||||
function wordObj(words) {
|
||||
var o = {};
|
||||
for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;
|
||||
return o;
|
||||
}
|
||||
var keywords = wordObj([
|
||||
"alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else",
|
||||
"elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or",
|
||||
"redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
|
||||
"until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
|
||||
"caller", "lambda", "proc", "public", "protected", "private", "require", "load",
|
||||
"require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__"
|
||||
]);
|
||||
var indentWords = wordObj(["def", "class", "case", "for", "while", "module", "then",
|
||||
"catch", "loop", "proc", "begin"]);
|
||||
var dedentWords = wordObj(["end", "until"]);
|
||||
var matching = { "[": "]", "{": "}", "(": ")" };
|
||||
var curPunc;
|
||||
|
||||
function chain(newtok, stream, state) {
|
||||
state.tokenize.push(newtok);
|
||||
return newtok(stream, state);
|
||||
}
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
curPunc = null;
|
||||
if (stream.sol() && stream.match("=begin") && stream.eol()) {
|
||||
state.tokenize.push(readBlockComment);
|
||||
return "comment";
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
var ch = stream.next(), m;
|
||||
if (ch == "`" || ch == "'" || ch == '"') {
|
||||
return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
|
||||
} else if (ch == "/") {
|
||||
var currentIndex = stream.current().length;
|
||||
if (stream.skipTo("/")) {
|
||||
var search_till = stream.current().length;
|
||||
stream.backUp(stream.current().length - currentIndex);
|
||||
var balance = 0; // balance brackets
|
||||
while (stream.current().length < search_till) {
|
||||
var chchr = stream.next();
|
||||
if (chchr == "(") balance += 1;
|
||||
else if (chchr == ")") balance -= 1;
|
||||
if (balance < 0) break;
|
||||
}
|
||||
stream.backUp(stream.current().length - currentIndex);
|
||||
if (balance == 0)
|
||||
return chain(readQuoted(ch, "string-2", true), stream, state);
|
||||
}
|
||||
return "operator";
|
||||
} else if (ch == "%") {
|
||||
var style = "string", embed = true;
|
||||
if (stream.eat("s")) style = "atom";
|
||||
else if (stream.eat(/[WQ]/)) style = "string";
|
||||
else if (stream.eat(/[r]/)) style = "string-2";
|
||||
else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; }
|
||||
var delim = stream.eat(/[^\w\s=]/);
|
||||
if (!delim) return "operator";
|
||||
if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
|
||||
return chain(readQuoted(delim, style, embed, true), stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
} else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
|
||||
return chain(readHereDoc(m[1]), stream, state);
|
||||
} else if (ch == "0") {
|
||||
if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
|
||||
else if (stream.eat("b")) stream.eatWhile(/[01]/);
|
||||
else stream.eatWhile(/[0-7]/);
|
||||
return "number";
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/);
|
||||
return "number";
|
||||
} else if (ch == "?") {
|
||||
while (stream.match(/^\\[CM]-/)) { }
|
||||
if (stream.eat("\\")) stream.eatWhile(/\w/);
|
||||
else stream.next();
|
||||
return "string";
|
||||
} else if (ch == ":") {
|
||||
if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
|
||||
if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
|
||||
|
||||
// :> :>> :< :<< are valid symbols
|
||||
if (stream.eat(/[\<\>]/)) {
|
||||
stream.eat(/[\<\>]/);
|
||||
return "atom";
|
||||
}
|
||||
|
||||
// :+ :- :/ :* :| :& :! are valid symbols
|
||||
if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) {
|
||||
return "atom";
|
||||
}
|
||||
|
||||
// Symbols can't start by a digit
|
||||
if (stream.eat(/[a-zA-Z$@_]/)) {
|
||||
stream.eatWhile(/[\w]/);
|
||||
// Only one ? ! = is allowed and only as the last character
|
||||
stream.eat(/[\?\!\=]/);
|
||||
return "atom";
|
||||
}
|
||||
return "operator";
|
||||
} else if (ch == "@" && stream.match(/^@?[a-zA-Z_]/)) {
|
||||
stream.eat("@");
|
||||
stream.eatWhile(/[\w]/);
|
||||
return "variable-2";
|
||||
} else if (ch == "$") {
|
||||
if (stream.eat(/[a-zA-Z_]/)) {
|
||||
stream.eatWhile(/[\w]/);
|
||||
} else if (stream.eat(/\d/)) {
|
||||
stream.eat(/\d/);
|
||||
} else {
|
||||
stream.next(); // Must be a special global like $: or $!
|
||||
}
|
||||
return "variable-3";
|
||||
} else if (/[a-zA-Z_]/.test(ch)) {
|
||||
stream.eatWhile(/[\w]/);
|
||||
stream.eat(/[\?\!]/);
|
||||
if (stream.eat(":")) return "atom";
|
||||
return "ident";
|
||||
} else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
|
||||
curPunc = "|";
|
||||
return null;
|
||||
} else if (/[\(\)\[\]{}\\;]/.test(ch)) {
|
||||
curPunc = ch;
|
||||
return null;
|
||||
} else if (ch == "-" && stream.eat(">")) {
|
||||
return "arrow";
|
||||
} else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) {
|
||||
var more = stream.eatWhile(/[=+\-\/*:\.^%<>~|]/);
|
||||
if (ch == "." && !more) curPunc = ".";
|
||||
return "operator";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function tokenBaseUntilBrace() {
|
||||
var depth = 1;
|
||||
return function (stream, state) {
|
||||
if (stream.peek() == "}") {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
state.tokenize.pop();
|
||||
return state.tokenize[state.tokenize.length - 1](stream, state);
|
||||
}
|
||||
} else if (stream.peek() == "{") {
|
||||
depth++;
|
||||
}
|
||||
return tokenBase(stream, state);
|
||||
};
|
||||
}
|
||||
function tokenBaseOnce() {
|
||||
var alreadyCalled = false;
|
||||
return function (stream, state) {
|
||||
if (alreadyCalled) {
|
||||
state.tokenize.pop();
|
||||
return state.tokenize[state.tokenize.length - 1](stream, state);
|
||||
}
|
||||
alreadyCalled = true;
|
||||
return tokenBase(stream, state);
|
||||
};
|
||||
}
|
||||
function readQuoted(quote, style, embed, unescaped) {
|
||||
return function (stream, state) {
|
||||
var escaped = false, ch;
|
||||
|
||||
if (state.context.type === 'read-quoted-paused') {
|
||||
state.context = state.context.prev;
|
||||
stream.eat("}");
|
||||
}
|
||||
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && (unescaped || !escaped)) {
|
||||
state.tokenize.pop();
|
||||
break;
|
||||
}
|
||||
if (embed && ch == "#" && !escaped) {
|
||||
if (stream.eat("{")) {
|
||||
if (quote == "}") {
|
||||
state.context = { prev: state.context, type: 'read-quoted-paused' };
|
||||
}
|
||||
state.tokenize.push(tokenBaseUntilBrace());
|
||||
break;
|
||||
} else if (/[@\$]/.test(stream.peek())) {
|
||||
state.tokenize.push(tokenBaseOnce());
|
||||
break;
|
||||
}
|
||||
}
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
function readHereDoc(phrase) {
|
||||
return function (stream, state) {
|
||||
if (stream.match(phrase)) state.tokenize.pop();
|
||||
else stream.skipToEnd();
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
function readBlockComment(stream, state) {
|
||||
if (stream.sol() && stream.match("=end") && stream.eol())
|
||||
state.tokenize.pop();
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function () {
|
||||
return { tokenize: [tokenBase],
|
||||
indented: 0,
|
||||
context: { type: "top", indented: -config.indentUnit },
|
||||
continuedLine: false,
|
||||
lastTok: null,
|
||||
varList: false
|
||||
};
|
||||
},
|
||||
|
||||
token: function (stream, state) {
|
||||
if (stream.sol()) state.indented = stream.indentation();
|
||||
var style = state.tokenize[state.tokenize.length - 1](stream, state), kwtype;
|
||||
var thisTok = curPunc;
|
||||
if (style == "ident") {
|
||||
var word = stream.current();
|
||||
style = state.lastTok == "." ? "property"
|
||||
: keywords.propertyIsEnumerable(stream.current()) ? "keyword"
|
||||
: /^[A-Z]/.test(word) ? "tag"
|
||||
: (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def"
|
||||
: "variable";
|
||||
if (style == "keyword") {
|
||||
thisTok = word;
|
||||
if (indentWords.propertyIsEnumerable(word)) kwtype = "indent";
|
||||
else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent";
|
||||
else if ((word == "if" || word == "unless") && stream.column() == stream.indentation())
|
||||
kwtype = "indent";
|
||||
else if (word == "do" && state.context.indented < state.indented)
|
||||
kwtype = "indent";
|
||||
}
|
||||
}
|
||||
if (curPunc || (style && style != "comment")) state.lastTok = thisTok;
|
||||
if (curPunc == "|") state.varList = !state.varList;
|
||||
|
||||
if (kwtype == "indent" || /[\(\[\{]/.test(curPunc))
|
||||
state.context = { prev: state.context, type: curPunc || style, indented: state.indented };
|
||||
else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev)
|
||||
state.context = state.context.prev;
|
||||
|
||||
if (stream.eol())
|
||||
state.continuedLine = (curPunc == "\\" || style == "operator");
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function (state, textAfter) {
|
||||
if (state.tokenize[state.tokenize.length - 1] != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0);
|
||||
var ct = state.context;
|
||||
var closing = ct.type == matching[firstChar] ||
|
||||
ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter);
|
||||
return ct.indented + (closing ? 0 : config.indentUnit) +
|
||||
(state.continuedLine ? config.indentUnit : 0);
|
||||
},
|
||||
|
||||
electricChars: "}de", // enD and rescuE
|
||||
lineComment: "#"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-ruby", "ruby");
|
||||
|
||||
});
|
||||
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// simple testing interface
|
||||
// written by Einar Lielmanis, einar@jsbeautifier.org
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// var t = new SanityTest(function (x) { return x; }, 'my function');
|
||||
// t.expect('input', 'output');
|
||||
// t.expect('a', 'a');
|
||||
// output_somewhere(t.results()); // good for <pre>, html safe-ish
|
||||
// alert(t.results_raw()); // html unescaped
|
||||
|
||||
|
||||
function SanityTest (func, name_of_test) {
|
||||
|
||||
var test_func = func || function (x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
var test_name = name_of_test || '';
|
||||
|
||||
var n_failed = 0;
|
||||
var n_succeeded = 0;
|
||||
|
||||
var failures = [];
|
||||
|
||||
this.test_function = function(func, name) {
|
||||
test_func = func;
|
||||
test_name = name || '';
|
||||
};
|
||||
|
||||
this.get_exitcode = function() {
|
||||
return n_succeeded === 0 || n_failed !== 0 ? 1 : 0;
|
||||
};
|
||||
|
||||
this.expect = function(parameters, expected_value) {
|
||||
// multi-parameter calls not supported (I don't need them now).
|
||||
var result = test_func(parameters);
|
||||
// proper array checking is a pain. i'll maybe do it later, compare strings representations instead
|
||||
if ((result === expected_value) || (expected_value instanceof Array && result.join(', ') == expected_value.join(', '))) {
|
||||
n_succeeded += 1;
|
||||
} else {
|
||||
n_failed += 1;
|
||||
failures.push([test_name, parameters, expected_value, result]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.results_raw = function() {
|
||||
var results = '';
|
||||
if (n_failed === 0) {
|
||||
if (n_succeeded === 0) {
|
||||
results = 'No tests run.';
|
||||
} else {
|
||||
results = 'All ' + n_succeeded + ' tests passed.';
|
||||
}
|
||||
} else {
|
||||
for (var i = 0 ; i < failures.length; i++) {
|
||||
var f = failures[i];
|
||||
if (f[0]) {
|
||||
f[0] = f[0] + ' ';
|
||||
}
|
||||
results += '---- ' + f[0] + 'input -------\n' + this.prettyprint(f[1]) + '\n';
|
||||
results += '---- ' + f[0] + 'expected ----\n' + this.prettyprint(f[2]) + '\n';
|
||||
results += '---- ' + f[0] + 'output ------\n' + this.prettyprint(f[3]) + '\n\n';
|
||||
|
||||
}
|
||||
results += n_failed + ' tests failed.\n';
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
this.results = function() {
|
||||
return this.lazy_escape(this.results_raw());
|
||||
};
|
||||
|
||||
|
||||
this.prettyprint = function(something, quote_strings) {
|
||||
var type = typeof something;
|
||||
switch(type.toLowerCase()) {
|
||||
case 'string':
|
||||
if (quote_strings) {
|
||||
return "'" + something.replace("'", "\\'") + "'";
|
||||
} else {
|
||||
return something;
|
||||
}
|
||||
case 'number':
|
||||
return '' + something;
|
||||
case 'boolean':
|
||||
return something ? 'true' : 'false';
|
||||
case 'undefined':
|
||||
return 'undefined';
|
||||
case 'object':
|
||||
if (something instanceof Array) {
|
||||
var x = [];
|
||||
var expected_index = 0;
|
||||
for (var k in something) {
|
||||
if (k == expected_index) {
|
||||
x.push(this.prettyprint(something[k], true));
|
||||
expected_index += 1;
|
||||
} else {
|
||||
x.push('\n' + k + ': ' + this.prettyprint(something[k], true));
|
||||
}
|
||||
}
|
||||
return '[' + x.join(', ') + ']';
|
||||
} else {
|
||||
return 'object: ' + something;
|
||||
}
|
||||
default:
|
||||
return type + ': ' + something;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.lazy_escape = function (str) {
|
||||
return str.replace(/</g, '<').replace(/\>/g, '>').replace(/\n/g, '<br />');
|
||||
};
|
||||
|
||||
|
||||
this.log = function () {
|
||||
if (window.console) {
|
||||
if (console.firebug) {
|
||||
console.log.apply(console, Array.prototype.slice.call(arguments));
|
||||
} else {
|
||||
console.log.call(console, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = SanityTest;
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function (mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function (CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("sql", function (config, parserConfig) {
|
||||
"use strict";
|
||||
|
||||
var client = parserConfig.client || {},
|
||||
atoms = parserConfig.atoms || { "false": true, "true": true, "null": true },
|
||||
builtin = parserConfig.builtin || {},
|
||||
keywords = parserConfig.keywords || {},
|
||||
operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/,
|
||||
support = parserConfig.support || {},
|
||||
hooks = parserConfig.hooks || {},
|
||||
dateSQL = parserConfig.dateSQL || { "date": true, "time": true, "timestamp": true };
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
|
||||
// call hooks from the mime type
|
||||
if (hooks[ch]) {
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
|
||||
if (support.hexNumber == true &&
|
||||
((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
|
||||
|| (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
|
||||
// hex
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
|
||||
return "number";
|
||||
} else if (support.binaryNumber == true &&
|
||||
(((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
|
||||
|| (ch == "0" && stream.match(/^b[01]+/)))) {
|
||||
// bitstring
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html
|
||||
return "number";
|
||||
} else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
|
||||
// numbers
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
|
||||
stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
|
||||
support.decimallessFloat == true && stream.eat('.');
|
||||
return "number";
|
||||
} else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
|
||||
// placeholders
|
||||
return "variable-3";
|
||||
} else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
|
||||
// strings
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
|
||||
state.tokenize = tokenLiteral(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if ((((support.nCharCast == true && (ch == "n" || ch == "N"))
|
||||
|| (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
|
||||
&& (stream.peek() == "'" || stream.peek() == '"'))) {
|
||||
// charset casting: _utf8'str', N'str', n'str'
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
|
||||
return "keyword";
|
||||
} else if (/^[\(\),\;\[\]]/.test(ch)) {
|
||||
// no highlightning
|
||||
return null;
|
||||
} else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
|
||||
// 1-line comment
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
} else if ((support.commentHash && ch == "#")
|
||||
|| (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
|
||||
// 1-line comments
|
||||
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
} else if (ch == "/" && stream.eat("*")) {
|
||||
// multi-line comments
|
||||
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||||
state.tokenize = tokenComment;
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ".") {
|
||||
// .1 for 0.1
|
||||
if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
|
||||
return "number";
|
||||
}
|
||||
// .table_name (ODBC)
|
||||
// // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
|
||||
if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {
|
||||
return "variable-2";
|
||||
}
|
||||
} else if (operatorChars.test(ch)) {
|
||||
// operators
|
||||
stream.eatWhile(operatorChars);
|
||||
return null;
|
||||
} else if (ch == '{' &&
|
||||
(stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
|
||||
// dates (weird ODBC syntax)
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
|
||||
return "number";
|
||||
} else {
|
||||
stream.eatWhile(/^[_\w\d]/);
|
||||
var word = stream.current().toLowerCase();
|
||||
// dates (standard SQL syntax)
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
|
||||
if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
|
||||
return "number";
|
||||
if (atoms.hasOwnProperty(word)) return "atom";
|
||||
if (builtin.hasOwnProperty(word)) return "builtin";
|
||||
if (keywords.hasOwnProperty(word)) return "keyword";
|
||||
if (client.hasOwnProperty(word)) return "string-2";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 'string', with char specified in quote escaped by '\'
|
||||
function tokenLiteral(quote) {
|
||||
return function (stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
function tokenComment(stream, state) {
|
||||
while (true) {
|
||||
if (stream.skipTo("*")) {
|
||||
stream.next();
|
||||
if (stream.eat("/")) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
|
||||
function pushContext(stream, state, type) {
|
||||
state.context = {
|
||||
prev: state.context,
|
||||
indent: stream.indentation(),
|
||||
col: stream.column(),
|
||||
type: type
|
||||
};
|
||||
}
|
||||
|
||||
function popContext(state) {
|
||||
state.indent = state.context.indent;
|
||||
state.context = state.context.prev;
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function () {
|
||||
return { tokenize: tokenBase, context: null };
|
||||
},
|
||||
|
||||
token: function (stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (state.context && state.context.align == null)
|
||||
state.context.align = false;
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
var style = state.tokenize(stream, state);
|
||||
if (style == "comment") return style;
|
||||
|
||||
if (state.context && state.context.align == null)
|
||||
state.context.align = true;
|
||||
|
||||
var tok = stream.current();
|
||||
if (tok == "(")
|
||||
pushContext(stream, state, ")");
|
||||
else if (tok == "[")
|
||||
pushContext(stream, state, "]");
|
||||
else if (state.context && state.context.type == tok)
|
||||
popContext(state);
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function (state, textAfter) {
|
||||
var cx = state.context;
|
||||
if (!cx) return 0;
|
||||
var closing = textAfter.charAt(0) == cx.type;
|
||||
if (cx.align) return cx.col + (closing ? 0 : 1);
|
||||
else return cx.indent + (closing ? 0 : config.indentUnit);
|
||||
},
|
||||
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null
|
||||
};
|
||||
});
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// `identifier`
|
||||
function hookIdentifier(stream) {
|
||||
// MySQL/MariaDB identifiers
|
||||
// ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "`" && !stream.eat("`")) return "variable-2";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// variable token
|
||||
function hookVar(stream) {
|
||||
// variables
|
||||
// @@prefix.varName @varName
|
||||
// varName can be quoted with ` or ' or "
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
|
||||
if (stream.eat("@")) {
|
||||
stream.match(/^session\./);
|
||||
stream.match(/^local\./);
|
||||
stream.match(/^global\./);
|
||||
}
|
||||
|
||||
if (stream.eat("'")) {
|
||||
stream.match(/^.*'/);
|
||||
return "variable-2";
|
||||
} else if (stream.eat('"')) {
|
||||
stream.match(/^.*"/);
|
||||
return "variable-2";
|
||||
} else if (stream.eat("`")) {
|
||||
stream.match(/^.*`/);
|
||||
return "variable-2";
|
||||
} else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) {
|
||||
return "variable-2";
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// short client keyword token
|
||||
function hookClient(stream) {
|
||||
// \N means NULL
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html
|
||||
if (stream.eat("N")) {
|
||||
return "atom";
|
||||
}
|
||||
// \g, etc
|
||||
// ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html
|
||||
return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
|
||||
}
|
||||
|
||||
// these keywords are used by all SQL dialects (however, a mode can still overwrite it)
|
||||
var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where ";
|
||||
|
||||
// turn a space-separated list into an array
|
||||
function set(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
// A generic SQL Mode. It's not a standard, it just try to support what is generally supported
|
||||
CodeMirror.defineMIME("text/x-sql", {
|
||||
name: "sql",
|
||||
keywords: set(sqlKeywords + "begin"),
|
||||
builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mssql", {
|
||||
name: "sql",
|
||||
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
|
||||
keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered"),
|
||||
builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=]/,
|
||||
dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"),
|
||||
hooks: {
|
||||
"@": hookVar
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mysql", {
|
||||
name: "sql",
|
||||
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
|
||||
keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
|
||||
builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=&|^]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
|
||||
hooks: {
|
||||
"@": hookVar,
|
||||
"`": hookIdentifier,
|
||||
"\\": hookClient
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-mariadb", {
|
||||
name: "sql",
|
||||
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
|
||||
keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
|
||||
builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=&|^]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
|
||||
hooks: {
|
||||
"@": hookVar,
|
||||
"`": hookIdentifier,
|
||||
"\\": hookClient
|
||||
}
|
||||
});
|
||||
|
||||
// the query language used by Apache Cassandra is called CQL, but this mime type
|
||||
// is called Cassandra to avoid confusion with Contextual Query Language
|
||||
CodeMirror.defineMIME("text/x-cassandra", {
|
||||
name: "sql",
|
||||
client: {},
|
||||
keywords: set("use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum"),
|
||||
builtin: set("ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint"),
|
||||
atoms: set("false true"),
|
||||
operatorChars: /^[<>=]/,
|
||||
dateSQL: {},
|
||||
support: set("commentSlashSlash decimallessFloat"),
|
||||
hooks: {}
|
||||
});
|
||||
|
||||
// this is based on Peter Raganitsch's 'plsql' mode
|
||||
CodeMirror.defineMIME("text/x-plsql", {
|
||||
name: "sql",
|
||||
client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),
|
||||
keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),
|
||||
builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"),
|
||||
operatorChars: /^[*+\-%<>!=~]/,
|
||||
dateSQL: set("date time timestamp"),
|
||||
support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")
|
||||
});
|
||||
|
||||
// Created to support specific hive keywords
|
||||
CodeMirror.defineMIME("text/x-hive", {
|
||||
name: "sql",
|
||||
keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with"),
|
||||
builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype"),
|
||||
atoms: set("false true null unknown"),
|
||||
operatorChars: /^[*+\-%<>!=]/,
|
||||
dateSQL: set("date timestamp"),
|
||||
support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
|
||||
});
|
||||
} ());
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
How Properties of Mime Types are used by SQL Mode
|
||||
=================================================
|
||||
|
||||
keywords:
|
||||
A list of keywords you want to be highlighted.
|
||||
functions:
|
||||
A list of function names you want to be highlighted.
|
||||
builtin:
|
||||
A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
|
||||
operatorChars:
|
||||
All characters that must be handled as operators.
|
||||
client:
|
||||
Commands parsed and executed by the client (not the server).
|
||||
support:
|
||||
A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.
|
||||
* ODBCdotTable: .tableName
|
||||
* zerolessFloat: .1
|
||||
* doubleQuote
|
||||
* nCharCast: N'string'
|
||||
* charsetCast: _utf8'string'
|
||||
* commentHash: use # char for comments
|
||||
* commentSlashSlash: use // for comments
|
||||
* commentSpaceRequired: require a space after -- for comments
|
||||
atoms:
|
||||
Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:
|
||||
UNKNOWN, INFINITY, UNDERFLOW, NaN...
|
||||
dateSQL:
|
||||
Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.
|
||||
*/
|
||||
@@ -0,0 +1,73 @@
|
||||
/*global unescape */
|
||||
/*jshint curly: false, scripturl: true */
|
||||
//
|
||||
// trivial bookmarklet/escaped script detector for the javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (Urlencoded.detect(some_string)) {
|
||||
// var unpacked = Urlencoded.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var isNode = (typeof module !== 'undefined' && module.exports);
|
||||
if (isNode) {
|
||||
var SanityTest = require(__dirname + '/../../test/sanitytest');
|
||||
}
|
||||
|
||||
var Urlencoded = {
|
||||
detect: function (str) {
|
||||
// the fact that script doesn't contain any space, but has %20 instead
|
||||
// should be sufficient check for now.
|
||||
if (str.indexOf(' ') == -1) {
|
||||
if (str.indexOf('%2') != -1) return true;
|
||||
if (str.replace(/[^%]+/g, '').length > 3) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (Urlencoded.detect(str)) {
|
||||
if (str.indexOf('%2B') != -1 || str.indexOf('%2b') != -1) {
|
||||
// "+" escaped as "%2B"
|
||||
return unescape(str.replace(/\+/g, '%20'));
|
||||
} else {
|
||||
return unescape(str);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
t.test_function(Urlencoded.detect, "Urlencoded.detect");
|
||||
t.expect('', false);
|
||||
t.expect('var a = b', false);
|
||||
t.expect('var%20a+=+b', true);
|
||||
t.expect('var%20a=b', true);
|
||||
t.expect('var%20%21%22', true);
|
||||
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();', true);
|
||||
t.test_function(Urlencoded.unpack, 'Urlencoded.unpack');
|
||||
|
||||
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();',
|
||||
'javascript:(function(){var whatever={init:function(){alert("a"+"b")}};whatever.init()})();'
|
||||
);
|
||||
t.expect('', '');
|
||||
t.expect('abcd', 'abcd');
|
||||
t.expect('var a = b', 'var a = b');
|
||||
t.expect('var%20a=b', 'var a=b');
|
||||
t.expect('var%20a=b+1', 'var a=b+1');
|
||||
t.expect('var%20a=b%2b1', 'var a=b+1');
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
if (isNode) {
|
||||
module.exports = Urlencoded;
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
|
||||
var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
|
||||
if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
|
||||
|
||||
var Kludges = parserConfig.htmlMode ? {
|
||||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
|
||||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
|
||||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
|
||||
'track': true, 'wbr': true, 'menuitem': true},
|
||||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
|
||||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
|
||||
'th': true, 'tr': true},
|
||||
contextGrabbers: {
|
||||
'dd': {'dd': true, 'dt': true},
|
||||
'dt': {'dd': true, 'dt': true},
|
||||
'li': {'li': true},
|
||||
'option': {'option': true, 'optgroup': true},
|
||||
'optgroup': {'optgroup': true},
|
||||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
|
||||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
|
||||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
|
||||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
|
||||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
|
||||
'rp': {'rp': true, 'rt': true},
|
||||
'rt': {'rp': true, 'rt': true},
|
||||
'tbody': {'tbody': true, 'tfoot': true},
|
||||
'td': {'td': true, 'th': true},
|
||||
'tfoot': {'tbody': true},
|
||||
'th': {'td': true, 'th': true},
|
||||
'thead': {'tbody': true, 'tfoot': true},
|
||||
'tr': {'tr': true}
|
||||
},
|
||||
doNotIndent: {"pre": true},
|
||||
allowUnquoted: true,
|
||||
allowMissing: true,
|
||||
caseFold: true
|
||||
} : {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false,
|
||||
caseFold: false
|
||||
};
|
||||
var alignCDATA = parserConfig.alignCDATA;
|
||||
|
||||
// Return variables for tokenizers
|
||||
var type, setStyle;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
|
||||
else return null;
|
||||
} else if (stream.match("--")) {
|
||||
return chain(inBlock("comment", "-->"));
|
||||
} else if (stream.match("DOCTYPE", true, true)) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(doctype(1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("meta", "?>");
|
||||
return "meta";
|
||||
} else {
|
||||
type = stream.eat("/") ? "closeTag" : "openTag";
|
||||
state.tokenize = inTag;
|
||||
return "tag bracket";
|
||||
}
|
||||
} else if (ch == "&") {
|
||||
var ok;
|
||||
if (stream.eat("#")) {
|
||||
if (stream.eat("x")) {
|
||||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
|
||||
}
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
|
||||
}
|
||||
return ok ? "atom" : "error";
|
||||
} else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "tag bracket";
|
||||
} else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
} else if (ch == "<") {
|
||||
state.tokenize = inText;
|
||||
state.state = baseState;
|
||||
state.tagName = state.tagStart = null;
|
||||
var next = state.tokenize(stream, state);
|
||||
return next ? next + " tag error" : "tag error";
|
||||
} else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
state.stringStartCol = stream.column();
|
||||
return state.tokenize(stream, state);
|
||||
} else {
|
||||
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
|
||||
return "word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
var closure = function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
closure.isInAttribute = true;
|
||||
return closure;
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
function doctype(depth) {
|
||||
return function(stream, state) {
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "<") {
|
||||
state.tokenize = doctype(depth + 1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ">") {
|
||||
if (depth == 1) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
} else {
|
||||
state.tokenize = doctype(depth - 1);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
};
|
||||
}
|
||||
|
||||
function Context(state, tagName, startOfLine) {
|
||||
this.prev = state.context;
|
||||
this.tagName = tagName;
|
||||
this.indent = state.indented;
|
||||
this.startOfLine = startOfLine;
|
||||
if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
|
||||
this.noIndent = true;
|
||||
}
|
||||
function popContext(state) {
|
||||
if (state.context) state.context = state.context.prev;
|
||||
}
|
||||
function maybePopContext(state, nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!state.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = state.context.tagName;
|
||||
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext(state);
|
||||
}
|
||||
}
|
||||
|
||||
function baseState(type, stream, state) {
|
||||
if (type == "openTag") {
|
||||
state.tagStart = stream.column();
|
||||
return tagNameState;
|
||||
} else if (type == "closeTag") {
|
||||
return closeTagNameState;
|
||||
} else {
|
||||
return baseState;
|
||||
}
|
||||
}
|
||||
function tagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
state.tagName = stream.current();
|
||||
setStyle = "tag";
|
||||
return attrState;
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return tagNameState;
|
||||
}
|
||||
}
|
||||
function closeTagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
var tagName = stream.current();
|
||||
if (state.context && state.context.tagName != tagName &&
|
||||
Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
|
||||
popContext(state);
|
||||
if (state.context && state.context.tagName == tagName) {
|
||||
setStyle = "tag";
|
||||
return closeState;
|
||||
} else {
|
||||
setStyle = "tag error";
|
||||
return closeStateErr;
|
||||
}
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return closeStateErr;
|
||||
}
|
||||
}
|
||||
|
||||
function closeState(type, _stream, state) {
|
||||
if (type != "endTag") {
|
||||
setStyle = "error";
|
||||
return closeState;
|
||||
}
|
||||
popContext(state);
|
||||
return baseState;
|
||||
}
|
||||
function closeStateErr(type, stream, state) {
|
||||
setStyle = "error";
|
||||
return closeState(type, stream, state);
|
||||
}
|
||||
|
||||
function attrState(type, _stream, state) {
|
||||
if (type == "word") {
|
||||
setStyle = "attribute";
|
||||
return attrEqState;
|
||||
} else if (type == "endTag" || type == "selfcloseTag") {
|
||||
var tagName = state.tagName, tagStart = state.tagStart;
|
||||
state.tagName = state.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
|
||||
maybePopContext(state, tagName);
|
||||
} else {
|
||||
maybePopContext(state, tagName);
|
||||
state.context = new Context(state, tagName, tagStart == state.indented);
|
||||
}
|
||||
return baseState;
|
||||
}
|
||||
setStyle = "error";
|
||||
return attrState;
|
||||
}
|
||||
function attrEqState(type, stream, state) {
|
||||
if (type == "equals") return attrValueState;
|
||||
if (!Kludges.allowMissing) setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
|
||||
setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrContinuedState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol())
|
||||
state.indented = stream.indentation();
|
||||
|
||||
if (stream.eatSpace()) return null;
|
||||
type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if ((style || type) && style != "comment") {
|
||||
setStyle = null;
|
||||
state.state = state.state(type || style, stream, state);
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
var context = state.context;
|
||||
// Indent multi-line strings (e.g. css).
|
||||
if (state.tokenize.isInAttribute) {
|
||||
if (state.tagStart == state.indented)
|
||||
return state.stringStartCol + 1;
|
||||
else
|
||||
return state.indented + indentUnit;
|
||||
}
|
||||
if (context && context.noIndent) return CodeMirror.Pass;
|
||||
if (state.tokenize != inTag && state.tokenize != inText)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
// Indent the starts of attribute names.
|
||||
if (state.tagName) {
|
||||
if (multilineTagIndentPastTag)
|
||||
return state.tagStart + state.tagName.length + 2;
|
||||
else
|
||||
return state.tagStart + indentUnit * multilineTagIndentFactor;
|
||||
}
|
||||
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
|
||||
if (tagAfter && tagAfter[1]) { // Closing tag spotted
|
||||
while (context) {
|
||||
if (context.tagName == tagAfter[2]) {
|
||||
context = context.prev;
|
||||
break;
|
||||
} else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
|
||||
context = context.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagAfter) { // Opening tag spotted
|
||||
while (context) {
|
||||
var grabbers = Kludges.contextGrabbers[context.tagName];
|
||||
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
|
||||
context = context.prev;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (context && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return 0;
|
||||
},
|
||||
|
||||
electricInput: /<\/[\s\w:]+>$/,
|
||||
blockCommentStart: "<!--",
|
||||
blockCommentEnd: "-->",
|
||||
|
||||
configuration: parserConfig.htmlMode ? "html" : "xml",
|
||||
helperType: parserConfig.htmlMode ? "html" : "xml"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user