##// END OF EJS Templates
Improved MathJax, missing callback workaround...
Improved MathJax, missing callback workaround MathJax.InputJax.TeX.resetEquationNumbers is supposed to be available, but isn't consistently loaded before the notebook fires off its first re-render request. The code edits in mathjaxutils.js fix this issue. Additionally, there was some init code in mathjaxutils.js that has been properly excised to the html templates. Removed some orphan rendering code so that all typesetting now goes through mathjaxutils.js Finally, removed an extra cell in the demo notebook.

File last commit:

r8053:58574fbf
r8659:9e186f76
Show More
coffeescript.js
346 lines | 10.7 KiB | application/javascript | JavascriptLexer
/**
* Link to the project's GitHub page:
* https://github.com/pickhardt/coffeescript-codemirror-mode
*/
CodeMirror.defineMode('coffeescript', function(conf) {
var ERRORCLASS = 'error';
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b");
}
var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\},:`=;\\.]');
var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*");
var properties = new RegExp("^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*");
var wordOperators = wordRegexp(['and', 'or', 'not',
'is', 'isnt', 'in',
'instanceof', 'typeof']);
var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else',
'switch', 'try', 'catch', 'finally', 'class'];
var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete',
'do', 'in', 'of', 'new', 'return', 'then',
'this', 'throw', 'when', 'until'];
var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
indentKeywords = wordRegexp(indentKeywords);
var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])");
var regexPrefixes = new RegExp("^(/{3}|/)");
var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no'];
var constants = wordRegexp(commonConstants);
// Tokenizers
function tokenBase(stream, state) {
// Handle scope changes
if (stream.sol()) {
var scopeOffset = state.scopes[0].offset;
if (stream.eatSpace()) {
var lineOffset = stream.indentation();
if (lineOffset > scopeOffset) {
return 'indent';
} else if (lineOffset < scopeOffset) {
return 'dedent';
}
return null;
} else {
if (scopeOffset > 0) {
dedent(stream, state);
}
}
}
if (stream.eatSpace()) {
return null;
}
var ch = stream.peek();
// Handle docco title comment (single line)
if (stream.match("####")) {
stream.skipToEnd();
return 'comment';
}
// Handle multi line comments
if (stream.match("###")) {
state.tokenize = longComment;
return state.tokenize(stream, state);
}
// Single line comment
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) {
// prevent from getting extra . on 1..
if (stream.peek() == "."){
stream.backUp(1);
}
return 'number';
}
// Integers
var intLiteral = false;
// Hex
if (stream.match(/^-?0x[0-9a-f]+/i)) {
intLiteral = true;
}
// Decimal
if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
intLiteral = true;
}
// Zero by itself with no other piece of number.
if (stream.match(/^-?0(?![\dx])/i)) {
intLiteral = true;
}
if (intLiteral) {
return 'number';
}
}
// Handle strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenFactory(stream.current(), 'string');
return state.tokenize(stream, state);
}
// Handle regex literals
if (stream.match(regexPrefixes)) {
if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division
state.tokenize = tokenFactory(stream.current(), 'string-2');
return state.tokenize(stream, state);
} else {
stream.backUp(1);
}
}
// Handle operators and delimiters
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
return 'punctuation';
}
if (stream.match(doubleOperators)
|| stream.match(singleOperators)
|| stream.match(wordOperators)) {
return 'operator';
}
if (stream.match(singleDelimiters)) {
return 'punctuation';
}
if (stream.match(constants)) {
return 'atom';
}
if (stream.match(keywords)) {
return 'keyword';
}
if (stream.match(identifiers)) {
return 'variable';
}
if (stream.match(properties)) {
return 'property';
}
// Handle non-detected items
stream.next();
return ERRORCLASS;
}
function tokenFactory(delimiter, outclass) {
var singleline = delimiter.length == 1;
return 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 (conf.mode.singleLineStringErrors) {
outclass = ERRORCLASS
} else {
state.tokenize = tokenBase;
}
}
return outclass;
};
}
function longComment(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^#]/);
if (stream.match("###")) {
state.tokenize = tokenBase;
break;
}
stream.eatWhile("#");
}
return "comment"
}
function indent(stream, state, type) {
type = type || 'coffee';
var indentUnit = 0;
if (type === 'coffee') {
for (var i = 0; i < state.scopes.length; i++) {
if (state.scopes[i].type === 'coffee') {
indentUnit = state.scopes[i].offset + conf.indentUnit;
break;
}
}
} else {
indentUnit = stream.column() + stream.current().length;
}
state.scopes.unshift({
offset: indentUnit,
type: type
});
}
function dedent(stream, state) {
if (state.scopes.length == 1) return;
if (state.scopes[0].type === 'coffee') {
var _indent = stream.indentation();
var _indent_index = -1;
for (var i = 0; i < state.scopes.length; ++i) {
if (_indent === state.scopes[i].offset) {
_indent_index = i;
break;
}
}
if (_indent_index === -1) {
return true;
}
while (state.scopes[0].offset !== _indent) {
state.scopes.shift();
}
return false
} else {
state.scopes.shift();
return false;
}
}
function tokenLexer(stream, state) {
var style = state.tokenize(stream, state);
var current = stream.current();
// Handle '.' connected identifiers
if (current === '.') {
style = state.tokenize(stream, state);
current = stream.current();
if (style === 'variable') {
return 'variable';
} else {
return ERRORCLASS;
}
}
// Handle scope changes.
if (current === 'return') {
state.dedent += 1;
}
if (((current === '->' || current === '=>') &&
!state.lambda &&
state.scopes[0].type == 'coffee' &&
stream.peek() === '')
|| style === 'indent') {
indent(stream, state);
}
var delimiter_index = '[({'.indexOf(current);
if (delimiter_index !== -1) {
indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
}
if (indentKeywords.exec(current)){
indent(stream, state);
}
if (current == 'then'){
dedent(stream, state);
}
if (style === 'dedent') {
if (dedent(stream, state)) {
return ERRORCLASS;
}
}
delimiter_index = '])}'.indexOf(current);
if (delimiter_index !== -1) {
if (dedent(stream, state)) {
return ERRORCLASS;
}
}
if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
if (state.scopes.length > 1) state.scopes.shift();
state.dedent -= 1;
}
return style;
}
var external = {
startState: function(basecolumn) {
return {
tokenize: tokenBase,
scopes: [{offset:basecolumn || 0, type:'coffee'}],
lastToken: null,
lambda: false,
dedent: 0
};
},
token: function(stream, state) {
var style = tokenLexer(stream, state);
state.lastToken = {style:style, content: stream.current()};
if (stream.eol() && stream.lambda) {
state.lambda = false;
}
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase) {
return 0;
}
return state.scopes[0].offset;
}
};
return external;
});
CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');