1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 14:19:43 +02:00

CodeMirror upgrade to 5.38.0

This commit is contained in:
Harvey Kandola 2018-05-29 18:27:42 +01:00
parent 36be6243ad
commit cfe30dcde5
52 changed files with 905 additions and 413 deletions

View file

@ -25,6 +25,7 @@
} else { // Assuming it's a detached DOM element. } else { // Assuming it's a detached DOM element.
dialog.appendChild(template); dialog.appendChild(template);
} }
CodeMirror.addClass(wrap, 'dialog-opened');
return dialog; return dialog;
} }
@ -47,6 +48,7 @@
} else { } else {
if (closed) return; if (closed) return;
closed = true; closed = true;
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
me.focus(); me.focus();
@ -102,6 +104,7 @@
function close() { function close() {
if (closed) return; if (closed) return;
closed = true; closed = true;
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
me.focus(); me.focus();
} }
@ -141,6 +144,7 @@
if (closed) return; if (closed) return;
closed = true; closed = true;
clearTimeout(doneTimer); clearTimeout(doneTimer);
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened');
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
} }

View file

@ -38,6 +38,7 @@
clearPlaceholder(cm); clearPlaceholder(cm);
var elt = cm.state.placeholder = document.createElement("pre"); var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible"; elt.style.cssText = "height: 0; overflow: visible";
elt.style.direction = cm.getOption("direction");
elt.className = "CodeMirror-placeholder"; elt.className = "CodeMirror-placeholder";
var placeHolder = cm.getOption("placeholder") var placeHolder = cm.getOption("placeholder")
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)

View file

@ -53,13 +53,14 @@
function autoCloseGT(cm) { function autoCloseGT(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var opt = cm.getOption("autoCloseTags");
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass; if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos); var pos = ranges[i].head, tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; var html = inner.mode.configuration == "html";
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
@ -81,13 +82,14 @@
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
} }
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose);
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var info = replacements[i]; var info = replacements[i];
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
var sel = cm.listSelections().slice(0); var sel = cm.listSelections().slice(0);
sel[i] = {head: info.newPos, anchor: info.newPos}; sel[i] = {head: info.newPos, anchor: info.newPos};
cm.setSelections(sel); cm.setSelections(sel);
if (info.indent) { if (!dontIndentOnAutoClose && info.indent) {
cm.indentLine(info.newPos.line, null, true); cm.indentLine(info.newPos.line, null, true);
cm.indentLine(info.newPos.line + 1, null, true); cm.indentLine(info.newPos.line + 1, null, true);
} }
@ -97,6 +99,8 @@
function autoCloseCurrent(cm, typingSlash) { function autoCloseCurrent(cm, typingSlash) {
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var head = typingSlash ? "/" : "</"; var head = typingSlash ? "/" : "</";
var opt = cm.getOption("autoCloseTags");
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash);
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass; if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos); var pos = ranges[i].head, tok = cm.getTokenAt(pos);
@ -127,9 +131,11 @@
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
ranges = cm.listSelections(); ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) if (!dontIndentOnAutoClose) {
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) for (var i = 0; i < ranges.length; i++)
cm.indentLine(ranges[i].head.line); if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
cm.indentLine(ranges[i].head.line);
}
} }
function autoCloseSlash(cm) { function autoCloseSlash(cm) {

View file

@ -39,13 +39,11 @@
replacements[i] = "\n"; replacements[i] = "\n";
} else { } else {
var indent = match[1], after = match[5]; var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
? match[2].replace("x", " ") var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
: (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after; replacements[i] = "\n" + indent + bullet + after;
incrementRemainingMarkdownListNumbers(cm, pos); if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
} }
} }
@ -68,7 +66,7 @@
var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount);
var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber;
if (startIndent === nextIndent) { if (startIndent === nextIndent && !isNaN(nextNumber)) {
if (newNumber === nextNumber) itemNumber = nextNumber + 1; if (newNumber === nextNumber) itemNumber = nextNumber + 1;
if (newNumber > nextNumber) itemNumber = newNumber + 1; if (newNumber > nextNumber) itemNumber = newNumber + 1;
cm.replaceRange( cm.replaceRange(

View file

@ -102,18 +102,23 @@
} }
} }
var currentlyHighlighted = null;
function doMatchBrackets(cm) { function doMatchBrackets(cm) {
cm.operation(function() { cm.operation(function() {
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} if (cm.state.matchBrackets.currentlyHighlighted) {
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
}); });
} }
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets); cm.off("cursorActivity", doMatchBrackets);
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
} }
if (val) { if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.state.matchBrackets = typeof val == "object" ? val : {};

View file

@ -137,12 +137,14 @@
CodeMirror.registerHelper("fold", "xml", function(cm, start) { CodeMirror.registerHelper("fold", "xml", function(cm, start) {
var iter = new Iter(cm, start.line, 0); var iter = new Iter(cm, start.line, 0);
for (;;) { for (;;) {
var openTag = toNextTag(iter), end; var openTag = toNextTag(iter)
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; if (!openTag || iter.line != start.line) return
var end = toTagEnd(iter)
if (!end) return
if (!openTag[1] && end != "selfClose") { if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch); var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]); var endPos = findMatchingClose(iter, openTag[2]);
return endPos && {from: startPos, to: endPos.from}; return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null
} }
} }
}); });

View file

@ -32,7 +32,9 @@
// Find the token at the cursor // Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur); var cur = editor.getCursor(), token = getToken(editor, cur);
if (/\b(?:string|comment)\b/.test(token.type)) return; if (/\b(?:string|comment)\b/.test(token.type)) return;
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; var innerMode = CodeMirror.innerMode(editor.getMode(), token.state);
if (innerMode.mode.helperType === "json") return;
token.state = innerMode.state;
// If it's not a 'word-style' token, ignore the token. // If it's not a 'word-style' token, ignore the token.
if (!/^[\w$_]*$/.test(token.string)) { if (!/^[\w$_]*$/.test(token.string)) {
@ -92,8 +94,8 @@
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
var funcProps = "prototype apply call bind".split(" "); var funcProps = "prototype apply call bind".split(" ");
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " +
"if in instanceof new null return switch throw true try typeof var void while with").split(" "); "if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" ");
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");

View file

@ -333,7 +333,7 @@
i = avoidWrap ? 0 : this.data.list.length - 1; i = avoidWrap ? 0 : this.data.list.length - 1;
if (this.selectedHint == i) return; if (this.selectedHint == i) return;
var node = this.hints.childNodes[this.selectedHint]; var node = this.hints.childNodes[this.selectedHint];
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
node = this.hints.childNodes[this.selectedHint = i]; node = this.hints.childNodes[this.selectedHint = i];
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
if (node.offsetTop < this.hints.scrollTop) if (node.offsetTop < this.hints.scrollTop)
@ -397,12 +397,13 @@
}); });
CodeMirror.registerHelper("hint", "fromList", function(cm, options) { CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
var cur = cm.getCursor(), token = cm.getTokenAt(cur); var cur = cm.getCursor(), token = cm.getTokenAt(cur)
var to = CodeMirror.Pos(cur.line, token.end); var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
if (token.string && /\w/.test(token.string[token.string.length - 1])) { if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
var term = token.string, from = CodeMirror.Pos(cur.line, token.start); term = token.string.substr(0, cur.ch - token.start)
} else { } else {
var term = "", from = to; term = ""
from = cur
} }
var found = []; var found = [];
for (var i = 0; i < options.words.length; i++) { for (var i = 0; i < options.words.length; i++) {

View file

@ -222,18 +222,20 @@
prevItem = separator[i]; prevItem = separator[i];
} }
var query = doc.getRange(validRange.start, validRange.end, false); if (validRange.start) {
var query = doc.getRange(validRange.start, validRange.end, false);
for (var i = 0; i < query.length; i++) { for (var i = 0; i < query.length; i++) {
var lineText = query[i]; var lineText = query[i];
eachWord(lineText, function(word) { eachWord(lineText, function(word) {
var wordUpperCase = word.toUpperCase(); var wordUpperCase = word.toUpperCase();
if (wordUpperCase === aliasUpperCase && getTable(previousWord)) if (wordUpperCase === aliasUpperCase && getTable(previousWord))
table = previousWord; table = previousWord;
if (wordUpperCase !== CONS.ALIAS_KEYWORD) if (wordUpperCase !== CONS.ALIAS_KEYWORD)
previousWord = word; previousWord = word;
}); });
if (table) break; if (table) break;
}
} }
return table; return table;
} }
@ -273,10 +275,23 @@
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) { if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
start = nameCompletion(cur, token, result, editor); start = nameCompletion(cur, token, result, editor);
} else { } else {
addMatches(result, search, tables, function(w) {return w;}); addMatches(result, search, defaultTable, function(w) {return {text:w, className: "CodeMirror-hint-table CodeMirror-hint-default-table"};});
addMatches(result, search, defaultTable, function(w) {return w;}); addMatches(
result,
search,
tables,
function(w) {
if (typeof w === 'object') {
w.className = "CodeMirror-hint-table";
} else {
w = {text: w, className: "CodeMirror-hint-table"};
}
return w;
}
);
if (!disableKeywords) if (!disableKeywords)
addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); addMatches(result, search, keywords, function(w) {return {text: w.toUpperCase(), className: "CodeMirror-hint-keyword"};});
} }
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};

View file

@ -12,15 +12,6 @@
"use strict"; "use strict";
// declare global: JSHINT // declare global: JSHINT
var bogus = [ "Dangerous comment" ];
var warnings = [ [ "Expected '{'",
"Statement body should be inside '{ }' braces." ] ];
var errors = [ "Missing semicolon", "Extra comma", "Missing property name",
"Unmatched ", " and instead saw", " is not defined",
"Unclosed string", "Stopping, unable to continue" ];
function validator(text, options) { function validator(text, options) {
if (!window.JSHINT) { if (!window.JSHINT) {
if (window.console) { if (window.console) {
@ -28,6 +19,8 @@
} }
return []; return [];
} }
if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation
options.indent = 1; // JSHint default value is 4
JSHINT(text, options, options.globals); JSHINT(text, options, options.globals);
var errors = JSHINT.data().errors, result = []; var errors = JSHINT.data().errors, result = [];
if (errors) parseErrors(errors, result); if (errors) parseErrors(errors, result);
@ -36,105 +29,34 @@
CodeMirror.registerHelper("lint", "javascript", validator); CodeMirror.registerHelper("lint", "javascript", validator);
function cleanup(error) {
// All problems are warnings by default
fixWith(error, warnings, "warning", true);
fixWith(error, errors, "error");
return isBogus(error) ? null : error;
}
function fixWith(error, fixes, severity, force) {
var description, fix, find, replace, found;
description = error.description;
for ( var i = 0; i < fixes.length; i++) {
fix = fixes[i];
find = (typeof fix === "string" ? fix : fix[0]);
replace = (typeof fix === "string" ? null : fix[1]);
found = description.indexOf(find) !== -1;
if (force || found) {
error.severity = severity;
}
if (found && replace) {
error.description = replace;
}
}
}
function isBogus(error) {
var description = error.description;
for ( var i = 0; i < bogus.length; i++) {
if (description.indexOf(bogus[i]) !== -1) {
return true;
}
}
return false;
}
function parseErrors(errors, output) { function parseErrors(errors, output) {
for ( var i = 0; i < errors.length; i++) { for ( var i = 0; i < errors.length; i++) {
var error = errors[i]; var error = errors[i];
if (error) { if (error) {
var linetabpositions, index; if (error.line <= 0) {
if (window.console) {
linetabpositions = []; window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error);
// This next block is to fix a problem in jshint. Jshint
// replaces
// all tabs with spaces then performs some checks. The error
// positions (character/space) are then reported incorrectly,
// not taking the replacement step into account. Here we look
// at the evidence line and try to adjust the character position
// to the correct value.
if (error.evidence) {
// Tab positions are computed once per line and cached
var tabpositions = linetabpositions[error.line];
if (!tabpositions) {
var evidence = error.evidence;
tabpositions = [];
// ugggh phantomjs does not like this
// forEachChar(evidence, function(item, index) {
Array.prototype.forEach.call(evidence, function(item,
index) {
if (item === '\t') {
// First col is 1 (not 0) to match error
// positions
tabpositions.push(index + 1);
}
});
linetabpositions[error.line] = tabpositions;
}
if (tabpositions.length > 0) {
var pos = error.character;
tabpositions.forEach(function(tabposition) {
if (pos > tabposition) pos -= 1;
});
error.character = pos;
} }
continue;
} }
var start = error.character - 1, end = start + 1; var start = error.character - 1, end = start + 1;
if (error.evidence) { if (error.evidence) {
index = error.evidence.substring(start).search(/.\b/); var index = error.evidence.substring(start).search(/.\b/);
if (index > -1) { if (index > -1) {
end += index; end += index;
} }
} }
// Convert to format expected by validation service // Convert to format expected by validation service
error.description = error.reason;// + "(jshint)"; var hint = {
error.start = error.character; message: error.reason,
error.end = end; severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error",
error = cleanup(error); from: CodeMirror.Pos(error.line - 1, start),
to: CodeMirror.Pos(error.line - 1, end)
};
if (error) output.push(hint);
output.push({message: error.description,
severity: error.severity,
from: CodeMirror.Pos(error.line - 1, start),
to: CodeMirror.Pos(error.line - 1, end)});
} }
} }
} }

View file

@ -23,6 +23,9 @@ CodeMirror.registerHelper("lint", "json", function(text) {
} }
return found; return found;
} }
// for jsonlint's web dist jsonlint is exported as an object with a single property parser, of which parseError
// is a subproperty
var jsonlint = window.jsonlint.parser || window.jsonlint
jsonlint.parseError = function(str, hash) { jsonlint.parseError = function(str, hash) {
var loc = hash.loc; var loc = hash.loc;
found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),

View file

@ -132,7 +132,7 @@
cm.off("change", abort) cm.off("change", abort)
if (state.waitingFor != id) return if (state.waitingFor != id) return
if (arg2 && annotations instanceof CodeMirror) annotations = arg2 if (arg2 && annotations instanceof CodeMirror) annotations = arg2
updateLinting(cm, annotations) cm.operation(function() {updateLinting(cm, annotations)})
}, passOptions, cm); }, passOptions, cm);
} }
@ -151,9 +151,9 @@
var annotations = getAnnotations(cm.getValue(), passOptions, cm); var annotations = getAnnotations(cm.getValue(), passOptions, cm);
if (!annotations) return; if (!annotations) return;
if (annotations.then) annotations.then(function(issues) { if (annotations.then) annotations.then(function(issues) {
updateLinting(cm, issues); cm.operation(function() {updateLinting(cm, issues)})
}); });
else updateLinting(cm, annotations); else cm.operation(function() {updateLinting(cm, annotations)})
} }
} }

View file

@ -48,6 +48,12 @@
color: #555; color: #555;
line-height: 1; line-height: 1;
} }
.CodeMirror-merge-scrolllock:after {
content: "\21db\00a0\00a0\21da";
}
.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after {
content: "\21db\21da";
}
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { .CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
position: absolute; position: absolute;

View file

@ -211,7 +211,7 @@
function setScrollLock(dv, val, action) { function setScrollLock(dv, val, action) {
dv.lockScroll = val; dv.lockScroll = val;
if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db&nbsp;&nbsp;\u21da"; (val ? CodeMirror.addClass : CodeMirror.rmClass)(dv.lockButton, "CodeMirror-merge-scrolllock-enabled");
} }
// Updating the marks for editor content // Updating the marks for editor content
@ -664,6 +664,7 @@
function getChunks(diff) { function getChunks(diff) {
var chunks = []; var chunks = [];
if (!diff.length) return chunks;
var startEdit = 0, startOrig = 0; var startEdit = 0, startOrig = 0;
var edit = Pos(0, 0), orig = Pos(0, 0); var edit = Pos(0, 0), orig = Pos(0, 0);
for (var i = 0; i < diff.length; ++i) { for (var i = 0; i < diff.length; ++i) {

View file

@ -50,7 +50,15 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
if (found == stream.pos) { if (found == stream.pos) {
if (!other.parseDelimiters) stream.match(other.open); if (!other.parseDelimiters) stream.match(other.open);
state.innerActive = other; state.innerActive = other;
state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
// Get the outer indent, making sure to handle CodeMirror.Pass
var outerIndent = 0;
if (outer.indent) {
var possibleOuterIndent = outer.indent(state.outer, "");
if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent;
}
state.inner = CodeMirror.startState(other.mode, outerIndent);
return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open"); return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
} else if (found != -1 && found < cutOff) { } else if (found != -1 && found < cutOff) {
cutOff = found; cutOff = found;

View file

@ -90,7 +90,7 @@
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false, state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"}); {className: "CodeMirror-selection-highlight-scrollbar"});
} }

View file

@ -19,8 +19,11 @@
+ (regexp.multiline ? "m" : "") + (regexp.multiline ? "m" : "")
} }
function ensureGlobal(regexp) { function ensureFlags(regexp, flags) {
return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g") var current = regexpFlags(regexp), target = current
for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
target += flags.charAt(i)
return current == target ? regexp : new RegExp(regexp.source, target)
} }
function maybeMultiline(regexp) { function maybeMultiline(regexp) {
@ -28,7 +31,7 @@
} }
function searchRegexpForward(doc, regexp, start) { function searchRegexpForward(doc, regexp, start) {
regexp = ensureGlobal(regexp) regexp = ensureFlags(regexp, "g")
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
regexp.lastIndex = ch regexp.lastIndex = ch
var string = doc.getLine(line), match = regexp.exec(string) var string = doc.getLine(line), match = regexp.exec(string)
@ -42,7 +45,7 @@
function searchRegexpForwardMultiline(doc, regexp, start) { function searchRegexpForwardMultiline(doc, regexp, start) {
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
regexp = ensureGlobal(regexp) regexp = ensureFlags(regexp, "gm")
var string, chunk = 1 var string, chunk = 1
for (var line = start.line, last = doc.lastLine(); line <= last;) { for (var line = start.line, last = doc.lastLine(); line <= last;) {
// This grows the search buffer in exponentially-sized chunks // This grows the search buffer in exponentially-sized chunks
@ -51,6 +54,7 @@
// searching for something that has tons of matches), but at the // searching for something that has tons of matches), but at the
// same time, the amount of retries is limited. // same time, the amount of retries is limited.
for (var i = 0; i < chunk; i++) { for (var i = 0; i < chunk; i++) {
if (line > last) break
var curLine = doc.getLine(line++) var curLine = doc.getLine(line++)
string = string == null ? curLine : string + "\n" + curLine string = string == null ? curLine : string + "\n" + curLine
} }
@ -81,7 +85,7 @@
} }
function searchRegexpBackward(doc, regexp, start) { function searchRegexpBackward(doc, regexp, start) {
regexp = ensureGlobal(regexp) regexp = ensureFlags(regexp, "g")
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
var string = doc.getLine(line) var string = doc.getLine(line)
if (ch > -1) string = string.slice(0, ch) if (ch > -1) string = string.slice(0, ch)
@ -94,7 +98,7 @@
} }
function searchRegexpBackwardMultiline(doc, regexp, start) { function searchRegexpBackwardMultiline(doc, regexp, start) {
regexp = ensureGlobal(regexp) regexp = ensureFlags(regexp, "gm")
var string, chunk = 1 var string, chunk = 1
for (var line = start.line, first = doc.firstLine(); line >= first;) { for (var line = start.line, first = doc.firstLine(); line >= first;) {
for (var i = 0; i < chunk; i++) { for (var i = 0; i < chunk; i++) {
@ -213,7 +217,7 @@
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
} }
} else { } else {
query = ensureGlobal(query) query = ensureFlags(query, "gm")
if (!options || options.multiline !== false) if (!options || options.multiline !== false)
this.matches = function(reverse, pos) { this.matches = function(reverse, pos) {
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)

View file

@ -614,7 +614,8 @@
var mouseOnTip = false, old = false; var mouseOnTip = false, old = false;
CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; });
CodeMirror.on(tip, "mouseout", function(e) { CodeMirror.on(tip, "mouseout", function(e) {
if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) { var related = e.relatedTarget || e.toElement
if (!related || !CodeMirror.contains(tip, related)) {
if (old) clear(); if (old) clear();
else mouseOnTip = false; else mouseOnTip = false;
} }

118
gui/public/codemirror/lib/codemirror.js vendored Executable file → Normal file
View file

@ -746,6 +746,16 @@ function collapsedSpanAtSide(line, start) {
function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
function collapsedSpanAround(line, ch) {
var sps = sawCollapsedSpans && line.markedSpans, found
if (sps) { for (var i = 0; i < sps.length; ++i) {
var sp = sps[i]
if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
(!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker }
} }
return found
}
// Test whether there exists a collapsed span that partially // Test whether there exists a collapsed span that partially
// overlaps (covers the start or end, but not both) of a new span. // overlaps (covers the start or end, but not both) of a new span.
// Such overlap is not allowed. // Such overlap is not allowed.
@ -2778,12 +2788,11 @@ function coordsChar(cm, x, y) {
var lineObj = getLine(doc, lineN) var lineObj = getLine(doc, lineN)
for (;;) { for (;;) {
var found = coordsCharInner(cm, lineObj, lineN, x, y) var found = coordsCharInner(cm, lineObj, lineN, x, y)
var merged = collapsedSpanAtEnd(lineObj) var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0))
var mergedPos = merged && merged.find(0, true) if (!collapsed) { return found }
if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) var rangeEnd = collapsed.find(1)
{ lineN = lineNo(lineObj = mergedPos.to.line) } if (rangeEnd.line == lineN) { return rangeEnd }
else lineObj = getLine(doc, lineN = rangeEnd.line)
{ return found }
} }
} }
@ -3543,6 +3552,7 @@ var NativeScrollbars = function(place, scroll, cm) {
this.cm = cm this.cm = cm
var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
vert.tabIndex = horiz.tabIndex = -1
place(vert); place(horiz) place(vert); place(horiz)
on(vert, "scroll", function () { on(vert, "scroll", function () {
@ -4783,7 +4793,7 @@ function addChangeToHistory(doc, change, selAfter, opId) {
if ((hist.lastOp == opId || if ((hist.lastOp == opId ||
hist.lastOrigin == change.origin && change.origin && hist.lastOrigin == change.origin && change.origin &&
((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
change.origin.charAt(0) == "*")) && change.origin.charAt(0) == "*")) &&
(cur = lastChangeEvent(hist, hist.lastOp == opId))) { (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
// Merge this change into the last event // Merge this change into the last event
@ -5212,7 +5222,8 @@ function makeChangeInner(doc, change) {
// Revert a change stored in a document's history. // Revert a change stored in a document's history.
function makeChangeFromHistory(doc, type, allowSelectionOnly) { function makeChangeFromHistory(doc, type, allowSelectionOnly) {
if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return } var suppress = doc.cm && doc.cm.state.suppressEdits
if (suppress && !allowSelectionOnly) { return }
var hist = doc.history, event, selAfter = doc.sel var hist = doc.history, event, selAfter = doc.sel
var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done
@ -5237,8 +5248,10 @@ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
return return
} }
selAfter = event selAfter = event
} } else if (suppress) {
else { break } source.push(event)
return
} else { break }
} }
// Build up a reverse change object to add to the opposite history // Build up a reverse change object to add to the opposite history
@ -5714,7 +5727,7 @@ function addLineWidget(doc, handle, node, options) {
} }
return true return true
}) })
signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) }
return widget return widget
} }
@ -6573,11 +6586,11 @@ function onResize(cm) {
} }
var keyNames = { var keyNames = {
3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
@ -6724,6 +6737,9 @@ function keyName(event, noShift) {
if (presto && event.keyCode == 34 && event["char"]) { return false } if (presto && event.keyCode == 34 && event["char"]) { return false }
var name = keyNames[event.keyCode] var name = keyNames[event.keyCode]
if (name == null || event.altGraphKey) { return false } if (name == null || event.altGraphKey) { return false }
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
if (event.keyCode == 3 && event.code) { name = event.code }
return addModifierNames(name, event, noShift) return addModifierNames(name, event, noShift)
} }
@ -7306,8 +7322,8 @@ function leftButtonStartDrag(cm, event, pos, behavior) {
var dragEnd = operation(cm, function (e) { var dragEnd = operation(cm, function (e) {
if (webkit) { display.scroller.draggable = false } if (webkit) { display.scroller.draggable = false }
cm.state.draggingText = false cm.state.draggingText = false
off(document, "mouseup", dragEnd) off(display.wrapper.ownerDocument, "mouseup", dragEnd)
off(document, "mousemove", mouseMove) off(display.wrapper.ownerDocument, "mousemove", mouseMove)
off(display.scroller, "dragstart", dragStart) off(display.scroller, "dragstart", dragStart)
off(display.scroller, "drop", dragEnd) off(display.scroller, "drop", dragEnd)
if (!moved) { if (!moved) {
@ -7316,7 +7332,7 @@ function leftButtonStartDrag(cm, event, pos, behavior) {
{ extendSelection(cm.doc, pos, null, null, behavior.extend) } { extendSelection(cm.doc, pos, null, null, behavior.extend) }
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
if (webkit || ie && ie_version == 9) if (webkit || ie && ie_version == 9)
{ setTimeout(function () {document.body.focus(); display.input.focus()}, 20) } { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus()}, 20) }
else else
{ display.input.focus() } { display.input.focus() }
} }
@ -7331,8 +7347,8 @@ function leftButtonStartDrag(cm, event, pos, behavior) {
dragEnd.copy = !behavior.moveOnDrag dragEnd.copy = !behavior.moveOnDrag
// IE's approach to draggable // IE's approach to draggable
if (display.scroller.dragDrop) { display.scroller.dragDrop() } if (display.scroller.dragDrop) { display.scroller.dragDrop() }
on(document, "mouseup", dragEnd) on(display.wrapper.ownerDocument, "mouseup", dragEnd)
on(document, "mousemove", mouseMove) on(display.wrapper.ownerDocument, "mousemove", mouseMove)
on(display.scroller, "dragstart", dragStart) on(display.scroller, "dragstart", dragStart)
on(display.scroller, "drop", dragEnd) on(display.scroller, "drop", dragEnd)
@ -7464,19 +7480,19 @@ function leftButtonSelect(cm, event, start, behavior) {
counter = Infinity counter = Infinity
e_preventDefault(e) e_preventDefault(e)
display.input.focus() display.input.focus()
off(document, "mousemove", move) off(display.wrapper.ownerDocument, "mousemove", move)
off(document, "mouseup", up) off(display.wrapper.ownerDocument, "mouseup", up)
doc.history.lastSelOrigin = null doc.history.lastSelOrigin = null
} }
var move = operation(cm, function (e) { var move = operation(cm, function (e) {
if (!e_button(e)) { done(e) } if (e.buttons === 0 || !e_button(e)) { done(e) }
else { extend(e) } else { extend(e) }
}) })
var up = operation(cm, done) var up = operation(cm, done)
cm.state.selectingText = up cm.state.selectingText = up
on(document, "mousemove", move) on(display.wrapper.ownerDocument, "mousemove", move)
on(document, "mouseup", up) on(display.wrapper.ownerDocument, "mouseup", up)
} }
// Used when mouse-selecting to adjust the anchor to the proper side // Used when mouse-selecting to adjust the anchor to the proper side
@ -7606,6 +7622,7 @@ function defineOptions(CodeMirror) {
clearCaches(cm) clearCaches(cm)
regChange(cm) regChange(cm)
}, true) }, true)
option("lineSeparator", null, function (cm, val) { option("lineSeparator", null, function (cm, val) {
cm.doc.lineSep = val cm.doc.lineSep = val
if (!val) { return } if (!val) { return }
@ -8012,7 +8029,7 @@ function applyTextInput(cm, inserted, deleted, sel, origin) {
var paste = cm.state.pasteIncoming || origin == "paste" var paste = cm.state.pasteIncoming || origin == "paste"
var textLines = splitLinesAuto(inserted), multiPaste = null var textLines = splitLinesAuto(inserted), multiPaste = null
// When pasing N lines into N selections, insert one line per selection // When pasting N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) { if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.text.join("\n") == inserted) { if (lastCopied && lastCopied.text.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.text.length == 0) { if (sel.ranges.length % lastCopied.text.length == 0) {
@ -8748,8 +8765,12 @@ ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
this.showMultipleSelections(info) this.showMultipleSelections(info)
}; };
ContentEditableInput.prototype.getSelection = function () {
return this.cm.display.wrapper.ownerDocument.getSelection()
};
ContentEditableInput.prototype.showPrimarySelection = function () { ContentEditableInput.prototype.showPrimarySelection = function () {
var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary()
var from = prim.from(), to = prim.to() var from = prim.from(), to = prim.to()
if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
@ -8816,13 +8837,13 @@ ContentEditableInput.prototype.showMultipleSelections = function (info) {
}; };
ContentEditableInput.prototype.rememberSelection = function () { ContentEditableInput.prototype.rememberSelection = function () {
var sel = window.getSelection() var sel = this.getSelection()
this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
}; };
ContentEditableInput.prototype.selectionInEditor = function () { ContentEditableInput.prototype.selectionInEditor = function () {
var sel = window.getSelection() var sel = this.getSelection()
if (!sel.rangeCount) { return false } if (!sel.rangeCount) { return false }
var node = sel.getRangeAt(0).commonAncestorContainer var node = sel.getRangeAt(0).commonAncestorContainer
return contains(this.div, node) return contains(this.div, node)
@ -8857,14 +8878,14 @@ ContentEditableInput.prototype.receivedFocus = function () {
}; };
ContentEditableInput.prototype.selectionChanged = function () { ContentEditableInput.prototype.selectionChanged = function () {
var sel = window.getSelection() var sel = this.getSelection()
return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
}; };
ContentEditableInput.prototype.pollSelection = function () { ContentEditableInput.prototype.pollSelection = function () {
if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
var sel = window.getSelection(), cm = this.cm var sel = this.getSelection(), cm = this.cm
// On Android Chrome (version 56, at least), backspacing into an // On Android Chrome (version 56, at least), backspacing into an
// uneditable block element will put the cursor in that element, // uneditable block element will put the cursor in that element,
// and then, because it's not editable, hide the virtual keyboard. // and then, because it's not editable, hide the virtual keyboard.
@ -8998,7 +9019,7 @@ ContentEditableInput.prototype.setUneditable = function (node) {
}; };
ContentEditableInput.prototype.onKeyPress = function (e) { ContentEditableInput.prototype.onKeyPress = function (e) {
if (e.charCode == 0) { return } if (e.charCode == 0 || this.composing) { return }
e.preventDefault() e.preventDefault()
if (!this.cm.isReadOnly()) if (!this.cm.isReadOnly())
{ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) } { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }
@ -9038,12 +9059,13 @@ function isInGutter(node) {
function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
function domTextBetween(cm, from, to, fromLine, toLine) { function domTextBetween(cm, from, to, fromLine, toLine) {
var text = "", closing = false, lineSep = cm.doc.lineSeparator() var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false
function recognizeMarker(id) { return function (marker) { return marker.id == id; } } function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
function close() { function close() {
if (closing) { if (closing) {
text += lineSep text += lineSep
closing = false if (extraLinebreak) { text += lineSep }
closing = extraLinebreak = false
} }
} }
function addText(str) { function addText(str) {
@ -9055,8 +9077,8 @@ function domTextBetween(cm, from, to, fromLine, toLine) {
function walk(node) { function walk(node) {
if (node.nodeType == 1) { if (node.nodeType == 1) {
var cmText = node.getAttribute("cm-text") var cmText = node.getAttribute("cm-text")
if (cmText != null) { if (cmText) {
addText(cmText || node.textContent.replace(/\u200b/g, "")) addText(cmText)
return return
} }
var markerID = node.getAttribute("cm-marker"), range var markerID = node.getAttribute("cm-marker"), range
@ -9067,19 +9089,24 @@ function domTextBetween(cm, from, to, fromLine, toLine) {
return return
} }
if (node.getAttribute("contenteditable") == "false") { return } if (node.getAttribute("contenteditable") == "false") { return }
var isBlock = /^(pre|div|p)$/i.test(node.nodeName) var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName)
if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
if (isBlock) { close() } if (isBlock) { close() }
for (var i = 0; i < node.childNodes.length; i++) for (var i = 0; i < node.childNodes.length; i++)
{ walk(node.childNodes[i]) } { walk(node.childNodes[i]) }
if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true }
if (isBlock) { closing = true } if (isBlock) { closing = true }
} else if (node.nodeType == 3) { } else if (node.nodeType == 3) {
addText(node.nodeValue) addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "))
} }
} }
for (;;) { for (;;) {
walk(from) walk(from)
if (from == to) { break } if (from == to) { break }
from = from.nextSibling from = from.nextSibling
extraLinebreak = false
} }
return text return text
} }
@ -9180,13 +9207,10 @@ TextareaInput.prototype.init = function (display) {
var this$1 = this; var this$1 = this;
var input = this, cm = this.cm var input = this, cm = this.cm
this.createField(display)
var te = this.textarea
// Wraps and hides input textarea display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild)
var div = this.wrapper = hiddenTextarea()
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
var te = this.textarea = div.firstChild
display.wrapper.insertBefore(div, display.wrapper.firstChild)
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
if (ios) { te.style.width = "0px" } if (ios) { te.style.width = "0px" }
@ -9253,6 +9277,14 @@ TextareaInput.prototype.init = function (display) {
}) })
}; };
TextareaInput.prototype.createField = function (_display) {
// Wraps and hides input textarea
this.wrapper = hiddenTextarea()
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
this.textarea = this.wrapper.firstChild
};
TextareaInput.prototype.prepareSelection = function () { TextareaInput.prototype.prepareSelection = function () {
// Redraw the selection and/or cursor // Redraw the selection and/or cursor
var cm = this.cm, display = cm.display, doc = cm.doc var cm = this.cm, display = cm.display, doc = cm.doc
@ -9646,7 +9678,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror) addLegacyProps(CodeMirror)
CodeMirror.version = "5.32.0" CodeMirror.version = "5.38.0"
return CodeMirror; return CodeMirror;

View file

@ -374,7 +374,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
blockKeywords: words("case do else for if switch while struct"), blockKeywords: words("case do else for if switch while struct"),
defKeywords: words("struct"), defKeywords: words("struct"),
typeFirstDefinitions: true, typeFirstDefinitions: true,
atoms: words("null true false"), atoms: words("NULL true false"),
hooks: {"#": cppHook, "*": pointerHook}, hooks: {"#": cppHook, "*": pointerHook},
modeProps: {fold: ["brace", "include"]} modeProps: {fold: ["brace", "include"]}
}); });
@ -390,7 +390,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
blockKeywords: words("catch class do else finally for if struct switch try while"), blockKeywords: words("catch class do else finally for if struct switch try while"),
defKeywords: words("class namespace struct enum union"), defKeywords: words("class namespace struct enum union"),
typeFirstDefinitions: true, typeFirstDefinitions: true,
atoms: words("true false null"), atoms: words("true false NULL"),
dontIndentStatements: /^template$/, dontIndentStatements: /^template$/,
isIdentifierChar: /[\w\$_~\xa1-\uffff]/, isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
hooks: { hooks: {
@ -489,6 +489,27 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "string"; return "string";
} }
function tokenNestedComment(depth) {
return function (stream, state) {
var ch
while (ch = stream.next()) {
if (ch == "*" && stream.eat("/")) {
if (depth == 1) {
state.tokenize = null
break
} else {
state.tokenize = tokenNestedComment(depth - 1)
return state.tokenize(stream, state)
}
} else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenNestedComment(depth + 1)
return state.tokenize(stream, state)
}
}
return "comment"
}
}
def("text/x-scala", { def("text/x-scala", {
name: "clike", name: "clike",
keywords: words( keywords: words(
@ -544,6 +565,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
} else { } else {
return false return false
} }
},
"/": function(stream, state) {
if (!stream.eat("*")) return false
state.tokenize = tokenNestedComment(1)
return state.tokenize(stream, state)
} }
}, },
modeProps: {closeBrackets: {triples: '"'}} modeProps: {closeBrackets: {triples: '"'}}
@ -570,31 +597,37 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
name: "clike", name: "clike",
keywords: words( keywords: words(
/*keywords*/ /*keywords*/
"package as typealias class interface this super val " + "package as typealias class interface this super val operator " +
"var fun for is in This throw return " + "var fun for is in This throw return annotation " +
"break continue object if else while do try when !in !is as? " + "break continue object if else while do try when !in !is as? " +
/*soft keywords*/ /*soft keywords*/
"file import where by get set abstract enum open inner override private public internal " + "file import where by get set abstract enum open inner override private public internal " +
"protected catch finally out final vararg reified dynamic companion constructor init " + "protected catch finally out final vararg reified dynamic companion constructor init " +
"sealed field property receiver param sparam lateinit data inline noinline tailrec " + "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
"external annotation crossinline const operator infix suspend" "external annotation crossinline const operator infix suspend actual expect setparam"
), ),
types: words( types: words(
/* package java.lang */ /* package java.lang */
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
"ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
"LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
), ),
intendSwitch: false, intendSwitch: false,
indentStatements: false, indentStatements: false,
multiLineStrings: true, multiLineStrings: true,
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
blockKeywords: words("catch class do else finally for if where try while enum"), blockKeywords: words("catch class do else finally for if where try while enum"),
defKeywords: words("class val var object interface fun"), defKeywords: words("class val var object interface fun"),
atoms: words("true false null this"), atoms: words("true false null this"),
hooks: { hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
},
'"': function(stream, state) { '"': function(stream, state) {
state.tokenize = tokenKotlinString(stream.match('""')); state.tokenize = tokenKotlinString(stream.match('""'));
return state.tokenize(stream, state); return state.tokenize(stream, state);

View file

@ -56,4 +56,14 @@
MTCPP("ctor_dtor", MTCPP("ctor_dtor",
"[def Foo::Foo]() {}", "[def Foo::Foo]() {}",
"[def Foo::~Foo]() {}"); "[def Foo::~Foo]() {}");
var mode_scala = CodeMirror.getMode({indentUnit: 2}, "text/x-scala");
function MTSCALA(name) { test.mode("scala_" + name, mode_scala, Array.prototype.slice.call(arguments, 1)); }
MTSCALA("nested_comments",
"[comment /*]",
"[comment But wait /* this is a nested comment */ for real]",
"[comment /**** let * me * show * you ****/]",
"[comment ///// let / me / show / you /////]",
"[comment */]");
})(); })();

View file

@ -77,9 +77,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return ret("qualifier", "qualifier"); return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) { } else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch); return ret(null, ch);
} else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) || } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
(ch == "d" && stream.match("omain(")) || ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
(ch == "r" && stream.match("egexp("))) { ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
stream.backUp(1); stream.backUp(1);
state.tokenize = tokenParenthesized; state.tokenize = tokenParenthesized;
return ret("property", "word"); return ret("property", "word");
@ -162,16 +162,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return pushContext(state, stream, "block"); return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) { } else if (type == "}" && state.context.prev) {
return popContext(state); return popContext(state);
} else if (supportsAtComponent && /@component/.test(type)) { } else if (supportsAtComponent && /@component/i.test(type)) {
return pushContext(state, stream, "atComponentBlock"); return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/.test(type)) { } else if (/^@(-moz-)?document$/i.test(type)) {
return pushContext(state, stream, "documentTypes"); return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) { } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
return pushContext(state, stream, "atBlock"); return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/.test(type)) { } else if (/^@(font-face|counter-style)/i.test(type)) {
state.stateArg = type; state.stateArg = type;
return "restricted_atBlock_before"; return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
return "keyframes"; return "keyframes";
} else if (type && type.charAt(0) == "@") { } else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at"); return pushContext(state, stream, "at");
@ -793,7 +793,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
}, },
"@": function(stream) { "@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"]; if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
stream.eatWhile(/[\w\\\-]/); stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false)) if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"]; return ["variable-2", "variable-definition"];

View file

@ -24,6 +24,9 @@
MT("atMediaUnknownFeatureValueKeyword", MT("atMediaUnknownFeatureValueKeyword",
"[def @media] ([property orientation]: [error upsidedown]) { }"); "[def @media] ([property orientation]: [error upsidedown]) { }");
MT("atMediaUppercase",
"[def @MEDIA] ([property orienTAtion]: [keyword landScape]) { }");
MT("tagSelector", MT("tagSelector",
"[tag foo] { }"); "[tag foo] { }");

View file

@ -197,13 +197,14 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) {
"\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>"); "\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>");
setType("builtin")( setType("builtin")(
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<", "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<*", "<=",
"==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**"); "<$>", "<*>", "=<<", "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*",
"*>", "**");
setType("builtin")( setType("builtin")(
"Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq", "Applicative", "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum",
"False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT", "Eq", "False", "FilePath", "Float", "Floating", "Fractional", "Functor",
"IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left", "GT", "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
"Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read", "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
"ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS", "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
"String", "True"); "String", "True");
@ -223,7 +224,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) {
"lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map", "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
"mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound", "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
"minimum", "mod", "negate", "not", "notElem", "null", "odd", "or", "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
"otherwise", "pi", "pred", "print", "product", "properFraction", "otherwise", "pi", "pred", "print", "product", "properFraction", "pure",
"putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile", "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
"readIO", "readList", "readLn", "readParen", "reads", "readsPrec", "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
"realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse", "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",

View file

@ -14,7 +14,16 @@
"use strict"; "use strict";
CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
var closeComment = parserConfig.closeComment || "--%>"
return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), { return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), {
open: parserConfig.openComment || "<%--",
close: closeComment,
delimStyle: "comment",
mode: {token: function(stream) {
stream.skipTo(closeComment) || stream.skipToEnd()
return "comment"
}}
}, {
open: parserConfig.open || parserConfig.scriptStartRegex || "<%", open: parserConfig.open || parserConfig.scriptStartRegex || "<%",
close: parserConfig.close || parserConfig.scriptEndRegex || "%>", close: parserConfig.close || parserConfig.scriptEndRegex || "%>",
mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec) mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec)

View file

@ -80,7 +80,7 @@ option.</p>
<li><a href="javascript/index.html">JavaScript</a> (<a href="jsx/index.html">JSX</a>)</li> <li><a href="javascript/index.html">JavaScript</a> (<a href="jsx/index.html">JSX</a>)</li>
<li><a href="jinja2/index.html">Jinja2</a></li> <li><a href="jinja2/index.html">Jinja2</a></li>
<li><a href="julia/index.html">Julia</a></li> <li><a href="julia/index.html">Julia</a></li>
<li><a href="kotlin/index.html">Kotlin</a></li> <li><a href="clike/index.html">Kotlin</a></li>
<li><a href="css/less.html">LESS</a></li> <li><a href="css/less.html">LESS</a></li>
<li><a href="livescript/index.html">LiveScript</a></li> <li><a href="livescript/index.html">LiveScript</a></li>
<li><a href="lua/index.html">Lua</a></li> <li><a href="lua/index.html">Lua</a></li>

View file

@ -26,7 +26,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d"); var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
var operator = kw("operator"), atom = {type: "atom", style: "atom"}; var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = { return {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C, "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"), "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
@ -38,33 +38,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C, "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
"await": C "await": C
}; };
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "type"};
var tsKeywords = {
// object-like things
"interface": kw("class"),
"implements": C,
"namespace": C,
// scope modifiers
"public": kw("modifier"),
"private": kw("modifier"),
"protected": kw("modifier"),
"abstract": kw("modifier"),
"readonly": kw("modifier"),
// types
"string": type, "number": type, "boolean": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}(); }();
var isOperatorChar = /[+\-*&%=<>!?|~^@]/; var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
@ -102,17 +75,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return ret(ch); return ret(ch);
} else if (ch == "=" && stream.eat(">")) { } else if (ch == "=" && stream.eat(">")) {
return ret("=>", "operator"); return ret("=>", "operator");
} else if (ch == "0" && stream.eat(/x/i)) { } else if (ch == "0" && stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/o/i)) {
stream.eatWhile(/[0-7]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/b/i)) {
stream.eatWhile(/[01]/i);
return ret("number", "number"); return ret("number", "number");
} else if (/\d/.test(ch)) { } else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/);
return ret("number", "number"); return ret("number", "number");
} else if (ch == "/") { } else if (ch == "/") {
if (stream.eat("*")) { if (stream.eat("*")) {
@ -123,7 +89,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return ret("comment", "comment"); return ret("comment", "comment");
} else if (expressionAllowed(stream, state, 1)) { } else if (expressionAllowed(stream, state, 1)) {
readRegexp(stream); readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);
return ret("regexp", "string-2"); return ret("regexp", "string-2");
} else { } else {
stream.eat("="); stream.eat("=");
@ -153,7 +119,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var kw = keywords[word] var kw = keywords[word]
return ret(kw.type, kw.style, word) return ret(kw.type, kw.style, word)
} }
if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\(\w]/, false)) if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
return ret("async", "keyword", word) return ret("async", "keyword", word)
} }
return ret("variable", "variable", word) return ret("variable", "variable", word)
@ -292,35 +258,68 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
pass.apply(null, arguments); pass.apply(null, arguments);
return true; return true;
} }
function inList(name, list) {
for (var v = list; v; v = v.next) if (v.name == name) return true
return false;
}
function register(varname) { 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; var state = cx.state;
cx.marked = "def"; cx.marked = "def";
if (state.context) { if (state.context) {
if (inList(state.localVars)) return; if (state.lexical.info == "var" && state.context && state.context.block) {
state.localVars = {name: varname, next: state.localVars}; // FIXME function decls are also not block scoped
} else { var newContext = registerVarScoped(varname, state.context)
if (inList(state.globalVars)) return; if (newContext != null) {
if (parserConfig.globalVars) state.context = newContext
state.globalVars = {name: varname, next: state.globalVars}; return
}
} else if (!inList(varname, state.localVars)) {
state.localVars = new Var(varname, state.localVars)
return
}
} }
// Fall through means this is global
if (parserConfig.globalVars && !inList(varname, state.globalVars))
state.globalVars = new Var(varname, state.globalVars)
}
function registerVarScoped(varname, context) {
if (!context) {
return null
} else if (context.block) {
var inner = registerVarScoped(varname, context.prev)
if (!inner) return null
if (inner == context.prev) return context
return new Context(inner, context.vars, true)
} else if (inList(varname, context.vars)) {
return context
} else {
return new Context(context.prev, new Var(varname, context.vars), false)
}
}
function isModifier(name) {
return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
} }
// Combinators // Combinators
var defaultVars = {name: "this", next: {name: "arguments"}}; function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }
function Var(name, next) { this.name = name; this.next = next }
var defaultVars = new Var("this", new Var("arguments", null))
function pushcontext() { function pushcontext() {
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; cx.state.context = new Context(cx.state.context, cx.state.localVars, false)
cx.state.localVars = defaultVars; cx.state.localVars = defaultVars
}
function pushblockcontext() {
cx.state.context = new Context(cx.state.context, cx.state.localVars, true)
cx.state.localVars = null
} }
function popcontext() { function popcontext() {
cx.state.localVars = cx.state.context.vars; cx.state.localVars = cx.state.context.vars
cx.state.context = cx.state.context.prev; cx.state.context = cx.state.context.prev
} }
popcontext.lex = true
function pushlex(type, info) { function pushlex(type, info) {
var result = function() { var result = function() {
var state = cx.state, indent = state.indented; var state = cx.state, indent = state.indented;
@ -352,12 +351,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
function statement(type, value) { function statement(type, value) {
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
if (type == "debugger") return cont(expect(";")); if (type == "debugger") return cont(expect(";"));
if (type == "{") return cont(pushlex("}"), block, poplex); if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext);
if (type == ";") return cont(); if (type == ";") return cont();
if (type == "if") { if (type == "if") {
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
@ -366,44 +365,51 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
if (type == "function") return cont(functiondef); if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
if (type == "variable") { if (type == "variable") {
if (isTS && value == "type") { if (isTS && value == "declare") {
cx.marked = "keyword"
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
} else if (isTS && value == "declare") {
cx.marked = "keyword" cx.marked = "keyword"
return cont(statement) return cont(statement)
} else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) { } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
cx.marked = "keyword" cx.marked = "keyword"
return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) if (value == "enum") return cont(enumdef);
else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
} else if (isTS && value == "abstract") {
cx.marked = "keyword"
return cont(statement)
} else { } else {
return cont(pushlex("stat"), maybelabel); return cont(pushlex("stat"), maybelabel);
} }
} }
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext,
block, poplex, poplex); block, poplex, poplex, popcontext);
if (type == "case") return cont(expression, expect(":")); if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":")); if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);
statement, poplex, popcontext);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("stat"), afterExport, poplex); if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
if (type == "import") return cont(pushlex("stat"), afterImport, poplex); if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
if (type == "async") return cont(statement) if (type == "async") return cont(statement)
if (value == "@") return cont(expression, statement) if (value == "@") return cont(expression, statement)
return pass(pushlex("stat"), expression, expect(";"), poplex); return pass(pushlex("stat"), expression, expect(";"), poplex);
} }
function expression(type) { function maybeCatchBinding(type) {
return expressionInner(type, false); if (type == "(") return cont(funarg, expect(")"))
} }
function expressionNoComma(type) { function expression(type, value) {
return expressionInner(type, true); return expressionInner(type, value, false);
}
function expressionNoComma(type, value) {
return expressionInner(type, value, true);
} }
function parenExpr(type) { function parenExpr(type) {
if (type != "(") return pass() if (type != "(") return pass()
return cont(pushlex(")"), expression, expect(")"), poplex) return cont(pushlex(")"), expression, expect(")"), poplex)
} }
function expressionInner(type, noComma) { function expressionInner(type, value, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) { if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody; var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
@ -413,7 +419,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop); if (type == "function") return cont(functiondef, maybeop);
if (type == "class") return cont(pushlex("form"), classExpression, poplex); if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
@ -421,6 +427,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "{") return contCommasep(objprop, "}", null, maybeop);
if (type == "quasi") return pass(quasi, maybeop); if (type == "quasi") return pass(quasi, maybeop);
if (type == "new") return cont(maybeTarget(noComma)); if (type == "new") return cont(maybeTarget(noComma));
if (type == "import") return cont(expression);
return cont(); return cont();
} }
function maybeexpression(type) { function maybeexpression(type) {
@ -511,10 +518,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(afterprop); return cont(afterprop);
} else if (type == "jsonld-keyword") { } else if (type == "jsonld-keyword") {
return cont(afterprop); return cont(afterprop);
} else if (type == "modifier") { } else if (isTS && isModifier(value)) {
cx.marked = "keyword"
return cont(objprop) return cont(objprop)
} else if (type == "[") { } else if (type == "[") {
return cont(expression, expect("]"), afterprop); return cont(expression, maybetype, expect("]"), afterprop);
} else if (type == "spread") { } else if (type == "spread") {
return cont(expressionNoComma, afterprop); return cont(expressionNoComma, afterprop);
} else if (value == "*") { } else if (value == "*") {
@ -579,19 +587,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
} }
function typeexpr(type, value) { function typeexpr(type, value) {
if (value == "keyof" || value == "typeof") {
cx.marked = "keyword"
return cont(value == "keyof" ? typeexpr : expressionNoComma)
}
if (type == "variable" || value == "void") { if (type == "variable" || value == "void") {
if (value == "keyof") { cx.marked = "type"
cx.marked = "keyword" return cont(afterType)
return cont(typeexpr)
} else {
cx.marked = "type"
return cont(afterType)
}
} }
if (type == "string" || type == "number" || type == "atom") return cont(afterType); if (type == "string" || type == "number" || type == "atom") return cont(afterType);
if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
} }
function maybeReturnType(type) { function maybeReturnType(type) {
if (type == "=>") return cont(typeexpr) if (type == "=>") return cont(typeexpr)
@ -608,15 +616,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(expression, maybetype, expect("]"), typeprop) return cont(expression, maybetype, expect("]"), typeprop)
} }
} }
function typearg(type) { function typearg(type, value) {
if (type == "variable") return cont(typearg) if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
else if (type == ":") return cont(typeexpr) if (type == ":") return cont(typeexpr)
return pass(typeexpr)
} }
function afterType(type, value) { function afterType(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
if (value == "|" || type == ".") return cont(typeexpr) if (value == "|" || type == "." || value == "&") return cont(typeexpr)
if (type == "[") return cont(expect("]"), afterType) if (type == "[") return cont(expect("]"), afterType)
if (value == "extends") return cont(typeexpr) if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
} }
function maybeTypeArgs(_, value) { function maybeTypeArgs(_, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
@ -627,11 +636,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function maybeTypeDefault(_, value) { function maybeTypeDefault(_, value) {
if (value == "=") return cont(typeexpr) if (value == "=") return cont(typeexpr)
} }
function vardef() { function vardef(_, value) {
if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
return pass(pattern, maybetype, maybeAssign, vardefCont); return pass(pattern, maybetype, maybeAssign, vardefCont);
} }
function pattern(type, value) { function pattern(type, value) {
if (type == "modifier") return cont(pattern) if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
if (type == "variable") { register(value); return cont(); } if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern); if (type == "spread") return cont(pattern);
if (type == "[") return contCommasep(pattern, "]"); if (type == "[") return contCommasep(pattern, "]");
@ -656,7 +666,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function maybeelse(type, value) { function maybeelse(type, value) {
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
} }
function forspec(type) { function forspec(type, value) {
if (value == "await") return cont(forspec);
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
} }
function forspec1(type) { function forspec1(type) {
@ -685,7 +696,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
function funarg(type, value) { function funarg(type, value) {
if (value == "@") cont(expression, funarg) if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg); if (type == "spread") return cont(funarg);
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
return pass(pattern, maybetype, maybeAssign); return pass(pattern, maybetype, maybeAssign);
} }
function classExpression(type, value) { function classExpression(type, value) {
@ -698,14 +710,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
function classNameAfter(type, value) { function classNameAfter(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
if (value == "extends" || value == "implements" || (isTS && type == ",")) if (value == "extends" || value == "implements" || (isTS && type == ",")) {
if (value == "implements") cx.marked = "keyword";
return cont(isTS ? typeexpr : expression, classNameAfter); return cont(isTS ? typeexpr : expression, classNameAfter);
}
if (type == "{") return cont(pushlex("}"), classBody, poplex); if (type == "{") return cont(pushlex("}"), classBody, poplex);
} }
function classBody(type, value) { function classBody(type, value) {
if (type == "modifier" || type == "async" || if (type == "async" ||
(type == "variable" && (type == "variable" &&
(value == "static" || value == "get" || value == "set") && (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
cx.marked = "keyword"; cx.marked = "keyword";
return cont(classBody); return cont(classBody);
@ -715,7 +729,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(isTS ? classfield : functiondef, classBody); return cont(isTS ? classfield : functiondef, classBody);
} }
if (type == "[") if (type == "[")
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody) return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
if (value == "*") { if (value == "*") {
cx.marked = "keyword"; cx.marked = "keyword";
return cont(classBody); return cont(classBody);
@ -742,6 +756,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
function afterImport(type) { function afterImport(type) {
if (type == "string") return cont(); if (type == "string") return cont();
if (type == "(") return pass(expression);
return pass(importSpec, maybeMoreImports, maybeFrom); return pass(importSpec, maybeMoreImports, maybeFrom);
} }
function importSpec(type, value) { function importSpec(type, value) {
@ -763,6 +778,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "]") return cont(); if (type == "]") return cont();
return pass(commasep(expressionNoComma, "]")); return pass(commasep(expressionNoComma, "]"));
} }
function enumdef() {
return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
}
function enummember() {
return pass(pattern, maybeAssign);
}
function isContinuedStatement(state, textAfter) { function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," || return state.lastType == "operator" || state.lastType == "," ||
@ -786,7 +807,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
cc: [], cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars, localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars}, context: parserConfig.localVars && new Context(null, null, false),
indented: basecolumn || 0 indented: basecolumn || 0
}; };
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
@ -827,7 +848,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
lexical = lexical.prev; lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type; var type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented; else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit; else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat") else if (type == "stat")

View file

@ -63,6 +63,12 @@
MT("import_trailing_comma", MT("import_trailing_comma",
"[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']") "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']")
MT("import_dynamic",
"[keyword import]([string 'baz']).[property then]")
MT("import_dynamic",
"[keyword const] [def t] [operator =] [keyword import]([string 'baz']).[property then]")
MT("const", MT("const",
"[keyword function] [def f]() {", "[keyword function] [def f]() {",
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
@ -71,12 +77,44 @@
MT("for/of", MT("for/of",
"[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}"); "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}");
MT("for await",
"[keyword for] [keyword await]([keyword let] [def of] [keyword of] [variable something]) {}");
MT("generator", MT("generator",
"[keyword function*] [def repeat]([def n]) {", "[keyword function*] [def repeat]([def n]) {",
" [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
" [keyword yield] [variable-2 i];", " [keyword yield] [variable-2 i];",
"}"); "}");
MT("let_scoping",
"[keyword function] [def scoped]([def n]) {",
" { [keyword var] [def i]; } [variable-2 i];",
" { [keyword let] [def j]; [variable-2 j]; } [variable j];",
" [keyword if] ([atom true]) { [keyword const] [def k]; [variable-2 k]; } [variable k];",
"}");
MT("switch_scoping",
"[keyword switch] ([variable x]) {",
" [keyword default]:",
" [keyword let] [def j];",
" [keyword return] [variable-2 j]",
"}",
"[variable j];")
MT("leaving_scope",
"[keyword function] [def a]() {",
" {",
" [keyword const] [def x] [operator =] [number 1]",
" [keyword if] ([atom true]) {",
" [keyword let] [def y] [operator =] [number 2]",
" [keyword var] [def z] [operator =] [number 3]",
" [variable console].[property log]([variable-2 x], [variable-2 y], [variable-2 z])",
" }",
" [variable console].[property log]([variable-2 x], [variable y], [variable-2 z])",
" }",
" [variable console].[property log]([variable x], [variable y], [variable-2 z])",
"}")
MT("quotedStringAddition", MT("quotedStringAddition",
"[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
@ -230,6 +268,8 @@
"[keyword const] [def async] [operator =] {[property a]: [number 1]};", "[keyword const] [def async] [operator =] {[property a]: [number 1]};",
"[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];") "[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];")
MT("bigint", "[number 1n] [operator +] [number 0x1afn] [operator +] [number 0o064n] [operator +] [number 0b100n];")
MT("async_comment", MT("async_comment",
"[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); "[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }");
@ -383,6 +423,25 @@
" }", " }",
"}") "}")
TS("type as variable",
"[variable type] [operator =] [variable x] [keyword as] [type Bar];");
TS("enum body",
"[keyword export] [keyword const] [keyword enum] [def CodeInspectionResultType] {",
" [def ERROR] [operator =] [string 'problem_type_error'],",
" [def WARNING] [operator =] [string 'problem_type_warning'],",
" [def META],",
"}")
TS("parenthesized type",
"[keyword class] [def Foo] {",
" [property x] [operator =] [keyword new] [variable A][operator <][type B], [type string][operator |](() [operator =>] [type void])[operator >]();",
" [keyword private] [property bar]();",
"}")
TS("abstract class",
"[keyword export] [keyword abstract] [keyword class] [def Foo] {}")
var jsonld_mode = CodeMirror.getMode( var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2}, {indentUnit: 2},
{name: "javascript", jsonld: true} {name: "javascript", jsonld: true}

View file

@ -26,7 +26,7 @@
} }
CodeMirror.defineMode("jsx", function(config, modeConfig) { CodeMirror.defineMode("jsx", function(config, modeConfig) {
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false}) var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true})
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript") var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
function flatXMLIndent(state) { function flatXMLIndent(state) {

View file

@ -11,6 +11,9 @@
MT("openclose", MT("openclose",
"([bracket&tag <][tag foo][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])") "([bracket&tag <][tag foo][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("openclosefragment",
"([bracket&tag <><][tag foo][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag ></>][operator ++])")
MT("attr", MT("attr",
"([bracket&tag <][tag foo] [attribute abc]=[string 'value'][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])") "([bracket&tag <][tag foo] [attribute abc]=[string 'value'][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")

View file

@ -90,7 +90,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
, setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
, textRE = /^[^#!\[\]*_\\<>` "'(~:]+/ , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/
, fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]*)[^\n`]*$/ , fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]*)[^\n`]*$/
, linkDefRE = /^\s*\[[^\]]+?\]:\s*\S+(\s*\S*\s*)?$/ // naive link-definition , linkDefRE = /^\s*\[[^\]]+?\]:.*$/ // naive link-definition
, punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/ , punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/
, expandedTab = " " // CommonMark specifies tab as 4 spaces , expandedTab = " " // CommonMark specifies tab as 4 spaces
@ -113,6 +113,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
function blankLine(state) { function blankLine(state) {
// Reset linkTitle state // Reset linkTitle state
state.linkTitle = false; state.linkTitle = false;
state.linkHref = false;
state.linkText = false;
// Reset EM state // Reset EM state
state.em = false; state.em = false;
// Reset STRONG state // Reset STRONG state
@ -151,6 +153,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (state.indentationDiff === null) { if (state.indentationDiff === null) {
state.indentationDiff = state.indentation; state.indentationDiff = state.indentation;
if (prevLineIsList) { if (prevLineIsList) {
// Reset inline styles which shouldn't propagate aross list items
state.em = false;
state.strong = false;
state.code = false;
state.strikethrough = false;
state.list = null; state.list = null;
// While this list item's marker's indentation is less than the deepest // While this list item's marker's indentation is less than the deepest
// list item's content's indentation,pop the deepest list item // list item's content's indentation,pop the deepest list item
@ -526,7 +534,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return type + tokenTypes.linkEmail; return type + tokenTypes.linkEmail;
} }
if (modeCfg.xml && ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) { if (modeCfg.xml && ch === '<' && stream.match(/^(!--|[a-z][a-z0-9-]*(?:\s+[a-z_:.\-]+(?:\s*=\s*[^>]+)?)*\s*>)/i, false)) {
var end = stream.string.indexOf(">", stream.pos); var end = stream.string.indexOf(">", stream.pos);
if (end != -1) { if (end != -1) {
var atts = stream.string.substring(stream.start, end); var atts = stream.string.substring(stream.start, end);
@ -611,7 +619,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
} }
if (ch === ' ') { if (ch === ' ') {
if (stream.match(/ +$/, false)) { if (stream.match(/^ +$/, false)) {
state.trailingSpace++; state.trailingSpace++;
} else if (state.trailingSpace) { } else if (state.trailingSpace) {
state.trailingSpaceNewLine = true; state.trailingSpaceNewLine = true;
@ -777,6 +785,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
formatting: false, formatting: false,
linkText: s.linkText, linkText: s.linkText,
linkTitle: s.linkTitle, linkTitle: s.linkTitle,
linkHref: s.linkHref,
code: s.code, code: s.code,
em: s.em, em: s.em,
strong: s.strong, strong: s.strong,
@ -856,6 +865,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return mode; return mode;
}, "xml"); }, "xml");
CodeMirror.defineMIME("text/markdown", "markdown");
CodeMirror.defineMIME("text/x-markdown", "markdown"); CodeMirror.defineMIME("text/x-markdown", "markdown");
}); });

View file

@ -71,12 +71,12 @@ CodeMirror.defineMode('mathematica', function(_config, _parserConfig) {
} }
// usage // usage
if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::usage)/, true, false)) { if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::usage)/, true, false)) {
return 'meta'; return 'meta';
} }
// message // message
if (stream.match(/([a-zA-Z\$]+(?:`?[a-zA-Z0-9\$])*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) { if (stream.match(/([a-zA-Z\$][a-zA-Z0-9\$]*(?:`[a-zA-Z0-9\$]+)*::[a-zA-Z\$][a-zA-Z0-9\$]*):?/, true, false)) {
return 'string-2'; return 'string-2';
} }

View file

@ -17,7 +17,7 @@
{name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]}, {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
{name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
{name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]}, {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
{name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]}, {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]},
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
@ -64,7 +64,7 @@
{name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]}, {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
{name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]}, {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]}, {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]}, {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm", "handlebars", "hbs"], alias: ["xhtml"]},
{name: "HTTP", mime: "message/http", mode: "http"}, {name: "HTTP", mime: "message/http", mode: "http"},
{name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]}, {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
{name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]}, {name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]},
@ -94,14 +94,14 @@
{name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]}, {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
{name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"], {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"],
mode: "ntriples", ext: ["nt", "nq"]}, mode: "ntriples", ext: ["nt", "nq"]},
{name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]}, {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]},
{name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
{name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
{name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]}, {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
{name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
{name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
{name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
{name: "PHP", mime: ["application/x-httpd-php", "text/x-php"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, {name: "PHP", mimes: ["text/x-php", "application/x-httpd-php", "application/x-httpd-php-open"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]},
{name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
{name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
@ -128,6 +128,7 @@
{name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
{name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]}, {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
{name: "Solr", mime: "text/x-solr", mode: "solr"}, {name: "Solr", mime: "text/x-solr", mode: "solr"},
{name: "SML", mime: "text/x-sml", mode: "mllike", ext: ["sml", "sig", "fun", "smackspec"]},
{name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]}, {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
{name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]}, {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
{name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
@ -137,7 +138,7 @@
{name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]}, {name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]},
{name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]}, {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
{name: "sTeX", mime: "text/x-stex", mode: "stex"}, {name: "sTeX", mime: "text/x-stex", mode: "stex"},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]}, {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx", "tex"], alias: ["tex"]},
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]}, {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]},
{name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]}, {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
{name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]}, {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},

View file

@ -132,6 +132,25 @@ let () =
(* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *) (* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *)
(* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *) (* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *)
module type S = sig type t end
let x = {|
this is a long string
with many lines and stuff
|}
let b = 0b00110
let h = 0x123abcd
let e = 1e-10
let i = 1.
let x = 30_000
let o = 0o1234
[1; 2; 3] (* lists *)
1 @ 2
1. +. 2.
</textarea> </textarea>
<h2>F# mode</h2> <h2>F# mode</h2>

View file

@ -13,31 +13,26 @@
CodeMirror.defineMode('mllike', function(_config, parserConfig) { CodeMirror.defineMode('mllike', function(_config, parserConfig) {
var words = { var words = {
'let': 'keyword', 'as': 'keyword',
'rec': 'keyword',
'in': 'keyword',
'of': 'keyword',
'and': 'keyword',
'if': 'keyword',
'then': 'keyword',
'else': 'keyword',
'for': 'keyword',
'to': 'keyword',
'while': 'keyword',
'do': 'keyword', 'do': 'keyword',
'done': 'keyword', 'else': 'keyword',
'end': 'keyword',
'exception': 'keyword',
'fun': 'keyword', 'fun': 'keyword',
'function': 'keyword', 'functor': 'keyword',
'val': 'keyword', 'if': 'keyword',
'in': 'keyword',
'include': 'keyword',
'let': 'keyword',
'of': 'keyword',
'open': 'keyword',
'rec': 'keyword',
'struct': 'keyword',
'then': 'keyword',
'type': 'keyword', 'type': 'keyword',
'mutable': 'keyword', 'val': 'keyword',
'match': 'keyword', 'while': 'keyword',
'with': 'keyword', 'with': 'keyword'
'try': 'keyword',
'open': 'builtin',
'ignore': 'builtin',
'begin': 'keyword',
'end': 'keyword'
}; };
var extraWords = parserConfig.extraWords || {}; var extraWords = parserConfig.extraWords || {};
@ -54,6 +49,13 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
state.tokenize = tokenString; state.tokenize = tokenString;
return state.tokenize(stream, state); return state.tokenize(stream, state);
} }
if (ch === '{') {
if (stream.eat('|')) {
state.longString = true;
state.tokenize = tokenLongString;
return state.tokenize(stream, state);
}
}
if (ch === '(') { if (ch === '(') {
if (stream.eat('*')) { if (stream.eat('*')) {
state.commentLevel++; state.commentLevel++;
@ -61,7 +63,7 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
return state.tokenize(stream, state); return state.tokenize(stream, state);
} }
} }
if (ch === '~') { if (ch === '~' || ch === '?') {
stream.eatWhile(/\w/); stream.eatWhile(/\w/);
return 'variable-2'; return 'variable-2';
} }
@ -74,13 +76,24 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
return 'comment'; return 'comment';
} }
if (/\d/.test(ch)) { if (/\d/.test(ch)) {
stream.eatWhile(/[\d]/); if (ch === '0' && stream.eat(/[bB]/)) {
if (stream.eat('.')) { stream.eatWhile(/[01]/);
stream.eatWhile(/[\d]/); } if (ch === '0' && stream.eat(/[xX]/)) {
stream.eatWhile(/[0-9a-fA-F]/)
} if (ch === '0' && stream.eat(/[oO]/)) {
stream.eatWhile(/[0-7]/);
} else {
stream.eatWhile(/[\d_]/);
if (stream.eat('.')) {
stream.eatWhile(/[\d]/);
}
if (stream.eat(/[eE]/)) {
stream.eatWhile(/[\d\-+]/);
}
} }
return 'number'; return 'number';
} }
if ( /[+\-*&%=<>!?|]/.test(ch)) { if ( /[+\-*&%=<>!?|@\.~:]/.test(ch)) {
return 'operator'; return 'operator';
} }
if (/[\w\xa1-\uffff]/.test(ch)) { if (/[\w\xa1-\uffff]/.test(ch)) {
@ -119,8 +132,20 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
return 'comment'; return 'comment';
} }
function tokenLongString(stream, state) {
var prev, next;
while (state.longString && (next = stream.next()) != null) {
if (prev === '|' && next === '}') state.longString = false;
prev = next;
}
if (!state.longString) {
state.tokenize = tokenBase;
}
return 'string';
}
return { return {
startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, startState: function() {return {tokenize: tokenBase, commentLevel: 0, longString: false};},
token: function(stream, state) { token: function(stream, state) {
if (stream.eatSpace()) return null; if (stream.eatSpace()) return null;
return state.tokenize(stream, state); return state.tokenize(stream, state);
@ -135,14 +160,64 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
CodeMirror.defineMIME('text/x-ocaml', { CodeMirror.defineMIME('text/x-ocaml', {
name: 'mllike', name: 'mllike',
extraWords: { extraWords: {
'succ': 'keyword', 'and': 'keyword',
'assert': 'keyword',
'begin': 'keyword',
'class': 'keyword',
'constraint': 'keyword',
'done': 'keyword',
'downto': 'keyword',
'external': 'keyword',
'function': 'keyword',
'initializer': 'keyword',
'lazy': 'keyword',
'match': 'keyword',
'method': 'keyword',
'module': 'keyword',
'mutable': 'keyword',
'new': 'keyword',
'nonrec': 'keyword',
'object': 'keyword',
'private': 'keyword',
'sig': 'keyword',
'to': 'keyword',
'try': 'keyword',
'value': 'keyword',
'virtual': 'keyword',
'when': 'keyword',
// builtins
'raise': 'builtin',
'failwith': 'builtin',
'true': 'builtin',
'false': 'builtin',
// Pervasives builtins
'asr': 'builtin',
'land': 'builtin',
'lor': 'builtin',
'lsl': 'builtin',
'lsr': 'builtin',
'lxor': 'builtin',
'mod': 'builtin',
'or': 'builtin',
// More Pervasives
'raise_notrace': 'builtin',
'trace': 'builtin', 'trace': 'builtin',
'exit': 'builtin', 'exit': 'builtin',
'print_string': 'builtin', 'print_string': 'builtin',
'print_endline': 'builtin', 'print_endline': 'builtin',
'true': 'atom',
'false': 'atom', 'int': 'type',
'raise': 'keyword' 'float': 'type',
'bool': 'type',
'char': 'type',
'string': 'type',
'unit': 'type',
// Modules
'List': 'builtin'
} }
}); });
@ -150,18 +225,21 @@ CodeMirror.defineMIME('text/x-fsharp', {
name: 'mllike', name: 'mllike',
extraWords: { extraWords: {
'abstract': 'keyword', 'abstract': 'keyword',
'as': 'keyword',
'assert': 'keyword', 'assert': 'keyword',
'base': 'keyword', 'base': 'keyword',
'begin': 'keyword',
'class': 'keyword', 'class': 'keyword',
'default': 'keyword', 'default': 'keyword',
'delegate': 'keyword', 'delegate': 'keyword',
'do!': 'keyword',
'done': 'keyword',
'downcast': 'keyword', 'downcast': 'keyword',
'downto': 'keyword', 'downto': 'keyword',
'elif': 'keyword', 'elif': 'keyword',
'exception': 'keyword',
'extern': 'keyword', 'extern': 'keyword',
'finally': 'keyword', 'finally': 'keyword',
'for': 'keyword',
'function': 'keyword',
'global': 'keyword', 'global': 'keyword',
'inherit': 'keyword', 'inherit': 'keyword',
'inline': 'keyword', 'inline': 'keyword',
@ -169,38 +247,108 @@ CodeMirror.defineMIME('text/x-fsharp', {
'internal': 'keyword', 'internal': 'keyword',
'lazy': 'keyword', 'lazy': 'keyword',
'let!': 'keyword', 'let!': 'keyword',
'member' : 'keyword', 'match': 'keyword',
'member': 'keyword',
'module': 'keyword', 'module': 'keyword',
'mutable': 'keyword',
'namespace': 'keyword', 'namespace': 'keyword',
'new': 'keyword', 'new': 'keyword',
'null': 'keyword', 'null': 'keyword',
'override': 'keyword', 'override': 'keyword',
'private': 'keyword', 'private': 'keyword',
'public': 'keyword', 'public': 'keyword',
'return': 'keyword',
'return!': 'keyword', 'return!': 'keyword',
'return': 'keyword',
'select': 'keyword', 'select': 'keyword',
'static': 'keyword', 'static': 'keyword',
'struct': 'keyword', 'to': 'keyword',
'try': 'keyword',
'upcast': 'keyword', 'upcast': 'keyword',
'use': 'keyword',
'use!': 'keyword', 'use!': 'keyword',
'val': 'keyword', 'use': 'keyword',
'void': 'keyword',
'when': 'keyword', 'when': 'keyword',
'yield': 'keyword',
'yield!': 'keyword', 'yield!': 'keyword',
'yield': 'keyword',
// Reserved words
'atomic': 'keyword',
'break': 'keyword',
'checked': 'keyword',
'component': 'keyword',
'const': 'keyword',
'constraint': 'keyword',
'constructor': 'keyword',
'continue': 'keyword',
'eager': 'keyword',
'event': 'keyword',
'external': 'keyword',
'fixed': 'keyword',
'method': 'keyword',
'mixin': 'keyword',
'object': 'keyword',
'parallel': 'keyword',
'process': 'keyword',
'protected': 'keyword',
'pure': 'keyword',
'sealed': 'keyword',
'tailcall': 'keyword',
'trait': 'keyword',
'virtual': 'keyword',
'volatile': 'keyword',
// builtins
'List': 'builtin', 'List': 'builtin',
'Seq': 'builtin', 'Seq': 'builtin',
'Map': 'builtin', 'Map': 'builtin',
'Set': 'builtin', 'Set': 'builtin',
'Option': 'builtin',
'int': 'builtin', 'int': 'builtin',
'string': 'builtin', 'string': 'builtin',
'raise': 'builtin',
'failwith': 'builtin',
'not': 'builtin', 'not': 'builtin',
'true': 'builtin', 'true': 'builtin',
'false': 'builtin' 'false': 'builtin',
'raise': 'builtin',
'failwith': 'builtin'
},
slashComments: true
});
CodeMirror.defineMIME('text/x-sml', {
name: 'mllike',
extraWords: {
'abstype': 'keyword',
'and': 'keyword',
'andalso': 'keyword',
'case': 'keyword',
'datatype': 'keyword',
'fn': 'keyword',
'handle': 'keyword',
'infix': 'keyword',
'infixr': 'keyword',
'local': 'keyword',
'nonfix': 'keyword',
'op': 'keyword',
'orelse': 'keyword',
'raise': 'keyword',
'withtype': 'keyword',
'eqtype': 'keyword',
'sharing': 'keyword',
'sig': 'keyword',
'signature': 'keyword',
'structure': 'keyword',
'where': 'keyword',
'true': 'keyword',
'false': 'keyword',
// types
'int': 'builtin',
'real': 'builtin',
'string': 'builtin',
'char': 'builtin',
'bool': 'builtin'
}, },
slashComments: true slashComments: true
}); });

View file

@ -1,4 +1,4 @@
<!doctype html> <!doctype html>
<head> <head>
<title>CodeMirror: NGINX mode</title> <title>CodeMirror: NGINX mode</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
@ -176,6 +176,6 @@ server {
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {}); var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script> </script>
<p><strong>MIME types defined:</strong> <code>text/nginx</code>.</p> <p><strong>MIME types defined:</strong> <code>text/x-nginx-conf</code>.</p>
</article> </article>

View file

@ -24,14 +24,14 @@ CodeMirror.defineSimpleMode("nsis",{
{ regex: /`(?:[^\\`]|\\.)*`?/, token: "string" }, { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" },
// Compile Time Commands // Compile Time Commands
{regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|pragma|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"}, {regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|pragma|finalize|getdllversion|gettlbversion|system|tempfile|warning|verbose|define|undef|insertmacro|macro|macroend|makensis|searchparse|searchreplace))\b/, token: "keyword"},
// Conditional Compilation // Conditional Compilation
{regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true}, {regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true},
{regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true}, {regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true},
// Runtime Commands // Runtime Commands
{regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|Int64Cmp|Int64CmpU|Int64Fmt|IntCmp|IntCmpU|IntFmt|IntOp|IntPtrCmp|IntPtrCmpU|IntPtrOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|PEDllCharacteristics|PESubsysVer|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"},
{regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true}, {regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true},
{regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true}, {regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true},

View file

@ -126,6 +126,15 @@ class ExampleClass(ParentClass):
def __init__(self, mixin = 'Hello'): def __init__(self, mixin = 'Hello'):
self.mixin = mixin self.mixin = mixin
# Python 3.6 f-strings (https://www.python.org/dev/peps/pep-0498/)
f'My name is {name}, my age next year is {age+1}, my anniversary is {anniversary:%A, %B %d, %Y}.'
f'He said his name is {name!r}.'
f"""He said his name is {name!r}."""
f'{"quoted string"}'
f'{{ {4*10} }}'
f'This is an error }'
f'This is ok }}'
fr'x={4*10}\n'
</textarea></div> </textarea></div>

View file

@ -41,7 +41,7 @@
CodeMirror.defineMode("python", function(conf, parserConf) { CodeMirror.defineMode("python", function(conf, parserConf) {
var ERRORCLASS = "error"; var ERRORCLASS = "error";
var delimiters = parserConf.delimiters || parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.]/; var delimiters = parserConf.delimiters || parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.\\]/;
// (Backwards-compatiblity with old, cumbersome config system) // (Backwards-compatiblity with old, cumbersome config system)
var operators = [parserConf.singleOperators, parserConf.doubleOperators, parserConf.doubleDelimiters, parserConf.tripleDelimiters, var operators = [parserConf.singleOperators, parserConf.doubleOperators, parserConf.doubleDelimiters, parserConf.tripleDelimiters,
parserConf.operators || /^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@])/] parserConf.operators || /^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@])/]
@ -62,7 +62,7 @@
var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/; var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/;
myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "async", "await"]); myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "async", "await"]);
myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]); myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]);
var stringPrefixes = new RegExp("^(([rbuf]|(br))?('{3}|\"{3}|['\"]))", "i"); var stringPrefixes = new RegExp("^(([rbuf]|(br)|(fr))?('{3}|\"{3}|['\"]))", "i");
} else { } else {
var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/; var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/;
myKeywords = myKeywords.concat(["exec", "print"]); myKeywords = myKeywords.concat(["exec", "print"]);
@ -76,9 +76,10 @@
// tokenizers // tokenizers
function tokenBase(stream, state) { function tokenBase(stream, state) {
if (stream.sol()) state.indent = stream.indentation() var sol = stream.sol() && state.lastToken != "\\"
if (sol) state.indent = stream.indentation()
// Handle scope changes // Handle scope changes
if (stream.sol() && top(state).type == "py") { if (sol && top(state).type == "py") {
var scopeOffset = top(state).offset; var scopeOffset = top(state).offset;
if (stream.eatSpace()) { if (stream.eatSpace()) {
var lineOffset = stream.indentation(); var lineOffset = stream.indentation();
@ -100,13 +101,8 @@
function tokenBaseInner(stream, state) { function tokenBaseInner(stream, state) {
if (stream.eatSpace()) return null; if (stream.eatSpace()) return null;
var ch = stream.peek();
// Handle Comments // Handle Comments
if (ch == "#") { if (stream.match(/^#.*/)) return "comment";
stream.skipToEnd();
return "comment";
}
// Handle Number Literals // Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) { if (stream.match(/^[0-9\.]/, false)) {
@ -146,8 +142,14 @@
// Handle Strings // Handle Strings
if (stream.match(stringPrefixes)) { if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current()); var isFmtString = stream.current().toLowerCase().indexOf('f') !== -1;
return state.tokenize(stream, state); if (!isFmtString) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
} else {
state.tokenize = formatStringFactory(stream.current(), state.tokenize);
return state.tokenize(stream, state);
}
} }
for (var i = 0; i < operators.length; i++) for (var i = 0; i < operators.length; i++)
@ -178,6 +180,77 @@
return ERRORCLASS; return ERRORCLASS;
} }
function formatStringFactory(delimiter, tokenOuter) {
while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
delimiter = delimiter.substr(1);
var singleline = delimiter.length == 1;
var OUTCLASS = "string";
function tokenFString(stream, state) {
// inside f-str Expression
if (stream.match(delimiter)) {
// expression ends pre-maturally, but very common in editing
// Could show error to remind users to close brace here
state.tokenize = tokenString
return OUTCLASS;
} else if (stream.match('{')) {
// starting brace, if not eaten below
return "punctuation";
} else if (stream.match('}')) {
// return to regular inside string state
state.tokenize = tokenString
return "punctuation";
} else {
// use tokenBaseInner to parse the expression
return tokenBaseInner(stream, state);
}
}
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 = tokenOuter;
return OUTCLASS;
} else if (stream.match('{{')) {
// ignore {{ in f-str
return OUTCLASS;
} else if (stream.match('{', false)) {
// switch to nested mode
state.tokenize = tokenFString
if (stream.current()) {
return OUTCLASS;
} else {
// need to return something, so eat the starting {
stream.next();
return "punctuation";
}
} else if (stream.match('}}')) {
return OUTCLASS;
} else if (stream.match('}')) {
// single } in f-string is an error
return ERRORCLASS;
} else {
stream.eat(/['"]/);
}
}
if (singleline) {
if (parserConf.singleLineStringErrors)
return ERRORCLASS;
else
state.tokenize = tokenOuter;
}
return OUTCLASS;
}
tokenString.isString = true;
return tokenString;
}
function tokenStringFactory(delimiter) { function tokenStringFactory(delimiter) {
while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0) while ("rubf".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)
delimiter = delimiter.substr(1); delimiter = delimiter.substr(1);
@ -258,14 +331,16 @@
if (current == ":" && !state.lambda && top(state).type == "py") if (current == ":" && !state.lambda && top(state).type == "py")
pushPyScope(state); pushPyScope(state);
var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; if (current.length == 1 && !/string|comment/.test(style)) {
if (delimiter_index != -1) var delimiter_index = "[({".indexOf(current);
pushBracketScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1)); if (delimiter_index != -1)
pushBracketScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
delimiter_index = "])}".indexOf(current); delimiter_index = "])}".indexOf(current);
if (delimiter_index != -1) { if (delimiter_index != -1) {
if (top(state).type == current) state.indent = state.scopes.pop().offset - hangingIndent if (top(state).type == current) state.indent = state.scopes.pop().offset - hangingIndent
else return ERRORCLASS; else return ERRORCLASS;
}
} }
if (state.dedent > 0 && stream.eol() && top(state).type == "py") { if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
if (state.scopes.length > 1) state.scopes.pop(); if (state.scopes.length > 1) state.scopes.pop();

View file

@ -30,6 +30,9 @@
MT("before_equal_sign_" + c, "[variable a] [operator " + c + "=] [variable b]"); MT("before_equal_sign_" + c, "[variable a] [operator " + c + "=] [variable b]");
} }
MT("fValidStringPrefix", "[string f'this is a {formatted} string']"); MT("fValidStringPrefix", "[string f'this is a]{[variable formatted]}[string string']");
MT("fValidExpressioninFString", "[string f'expression ]{[number 100][operator *][number 5]}[string string']");
MT("fInvalidFString", "[error f'this is wrong}]");
MT("fNestedFString", "[string f'expression ]{[number 100] [operator +] [string f'inner]{[number 5]}[string ']}[string string']");
MT("uValidStringPrefix", "[string u'this is an unicode string']"); MT("uValidStringPrefix", "[string u'this is an unicode string']");
})(); })();

View file

@ -84,29 +84,38 @@ CodeMirror.defineMode('shell', function() {
function tokenString(quote, style) { function tokenString(quote, style) {
var close = quote == "(" ? ")" : quote == "{" ? "}" : quote var close = quote == "(" ? ")" : quote == "{" ? "}" : quote
return function(stream, state) { return function(stream, state) {
var next, end = false, escaped = false; var next, escaped = false;
while ((next = stream.next()) != null) { while ((next = stream.next()) != null) {
if (next === close && !escaped) { if (next === close && !escaped) {
end = true; state.tokens.shift();
break; break;
} } else if (next === '$' && !escaped && quote !== "'" && stream.peek() != close) {
if (next === '$' && !escaped && quote !== "'") {
escaped = true; escaped = true;
stream.backUp(1); stream.backUp(1);
state.tokens.unshift(tokenDollar); state.tokens.unshift(tokenDollar);
break; break;
} } else if (!escaped && quote !== close && next === quote) {
if (!escaped && next === quote && quote !== close) {
state.tokens.unshift(tokenString(quote, style)) state.tokens.unshift(tokenString(quote, style))
return tokenize(stream, state) return tokenize(stream, state)
} else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) {
state.tokens.unshift(tokenStringStart(next, "string"));
stream.backUp(1);
break;
} }
escaped = !escaped && next === '\\'; escaped = !escaped && next === '\\';
} }
if (end) state.tokens.shift();
return style; return style;
}; };
}; };
function tokenStringStart(quote, style) {
return function(stream, state) {
state.tokens[0] = tokenString(quote, style)
stream.next()
return tokenize(stream, state)
}
}
var tokenDollar = function(stream, state) { var tokenDollar = function(stream, state) {
if (state.tokens.length > 1) stream.eat('$'); if (state.tokens.length > 1) stream.eat('$');
var ch = stream.next() var ch = stream.next()

View file

@ -61,4 +61,13 @@
MT("nested braces", MT("nested braces",
"[builtin echo] [def ${A[${B}]]}]") "[builtin echo] [def ${A[${B}]]}]")
MT("strings in parens",
"[def FOO][operator =]([quote $(<][string \"][def $MYDIR][string \"][quote /myfile grep ][string 'hello$'][quote )])")
MT ("string ending in dollar",
'[def a][operator =][string "xyz$"]; [def b][operator =][string "y"]')
MT ("quote ending in dollar",
"[quote $(echo a$)]")
})(); })();

View file

@ -22,6 +22,7 @@
attributes: textMode, attributes: textMode,
text: textMode, text: textMode,
uri: textMode, uri: textMode,
trusted_resource_uri: textMode,
css: CodeMirror.getMode(config, "text/css"), css: CodeMirror.getMode(config, "text/css"),
js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit}) js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit})
}; };

File diff suppressed because one or more lines are too long

View file

@ -78,6 +78,14 @@
plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]); plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]);
plugins["end"] = addPluginPattern("end", "tag", ["atom"]); plugins["end"] = addPluginPattern("end", "tag", ["atom"]);
plugins["label" ] = addPluginPattern("label" , "tag", ["atom"]);
plugins["ref" ] = addPluginPattern("ref" , "tag", ["atom"]);
plugins["eqref" ] = addPluginPattern("eqref" , "tag", ["atom"]);
plugins["cite" ] = addPluginPattern("cite" , "tag", ["atom"]);
plugins["bibitem" ] = addPluginPattern("bibitem" , "tag", ["atom"]);
plugins["Bibitem" ] = addPluginPattern("Bibitem" , "tag", ["atom"]);
plugins["RBibitem" ] = addPluginPattern("RBibitem" , "tag", ["atom"]);
plugins["DEFAULT"] = function () { plugins["DEFAULT"] = function () {
this.name = "DEFAULT"; this.name = "DEFAULT";
this.style = "tag"; this.style = "tag";
@ -117,6 +125,10 @@
setState(state, function(source, state){ return inMathMode(source, state, "\\]"); }); setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
return "keyword"; return "keyword";
} }
if (source.match("\\(")) {
setState(state, function(source, state){ return inMathMode(source, state, "\\)"); });
return "keyword";
}
if (source.match("$$")) { if (source.match("$$")) {
setState(state, function(source, state){ return inMathMode(source, state, "$$"); }); setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
return "keyword"; return "keyword";

View file

@ -111,9 +111,18 @@
MT("inlineMath", MT("inlineMath",
"[keyword $][number 3][variable-2 x][tag ^][number 2.45]-[tag \\sqrt][bracket {][tag \\$\\alpha][bracket }] = [number 2][keyword $] other text"); "[keyword $][number 3][variable-2 x][tag ^][number 2.45]-[tag \\sqrt][bracket {][tag \\$\\alpha][bracket }] = [number 2][keyword $] other text");
MT("inlineMathLatexStyle",
"[keyword \\(][number 3][variable-2 x][tag ^][number 2.45]-[tag \\sqrt][bracket {][tag \\$\\alpha][bracket }] = [number 2][keyword \\)] other text");
MT("displayMath", MT("displayMath",
"More [keyword $$]\t[variable-2 S][tag ^][variable-2 n][tag \\sum] [variable-2 i][keyword $$] other text"); "More [keyword $$]\t[variable-2 S][tag ^][variable-2 n][tag \\sum] [variable-2 i][keyword $$] other text");
MT("displayMath environment",
"[tag \\begin][bracket {][atom equation][bracket }] x [tag \\end][bracket {][atom equation][bracket }] other text");
MT("displayMath environment with label",
"[tag \\begin][bracket {][atom equation][bracket }][tag \\label][bracket {][atom eq1][bracket }] x [tag \\end][bracket {][atom equation][bracket }] other text~[tag \\ref][bracket {][atom eq1][bracket }]");
MT("mathWithComment", MT("mathWithComment",
"[keyword $][variable-2 x] [comment % $]", "[keyword $][variable-2 x] [comment % $]",
"[variable-2 y][keyword $] other text"); "[variable-2 y][keyword $] other text");

View file

@ -76,7 +76,7 @@
if (ch == "#") { if (ch == "#") {
stream.next(); stream.next();
// Hex color // Hex color
if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) { if (stream.match(/^[0-9a-f]{3}([0-9a-f]([0-9a-f]{2}){0,2})?\b/i)) {
return ["atom", "atom"]; return ["atom", "atom"];
} }
// ID selector // ID selector

View file

@ -138,8 +138,17 @@
} }
function tokenComment(stream, state) { function tokenComment(stream, state) {
stream.match(/^(?:[^*]|\*(?!\/))*/) var ch
if (stream.match("*/")) state.tokenize.pop() while (true) {
stream.match(/^[^/*]+/, true)
ch = stream.next()
if (!ch) break
if (ch === "/" && stream.eat("*")) {
state.tokenize.push(tokenComment)
} else if (ch === "*" && stream.eat("/")) {
state.tokenize.pop()
}
}
return "comment" return "comment"
} }

View file

@ -142,6 +142,13 @@
"[variable print][punctuation (][variable foo][property ._123][punctuation )]", "[variable print][punctuation (][variable foo][property ._123][punctuation )]",
"[variable print][punctuation (]") "[variable print][punctuation (]")
MT("nested_comments",
"[comment /*]",
"[comment But wait /* this is a nested comment */ for real]",
"[comment /**** let * me * show * you ****/]",
"[comment ///// let / me / show / you /////]",
"[comment */]");
// TODO: correctly identify when multiple variables are being declared // TODO: correctly identify when multiple variables are being declared
// by use of a comma-separated list. // by use of a comma-separated list.
// TODO: correctly identify when variables are being declared in a tuple. // TODO: correctly identify when variables are being declared in a tuple.

View file

@ -82,7 +82,7 @@ CodeMirror.defineMode("velocity", function() {
} }
// variable? // variable?
else if (ch == "$") { else if (ch == "$") {
stream.eatWhile(/[\w\d\$_\.{}]/); stream.eatWhile(/[\w\d\$_\.{}-]/);
// is it one of the specials? // is it one of the specials?
if (specials && specials.propertyIsEnumerable(stream.current())) { if (specials && specials.propertyIsEnumerable(stream.current())) {
return "keyword"; return "keyword";

View file

@ -52,6 +52,7 @@ var xmlConfig = {
doNotIndent: {}, doNotIndent: {},
allowUnquoted: false, allowUnquoted: false,
allowMissing: false, allowMissing: false,
allowMissingTagName: false,
caseFold: false caseFold: false
} }
@ -226,6 +227,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
state.tagName = stream.current(); state.tagName = stream.current();
setStyle = "tag"; setStyle = "tag";
return attrState; return attrState;
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return attrState(type, stream, state);
} else { } else {
setStyle = "error"; setStyle = "error";
return tagNameState; return tagNameState;
@ -244,6 +248,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
setStyle = "tag error"; setStyle = "tag error";
return closeStateErr; return closeStateErr;
} }
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return closeState(type, stream, state);
} else { } else {
setStyle = "error"; setStyle = "error";
return closeStateErr; return closeStateErr;

View file

@ -108,7 +108,8 @@ CodeMirror.defineMode("yaml", function() {
literal: false, literal: false,
escaped: false escaped: false
}; };
} },
lineComment: "#"
}; };
}); });