mirror of https://github.com/xwiki-labs/cryptpad
Merge branch 'asciidoc' into 5.1-candidate
This commit is contained in:
commit
97bc45c3d7
|
@ -7,6 +7,7 @@ define([
|
|||
var list = Modes.list = [
|
||||
"APL apl .apl",
|
||||
"ASCII-Armor asciiarmor .asc",
|
||||
"AsciiDoc asciidoc .adoc",
|
||||
"ASN.1 asn.1 .asn1",
|
||||
"Asterisk asterisk",
|
||||
"Brainfuck brainfuck .b",
|
||||
|
|
|
@ -20,6 +20,7 @@ define([
|
|||
'netflux-client': '/bower_components/netflux-websocket/netflux-client',
|
||||
'chainpad-netflux': '/bower_components/chainpad-netflux/chainpad-netflux',
|
||||
'chainpad-listmap': '/bower_components/chainpad-listmap/chainpad-listmap',
|
||||
'cm-extra': '/lib/codemirror-extra-modes'
|
||||
},
|
||||
map: {
|
||||
'*': {
|
||||
|
|
|
@ -272,6 +272,13 @@ define([
|
|||
if (/text\/x/.test(mode)) {
|
||||
CMeditor.autoLoadMode(editor, 'clike');
|
||||
editor.setOption('mode', mode);
|
||||
} else if (mode === 'asciidoc') {
|
||||
CMeditor.autoLoadMode(editor, mode, {
|
||||
path: function () {
|
||||
return 'cm-extra/asciidoc/asciidoc';
|
||||
}
|
||||
});
|
||||
editor.setOption('mode', mode);
|
||||
} else {
|
||||
if (mode !== "text") {
|
||||
CMeditor.autoLoadMode(editor, mode);
|
||||
|
|
|
@ -11,4 +11,5 @@ This file is intended to be used as a log of what third-party source we have ven
|
|||
* [mermaid 9.0.0](https://github.com/mermaid-js/mermaid/releases/tag/8.13.4) extends our markdown integration to support a variety of diagram types
|
||||
* [Fabricjs 4.6.0](https://github.com/fabricjs/fabric.js) and [Fabric-history](https://github.com/lyzerk/fabric-history) for the whiteboard app
|
||||
* [Requirejs optional module plugin](https://stackoverflow.com/a/27422370)
|
||||
* [asciidoc.js 2.0.0](https://github.com/asciidoctor/codemirror-asciidoc/releases/tag/2.0.0) with slight changes to match the format of other codemirror modes
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2010, Ajax.org B.V.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Ajax.org B.V. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,666 @@
|
|||
// Parts from Ace; see <https://raw.githubusercontent.com/ajaxorg/ace/master/LICENSE>
|
||||
// Ace highlight rules function imported below.
|
||||
|
||||
(function(mod) {
|
||||
"use strict";
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("cm/lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["cm/lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
CodeMirror.defineMode("asciidoc", function() {
|
||||
|
||||
var HighlightRules = function () {
|
||||
var identifierRe = "[a-zA-Z\u00a1-\uffff]+\\b";
|
||||
|
||||
this.$rules = {
|
||||
"start": [
|
||||
{token: "empty", regex: /$/},
|
||||
{token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"},
|
||||
{token: "literal", regex: /^-{4,}\s*$/, next: "literalBlock"},
|
||||
{token: "literal", regex: /^\+{4,}\s*$/, next: "passthroughBlock"},
|
||||
{token: "keyword", regex: /^={4,}\s*$/},
|
||||
{token: "text", regex: /^\s*$/},
|
||||
// immediately return to the start mode without matching anything
|
||||
{token: "empty", regex: "", next: "dissallowDelimitedBlock"}
|
||||
],
|
||||
|
||||
"dissallowDelimitedBlock": [
|
||||
{include: "paragraphEnd"},
|
||||
{token: "comment", regex: '^//.+$'},
|
||||
{token: "keyword", regex: "^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s"},
|
||||
|
||||
{include: "listStart"},
|
||||
{token: "literal", regex: /^\s+.+$/, next: "indentedBlock"},
|
||||
{token: "empty", regex: "", next: "text"}
|
||||
],
|
||||
|
||||
"paragraphEnd": [
|
||||
{token: "doc.comment", regex: /^\/{4,}\s*$/, next: "commentBlock"},
|
||||
{token: "tableBlock", regex: /^\s*[|!]=+\s*$/, next: "tableBlock"},
|
||||
// open block, ruler
|
||||
{token: "keyword", regex: /^(?:--|''')\s*$/, next: "start"},
|
||||
{token: "option", regex: /^\[.*\]\s*$/, next: "start"},
|
||||
{token: "pageBreak", regex: /^>{3,}$/, next: "start"},
|
||||
{token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"},
|
||||
{token: "titleUnderline", regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: "start"},
|
||||
{token: "singleLineTitle", regex: /^={1,6}\s+\S.*$/, next: "start"},
|
||||
|
||||
{token: "otherBlock", regex: /^(?:\*{2,}|_{2,})\s*$/, next: "start"},
|
||||
// .optional title
|
||||
{token: "optionalTitle", regex: /^\.[^.\s].+$/, next: "start"}
|
||||
],
|
||||
|
||||
"listStart": [
|
||||
{
|
||||
token: "keyword",
|
||||
regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,
|
||||
next: "listText"
|
||||
},
|
||||
{token: "meta.tag", regex: /^.+(?::{2,4}|;;)(?: |$)/, next: "listText"},
|
||||
// continuation
|
||||
{token: "keyword", regex: /^\+\s*$/, next: "start"}
|
||||
],
|
||||
|
||||
"text": [
|
||||
{
|
||||
token: ["link", "link"],
|
||||
regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/
|
||||
},
|
||||
{token: ["link", "link"], regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/},
|
||||
{token: "link", regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/},
|
||||
{include: "macros"},
|
||||
{include: "paragraphEnd"},
|
||||
{token: "literal", regex: /\+{3,}/, next: "smallPassthrough"},
|
||||
{
|
||||
token: "escape",
|
||||
regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/
|
||||
},
|
||||
{token: "escape", regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/},
|
||||
{token: "keyword", regex: /\s\+$/},
|
||||
// any word
|
||||
{token: "text", regex: identifierRe},
|
||||
{
|
||||
token: ["keyword", "string", "keyword"],
|
||||
regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/
|
||||
},
|
||||
{token: "keyword", regex: /<<[\w\d\-$]+,?|>>/},
|
||||
{token: "constant.character", regex: /\({2,3}.*?\){2,3}/},
|
||||
// List of callouts
|
||||
{token: "support.function.list.callout", regex: /^(?:<\d+>|\d+>|>) /, next: "text"},
|
||||
// Anchor
|
||||
{token: "keyword", regex: /\[\[.+?\]\]/},
|
||||
// bibliography
|
||||
{token: "support", regex: /^\[{3}[\w\d =\-]+\]{3}/},
|
||||
|
||||
{include: "quotes"},
|
||||
// text block end
|
||||
{token: "empty", regex: /^\s*$/, next: "start"}
|
||||
],
|
||||
|
||||
"listText": [
|
||||
{include: "listStart"},
|
||||
{include: "text"}
|
||||
],
|
||||
|
||||
"indentedBlock": [
|
||||
{token: "literal", regex: /^[\s\w].+$/, next: "indentedBlock"},
|
||||
{token: "literal", regex: "", next: "start"}
|
||||
],
|
||||
|
||||
"listingBlock": [
|
||||
{token: "literal", regex: /^\.{4,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "constant.numeric", regex: '<\\d+>'},
|
||||
{token: "literal", regex: '[^<]+'},
|
||||
{token: "literal", regex: '<'}
|
||||
],
|
||||
"literalBlock": [
|
||||
{token: "literal", regex: /^-{4,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "constant.numeric", regex: '<\\d+>'},
|
||||
{token: "literal", regex: '[^<]+'},
|
||||
{token: "literal", regex: '<'}
|
||||
],
|
||||
"passthroughBlock": [
|
||||
{token: "literal", regex: /^\+{4,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "literal", regex: identifierRe + "|\\d+"},
|
||||
{include: "macros"},
|
||||
{token: "literal", regex: "."}
|
||||
],
|
||||
|
||||
"smallPassthrough": [
|
||||
{token: "literal", regex: /[+]{3,}/, next: "dissallowDelimitedBlock"},
|
||||
{token: "literal", regex: /^\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "literal", regex: identifierRe + "|\\d+"},
|
||||
{include: "macros"}
|
||||
],
|
||||
|
||||
"commentBlock": [
|
||||
{token: "doc.comment", regex: /^\/{4,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "doc.comment", regex: '^.*$'}
|
||||
],
|
||||
"tableBlock": [
|
||||
{token: "tableBlock", regex: /^\s*\|={3,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "innerTableBlock"},
|
||||
{token: "tableBlock", regex: /\|/},
|
||||
{include: "text", noEscape: true}
|
||||
],
|
||||
"innerTableBlock": [
|
||||
{token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "tableBlock"},
|
||||
{token: "tableBlock", regex: /^\s*|={3,}\s*$/, next: "dissallowDelimitedBlock"},
|
||||
{token: "tableBlock", regex: /\!/}
|
||||
],
|
||||
"macros": [
|
||||
{token: "macro", regex: /{[\w\-$]+}/},
|
||||
{
|
||||
token: ["text", "string", "text", "constant.character", "text"],
|
||||
regex: /({)([\w\-$]+)(:)?(.+)?(})/
|
||||
},
|
||||
{
|
||||
token: ["text", "markup.list.macro", "keyword", "string"],
|
||||
regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/
|
||||
},
|
||||
{
|
||||
token: ["markup.list.macro", "keyword", "string"],
|
||||
regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/
|
||||
},
|
||||
{token: ["markup.list.macro", "keyword"], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/},
|
||||
{token: "keyword", regex: /^:.+?:(?= |$)/}
|
||||
],
|
||||
|
||||
"quotes": [
|
||||
{token: "string.italic", regex: /__[^_\s].*?__/},
|
||||
{token: "string.italic", regex: quoteRule("_")},
|
||||
|
||||
{token: "keyword.bold", regex: /\*\*[^*\s].*?\*\*/},
|
||||
{token: "keyword.bold", regex: quoteRule("\\*")},
|
||||
|
||||
{token: "literal", regex: /\+\+[^+\s].*?\+\+/},
|
||||
{token: "literal", regex: quoteRule("\\+")},
|
||||
|
||||
{token: "literal", regex: /\$\$.+?\$\$/},
|
||||
{token: "literal", regex: quoteRule("\\$")},
|
||||
|
||||
{token: "literal", regex: /``[^`\s].*?``/},
|
||||
{token: "literal", regex: quoteRule("`")},
|
||||
|
||||
{token: "keyword", regex: /\^[^\^].*?\^/},
|
||||
{token: "keyword", regex: quoteRule("\\^")},
|
||||
{token: "keyword", regex: /~[^~].*?~/},
|
||||
{token: "keyword", regex: quoteRule("~")},
|
||||
|
||||
{token: "keyword", regex: /##?/},
|
||||
{token: "keyword", regex: /(?:\B|^)``|\b''/}
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
function quoteRule(ch) {
|
||||
var prefix = /\w/.test(ch) ? "\\b" : "(?:\\B|^)";
|
||||
return prefix + ch + "[^" + ch + "].*?" + ch + "(?![\\w*])";
|
||||
}
|
||||
|
||||
//addQuoteBlock("text")
|
||||
|
||||
var tokenMap = {
|
||||
macro: "constant.character",
|
||||
tableBlock: "doc.comment",
|
||||
titleUnderline: "markup.heading",
|
||||
singleLineTitle: "markup.heading",
|
||||
pageBreak: "string",
|
||||
option: "string.regexp",
|
||||
otherBlock: "markup.list",
|
||||
literal: "support.function",
|
||||
optionalTitle: "constant.numeric",
|
||||
escape: "constant.language.escape",
|
||||
link: "markup.underline.list"
|
||||
};
|
||||
|
||||
for (var state in this.$rules) {
|
||||
var stateRules = this.$rules[state];
|
||||
for (var i = stateRules.length; i--;) {
|
||||
var rule = stateRules[i];
|
||||
if (rule.include || typeof rule == "string") {
|
||||
var args = [i, 1].concat(this.$rules[rule.include || rule]);
|
||||
if (rule.noEscape) {
|
||||
args = args.filter(function (x) {
|
||||
return !x.next;
|
||||
});
|
||||
}
|
||||
stateRules.splice.apply(stateRules, args);
|
||||
} else if (rule.token in tokenMap) {
|
||||
rule.token = tokenMap[rule.token];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Ace's Syntax Tokenizer.
|
||||
|
||||
// tokenizing lines longer than this makes editor very slow
|
||||
var MAX_TOKEN_COUNT = 1000;
|
||||
var Tokenizer = function (rules) {
|
||||
this.states = rules;
|
||||
|
||||
this.regExps = {};
|
||||
this.matchMappings = {};
|
||||
for (var key in this.states) {
|
||||
var state = this.states[key];
|
||||
var ruleRegExps = [];
|
||||
var matchTotal = 0;
|
||||
var mapping = this.matchMappings[key] = {defaultToken: "text"};
|
||||
var flag = "g";
|
||||
|
||||
var splitterRurles = [];
|
||||
for (var i = 0; i < state.length; i++) {
|
||||
var rule = state[i];
|
||||
if (rule.defaultToken)
|
||||
mapping.defaultToken = rule.defaultToken;
|
||||
if (rule.caseInsensitive)
|
||||
flag = "gi";
|
||||
if (rule.regex == null)
|
||||
continue;
|
||||
|
||||
if (rule.regex instanceof RegExp)
|
||||
rule.regex = rule.regex.toString().slice(1, -1);
|
||||
|
||||
// Count number of matching groups. 2 extra groups from the full match
|
||||
// And the catch-all on the end (used to force a match);
|
||||
var adjustedregex = rule.regex;
|
||||
var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2;
|
||||
if (Array.isArray(rule.token)) {
|
||||
if (rule.token.length == 1 || matchcount == 1) {
|
||||
rule.token = rule.token[0];
|
||||
} else if (matchcount - 1 != rule.token.length) {
|
||||
throw new Error("number of classes and regexp groups in '" +
|
||||
rule.token + "'\n'" + rule.regex + "' doesn't match\n"
|
||||
+ (matchcount - 1) + "!=" + rule.token.length);
|
||||
} else {
|
||||
rule.tokenArray = rule.token;
|
||||
rule.token = null;
|
||||
rule.onMatch = this.$arrayTokens;
|
||||
}
|
||||
} else if (typeof rule.token == "function" && !rule.onMatch) {
|
||||
if (matchcount > 1)
|
||||
rule.onMatch = this.$applyToken;
|
||||
else
|
||||
rule.onMatch = rule.token;
|
||||
}
|
||||
|
||||
if (matchcount > 1) {
|
||||
if (/\\\d/.test(rule.regex)) {
|
||||
// Replace any backreferences and offset appropriately.
|
||||
adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
|
||||
return "\\" + (parseInt(digit, 10) + matchTotal + 1);
|
||||
});
|
||||
} else {
|
||||
matchcount = 1;
|
||||
adjustedregex = this.removeCapturingGroups(rule.regex);
|
||||
}
|
||||
if (!rule.splitRegex && typeof rule.token != "string")
|
||||
splitterRurles.push(rule); // flag will be known only at the very end
|
||||
}
|
||||
|
||||
mapping[matchTotal] = i;
|
||||
matchTotal += matchcount;
|
||||
|
||||
ruleRegExps.push(adjustedregex);
|
||||
|
||||
// makes property access faster
|
||||
if (!rule.onMatch)
|
||||
rule.onMatch = null;
|
||||
}
|
||||
|
||||
splitterRurles.forEach(function (rule) {
|
||||
rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
|
||||
}, this);
|
||||
|
||||
this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag);
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
this.$setMaxTokenCount = function (m) {
|
||||
MAX_TOKEN_COUNT = m | 0;
|
||||
};
|
||||
|
||||
this.$applyToken = function (str) {
|
||||
var values = this.splitRegex.exec(str).slice(1);
|
||||
var types = this.token.apply(this, values);
|
||||
|
||||
// required for compatibility with old modes
|
||||
if (typeof types === "string")
|
||||
return [{type: types, value: str}];
|
||||
|
||||
var tokens = [];
|
||||
for (var i = 0, l = types.length; i < l; i++) {
|
||||
if (values[i])
|
||||
tokens[tokens.length] = {
|
||||
type: types[i],
|
||||
value: values[i]
|
||||
};
|
||||
}
|
||||
return tokens;
|
||||
},
|
||||
|
||||
this.$arrayTokens = function (str) {
|
||||
if (!str)
|
||||
return [];
|
||||
var values = this.splitRegex.exec(str);
|
||||
if (!values)
|
||||
return "text";
|
||||
var tokens = [];
|
||||
var types = this.tokenArray;
|
||||
for (var i = 0, l = types.length; i < l; i++) {
|
||||
if (values[i + 1])
|
||||
tokens[tokens.length] = {
|
||||
type: types[i],
|
||||
value: values[i + 1]
|
||||
};
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
this.removeCapturingGroups = function (src) {
|
||||
var r = src.replace(
|
||||
/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,
|
||||
function (x, y) {
|
||||
return y ? "(?:" : x;
|
||||
}
|
||||
);
|
||||
return r;
|
||||
};
|
||||
|
||||
this.createSplitterRegexp = function (src, flag) {
|
||||
if (src.indexOf("(?=") != -1) {
|
||||
var stack = 0;
|
||||
var inChClass = false;
|
||||
var lastCapture = {};
|
||||
src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function (m, esc, parenOpen, parenClose, square, index) {
|
||||
if (inChClass) {
|
||||
inChClass = square != "]";
|
||||
} else if (square) {
|
||||
inChClass = true;
|
||||
} else if (parenClose) {
|
||||
if (stack == lastCapture.stack) {
|
||||
lastCapture.end = index + 1;
|
||||
lastCapture.stack = -1;
|
||||
}
|
||||
stack--;
|
||||
} else if (parenOpen) {
|
||||
stack++;
|
||||
if (parenOpen.length != 1) {
|
||||
lastCapture.stack = stack
|
||||
lastCapture.start = index;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
});
|
||||
|
||||
if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
|
||||
src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
|
||||
}
|
||||
return new RegExp(src, (flag || "").replace("g", ""));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
|
||||
* @returns {Object}
|
||||
**/
|
||||
this.getLineTokens = function (line, startState) {
|
||||
if (startState && typeof startState != "string") {
|
||||
var stack = startState.slice(0);
|
||||
startState = stack[0];
|
||||
} else
|
||||
var stack = [];
|
||||
|
||||
var currentState = startState || "start";
|
||||
var state = this.states[currentState];
|
||||
if (!state) {
|
||||
currentState = "start";
|
||||
state = this.states[currentState];
|
||||
}
|
||||
var mapping = this.matchMappings[currentState];
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = 0;
|
||||
|
||||
var match, tokens = [];
|
||||
var lastIndex = 0;
|
||||
|
||||
var token = {type: null, value: ""};
|
||||
|
||||
while (match = re.exec(line)) {
|
||||
var type = mapping.defaultToken;
|
||||
var rule = null;
|
||||
var value = match[0];
|
||||
var index = re.lastIndex;
|
||||
|
||||
if (index - value.length > lastIndex) {
|
||||
var skipped = line.substring(lastIndex, index - value.length);
|
||||
if (token.type == type) {
|
||||
token.value += skipped;
|
||||
} else {
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
token = {type: type, value: skipped};
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < match.length - 2; i++) {
|
||||
if (match[i + 1] === undefined)
|
||||
continue;
|
||||
|
||||
rule = state[mapping[i]];
|
||||
|
||||
if (rule.onMatch)
|
||||
type = rule.onMatch(value, currentState, stack);
|
||||
else
|
||||
type = rule.token;
|
||||
|
||||
if (rule.next) {
|
||||
if (typeof rule.next == "string")
|
||||
currentState = rule.next;
|
||||
else
|
||||
currentState = rule.next(currentState, stack);
|
||||
|
||||
state = this.states[currentState];
|
||||
if (!state) {
|
||||
window.console && console.error && console.error(currentState, "doesn't exist");
|
||||
currentState = "start";
|
||||
state = this.states[currentState];
|
||||
}
|
||||
mapping = this.matchMappings[currentState];
|
||||
lastIndex = index;
|
||||
re = this.regExps[currentState];
|
||||
re.lastIndex = index;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
if (typeof type == "string") {
|
||||
if ((!rule || rule.merge !== false) && token.type === type) {
|
||||
token.value += value;
|
||||
} else {
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
token = {type: type, value: value};
|
||||
}
|
||||
} else if (type) {
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
token = {type: null, value: ""};
|
||||
for (var i = 0; i < type.length; i++)
|
||||
tokens.push(type[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastIndex == line.length)
|
||||
break;
|
||||
|
||||
lastIndex = index;
|
||||
|
||||
if (tokens.length > MAX_TOKEN_COUNT) {
|
||||
// chrome doens't show contents of text nodes with very long text
|
||||
while (lastIndex < line.length) {
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
token = {
|
||||
value: line.substring(lastIndex, lastIndex += 2000),
|
||||
type: "overflow"
|
||||
};
|
||||
}
|
||||
currentState = "start";
|
||||
stack = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.type)
|
||||
tokens.push(token);
|
||||
|
||||
if (stack.length > 1) {
|
||||
if (stack[0] !== currentState)
|
||||
stack.unshift(currentState);
|
||||
}
|
||||
return {
|
||||
tokens: tokens,
|
||||
state: stack.length ? stack : currentState
|
||||
};
|
||||
};
|
||||
|
||||
}).call(Tokenizer.prototype);
|
||||
|
||||
// Token conversion.
|
||||
// See <https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens>
|
||||
// This is not an exact match nor the best match that can be made.
|
||||
var tokenFromAceToken = {
|
||||
empty: null,
|
||||
text: null,
|
||||
|
||||
// Keyword
|
||||
keyword: 'keyword',
|
||||
control: 'keyword',
|
||||
operator: 'operator',
|
||||
|
||||
// Constants
|
||||
constant: 'atom',
|
||||
numeric: 'number',
|
||||
character: 'atom',
|
||||
escape: 'atom',
|
||||
|
||||
// Variables
|
||||
variable: 'variable',
|
||||
parameter: 'variable-3',
|
||||
language: 'variable-2', // Python's `self` uses that.
|
||||
|
||||
// Comments
|
||||
comment: 'comment',
|
||||
line: 'comment',
|
||||
'double-slash': 'comment',
|
||||
'double-dash': 'comment',
|
||||
'number-sign': 'comment',
|
||||
percentage: 'comment',
|
||||
block: 'comment',
|
||||
doc: 'comment',
|
||||
|
||||
// String
|
||||
string: 'string',
|
||||
quoted: 'string',
|
||||
single: 'string',
|
||||
double: 'string',
|
||||
triple: 'string',
|
||||
unquoted: 'string',
|
||||
interpolated: 'string',
|
||||
regexp: 'string-2',
|
||||
|
||||
meta: 'keyword',
|
||||
literal: 'qualifier',
|
||||
support: 'builtin',
|
||||
|
||||
// Markup
|
||||
markup: 'tag',
|
||||
underline: 'link',
|
||||
link: 'link',
|
||||
strong: 'strong',
|
||||
heading: 'header',
|
||||
em: 'em',
|
||||
list: 'variable-2',
|
||||
numbered: 'variable-2',
|
||||
unnumbered: 'variable-2',
|
||||
quote: 'quote',
|
||||
raw: 'variable-2', // Markdown's raw block uses that.
|
||||
|
||||
// Invalid
|
||||
invalid: 'error',
|
||||
illegal: 'invalidchar',
|
||||
deprecated: 'error'
|
||||
};
|
||||
|
||||
// Takes a list of Ace tokens, returns a (string) CodeMirror token.
|
||||
var cmTokenFromAceTokens = function (tokens) {
|
||||
var token = null;
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
// Find the most specific token.
|
||||
if (tokenFromAceToken[tokens[i]] !== undefined) {
|
||||
token = tokenFromAceToken[tokens[i]];
|
||||
}
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
// Consume a token from plannedTokens.
|
||||
var consumeToken = function (stream, state) {
|
||||
var plannedToken = state.plannedTokens.shift();
|
||||
if (plannedToken === undefined) {
|
||||
return null;
|
||||
}
|
||||
stream.match(plannedToken.value);
|
||||
var tokens = plannedToken.type.split('.');
|
||||
return cmTokenFromAceTokens(tokens);
|
||||
};
|
||||
|
||||
var matchToken = function (stream, state) {
|
||||
// Anormal start: we already have planned tokens to consume.
|
||||
if (state.plannedTokens.length > 0) {
|
||||
return consumeToken(stream, state);
|
||||
}
|
||||
|
||||
// Normal start.
|
||||
var currentState = state.current;
|
||||
var currentLine = stream.match(/.*$/, false)[0];
|
||||
var tokenized = tokenizer.getLineTokens(currentLine, currentState);
|
||||
// We got a {tokens, state} object.
|
||||
// Each token is a {value, type} object.
|
||||
state.plannedTokens = tokenized.tokens;
|
||||
state.current = tokenized.state;
|
||||
|
||||
// Consume a token.
|
||||
return consumeToken(stream, state);
|
||||
}
|
||||
|
||||
// Initialize all state.
|
||||
var aceHighlightRules = new HighlightRules();
|
||||
var tokenizer = new Tokenizer(aceHighlightRules.$rules);
|
||||
|
||||
var asciidoc = {
|
||||
startState: function () {
|
||||
return {
|
||||
current: 'start',
|
||||
// List of {value, type}, with type being an Ace token string.
|
||||
plannedTokens: []
|
||||
};
|
||||
},
|
||||
blankLine: function (state) {
|
||||
matchToken('', state);
|
||||
},
|
||||
token: matchToken
|
||||
};
|
||||
return asciidoc;
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME('text/asciidoc', 'asciidoc');
|
||||
});
|
Loading…
Reference in New Issue