'], type: 'action',
+ action: 'scroll',
+ actionArgs: { forward: false, linewise: true }},
{ keys: ['a'], type: 'action', action: 'enterInsertMode', isEdit: true,
actionArgs: { insertAt: 'charAfter' }},
{ keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true,
@@ -324,12 +331,16 @@
CodeMirror.defineOption('vimMode', false, function(cm, val) {
if (val) {
cm.setOption('keyMap', 'vim');
+ cm.setOption('disableInput', true);
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
cm.on('beforeSelectionChange', beforeSelectionChange);
maybeInitVimState(cm);
+ CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
} else if (cm.state.vim) {
cm.setOption('keyMap', 'default');
+ cm.setOption('disableInput', false);
cm.off('beforeSelectionChange', beforeSelectionChange);
+ CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
cm.state.vim = null;
}
});
@@ -342,6 +353,18 @@
head.ch--;
}
}
+ function getOnPasteFn(cm) {
+ var vim = cm.state.vim;
+ if (!vim.onPasteFn) {
+ vim.onPasteFn = function() {
+ if (!vim.insertMode) {
+ cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
+ actions.enterInsertMode(cm, {}, vim);
+ }
+ };
+ }
+ return vim.onPasteFn;
+ }
var numberRegex = /[\d]/;
var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
@@ -549,9 +572,9 @@
maybeInitVimState_: maybeInitVimState,
InsertModeKey: InsertModeKey,
- map: function(lhs, rhs) {
+ map: function(lhs, rhs, ctx) {
// Add user defined key bindings.
- exCommandDispatcher.map(lhs, rhs);
+ exCommandDispatcher.map(lhs, rhs, ctx);
},
defineEx: function(name, prefix, func){
if (name.indexOf(prefix) !== 0) {
@@ -833,11 +856,17 @@
} else {
// Find the best match in the list of matchedCommands.
var context = vim.visualMode ? 'visual' : 'normal';
- var bestMatch = matchedCommands[0]; // Default to first in the list.
+ var bestMatch; // Default to first in the list.
for (var i = 0; i < matchedCommands.length; i++) {
- if (matchedCommands[i].context == context) {
- bestMatch = matchedCommands[i];
+ var current = matchedCommands[i];
+ if (current.context == context) {
+ bestMatch = current;
break;
+ } else if (!bestMatch && !current.context) {
+ // Only set an imperfect match to best match if no best match is
+ // set and the imperfect match is not restricted to another
+ // context.
+ bestMatch = current;
}
}
return getFullyMatchedCommandOrNull(bestMatch);
@@ -1636,6 +1665,43 @@
markPos = markPos ? markPos : cm.getCursor();
cm.setCursor(markPos);
},
+ scroll: function(cm, actionArgs, vim) {
+ if (vim.visualMode) {
+ return;
+ }
+ var repeat = actionArgs.repeat || 1;
+ var lineHeight = cm.defaultTextHeight();
+ var top = cm.getScrollInfo().top;
+ var delta = lineHeight * repeat;
+ var newPos = actionArgs.forward ? top + delta : top - delta;
+ var cursor = cm.getCursor();
+ var cursorCoords = cm.charCoords(cursor, 'local');
+ if (actionArgs.forward) {
+ if (newPos > cursorCoords.top) {
+ cursor.line += (newPos - cursorCoords.top) / lineHeight;
+ cursor.line = Math.ceil(cursor.line);
+ cm.setCursor(cursor);
+ cursorCoords = cm.charCoords(cursor, 'local');
+ cm.scrollTo(null, cursorCoords.top);
+ } else {
+ // Cursor stays within bounds. Just reposition the scroll window.
+ cm.scrollTo(null, newPos);
+ }
+ } else {
+ var newBottom = newPos + cm.getScrollInfo().clientHeight;
+ if (newBottom < cursorCoords.bottom) {
+ cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight;
+ cursor.line = Math.floor(cursor.line);
+ cm.setCursor(cursor);
+ cursorCoords = cm.charCoords(cursor, 'local');
+ cm.scrollTo(
+ null, cursorCoords.bottom - cm.getScrollInfo().clientHeight);
+ } else {
+ // Cursor stays within bounds. Just reposition the scroll window.
+ cm.scrollTo(null, newPos);
+ }
+ }
+ },
scrollToCursor: function(cm, actionArgs) {
var lineNum = cm.getCursor().line;
var charCoords = cm.charCoords({line: lineNum, ch: 0}, 'local');
@@ -1691,6 +1757,7 @@
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
}
cm.setOption('keyMap', 'vim-insert');
+ cm.setOption('disableInput', false);
if (actionArgs && actionArgs.replace) {
// Handle Replace-mode as a special case of insert mode.
cm.toggleOverwrite(true);
@@ -2726,10 +2793,9 @@
return regexp;
}
function showConfirm(cm, text) {
- if (cm.openConfirm) {
- cm.openConfirm('' + text +
- ' ', function() {},
- {bottom: true});
+ if (cm.openNotification) {
+ cm.openNotification('' + text + '',
+ {bottom: true, duration: 5000});
} else {
alert(text);
}
@@ -2897,14 +2963,16 @@
// pair of commands that have a shared prefix, at least one of their
// shortNames must not match the prefix of the other command.
var defaultExCommandMap = [
- { name: 'map', type: 'builtIn' },
- { name: 'write', shortName: 'w', type: 'builtIn' },
- { name: 'undo', shortName: 'u', type: 'builtIn' },
- { name: 'redo', shortName: 'red', type: 'builtIn' },
- { name: 'sort', shortName: 'sor', type: 'builtIn'},
- { name: 'substitute', shortName: 's', type: 'builtIn'},
- { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'},
- { name: 'delmarks', shortName: 'delm', type: 'builtin'}
+ { name: 'map' },
+ { name: 'nmap', shortName: 'nm' },
+ { name: 'vmap', shortName: 'vm' },
+ { name: 'write', shortName: 'w' },
+ { name: 'undo', shortName: 'u' },
+ { name: 'redo', shortName: 'red' },
+ { name: 'sort', shortName: 'sor' },
+ { name: 'substitute', shortName: 's' },
+ { name: 'nohlsearch', shortName: 'noh' },
+ { name: 'delmarks', shortName: 'delm' }
];
Vim.ExCommandDispatcher = function() {
this.buildCommandMap_();
@@ -2956,6 +3024,7 @@
exCommands[commandName](cm, params);
} catch(e) {
showConfirm(cm, e);
+ throw e;
}
},
parseInput_: function(cm, inputStream, result) {
@@ -3038,8 +3107,9 @@
this.commandMap_[key] = command;
}
},
- map: function(lhs, rhs) {
+ map: function(lhs, rhs, ctx) {
if (lhs != ':' && lhs.charAt(0) == ':') {
+ if (ctx) { throw Error('Mode not supported for ex mappings'); }
var commandName = lhs.substring(1);
if (rhs != ':' && rhs.charAt(0) == ':') {
// Ex to Ex mapping
@@ -3059,17 +3129,21 @@
} else {
if (rhs != ':' && rhs.charAt(0) == ':') {
// Key to Ex mapping.
- defaultKeymap.unshift({
+ var mapping = {
keys: parseKeyString(lhs),
type: 'keyToEx',
- exArgs: { input: rhs.substring(1) }});
+ exArgs: { input: rhs.substring(1) }};
+ if (ctx) { mapping.context = ctx; }
+ defaultKeymap.unshift(mapping);
} else {
// Key to key mapping
- defaultKeymap.unshift({
+ var mapping = {
keys: parseKeyString(lhs),
type: 'keyToKey',
toKeys: parseKeyString(rhs)
- });
+ };
+ if (ctx) { mapping.context = ctx; }
+ defaultKeymap.unshift(mapping);
}
}
}
@@ -3091,7 +3165,7 @@
}
var exCommands = {
- map: function(cm, params) {
+ map: function(cm, params, ctx) {
var mapArgs = params.args;
if (!mapArgs || mapArgs.length < 2) {
if (cm) {
@@ -3099,8 +3173,10 @@
}
return;
}
- exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
+ exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);
},
+ nmap: function(cm, params) { this.map(cm, params, 'normal'); },
+ vmap: function(cm, params) { this.map(cm, params, 'visual'); },
move: function(cm, params) {
commandDispatcher.processCommand(cm, cm.state.vim, {
type: 'motion',
@@ -3116,7 +3192,7 @@
var args = new CodeMirror.StringStream(params.argString);
if (args.eat('!')) { reverse = true; }
if (args.eol()) { return; }
- if (!args.eatSpace()) { throw new Error('invalid arguments ' + args.match(/.*/)[0]); }
+ if (!args.eatSpace()) { return 'Invalid arguments'; }
var opts = args.match(/[a-z]+/);
if (opts) {
opts = opts[0];
@@ -3125,13 +3201,17 @@
var decimal = opts.indexOf('d') != -1 && 1;
var hex = opts.indexOf('x') != -1 && 1;
var octal = opts.indexOf('o') != -1 && 1;
- if (decimal + hex + octal > 1) { throw new Error('invalid arguments'); }
+ if (decimal + hex + octal > 1) { return 'Invalid arguments'; }
number = decimal && 'decimal' || hex && 'hex' || octal && 'octal';
}
- if (args.eatSpace() && args.match(/\/.*\//)) { throw new Error('patterns not supported'); }
+ if (args.eatSpace() && args.match(/\/.*\//)) { 'patterns not supported'; }
}
}
- parseArgs();
+ var err = parseArgs();
+ if (err) {
+ showConfirm(cm, err + ': ' + params.argString);
+ return;
+ }
var lineStart = params.line || cm.firstLine();
var lineEnd = params.lineEnd || params.line || cm.lastLine();
if (lineStart == lineEnd) { return; }
@@ -3252,13 +3332,13 @@
clearSearchHighlight(cm);
},
delmarks: function(cm, params) {
- if (!params.argString || !params.argString.trim()) {
+ if (!params.argString || !trim(params.argString)) {
showConfirm(cm, 'Argument required');
return;
}
var state = cm.state.vim;
- var stream = new CodeMirror.StringStream(params.argString.trim());
+ var stream = new CodeMirror.StringStream(trim(params.argString));
while (!stream.eol()) {
stream.eatSpace();
@@ -3395,7 +3475,8 @@
// Actually do replace.
next();
if (done) {
- throw new Error('No matches for ' + query.source);
+ showConfirm(cm, 'No matches for ' + query.source);
+ return;
}
if (!confirm) {
replaceAll();
@@ -3446,7 +3527,6 @@
var cmToVimKeymap = {
'nofallthrough': true,
- 'disableInput': true,
'style': 'fat-cursor'
};
function bindKeys(keys, modifier) {
@@ -3493,6 +3573,7 @@
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
vim.insertMode = false;
cm.setOption('keyMap', 'vim');
+ cm.setOption('disableInput', true);
cm.toggleOverwrite(false); // exit replace mode if we were in it.
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
}
diff --git a/applications/admin/static/codemirror/lib/codemirror.js b/applications/admin/static/codemirror/lib/codemirror.js
index 7b48bf5f..d82bd143 100644
--- a/applications/admin/static/codemirror/lib/codemirror.js
+++ b/applications/admin/static/codemirror/lib/codemirror.js
@@ -1,4 +1,4 @@
-// CodeMirror version 3.19
+// CodeMirror version 3.21
//
// CodeMirror is the only global var we claim
window.CodeMirror = (function() {
@@ -9,9 +9,14 @@ window.CodeMirror = (function() {
// Crude, but necessary to handle a number of hard-to-feature-detect
// bugs and behavior differences.
var gecko = /gecko\/\d/i.test(navigator.userAgent);
- var ie = /MSIE \d/.test(navigator.userAgent);
- var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8);
- var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
+ // IE11 currently doesn't count as 'ie', since it has almost none of
+ // the same bugs as earlier versions. Use ie_gt10 to handle
+ // incompatibilities in that version.
+ var old_ie = /MSIE \d/.test(navigator.userAgent);
+ var ie_lt8 = old_ie && (document.documentMode == null || document.documentMode < 8);
+ var ie_lt9 = old_ie && (document.documentMode == null || document.documentMode < 9);
+ var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
+ var ie = old_ie || ie_gt10;
var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(navigator.userAgent);
@@ -33,7 +38,7 @@ window.CodeMirror = (function() {
if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11));
- var captureMiddleClick = gecko || (ie && !ie_lt9);
+ var captureMiddleClick = gecko || (old_ie && !ie_lt9);
// Optimize some code when these features are not used
var sawReadOnlySpans = false, sawCollapsedSpans = false;
@@ -59,7 +64,8 @@ window.CodeMirror = (function() {
overlays: [],
modeGen: 0,
overwrite: false, focused: false,
- suppressEdits: false, pasteIncoming: false,
+ suppressEdits: false,
+ pasteIncoming: false, cutIncoming: false,
draggingText: false,
highlight: new Delayed()};
@@ -73,7 +79,7 @@ window.CodeMirror = (function() {
// Override magic textarea content restore that IE sometimes does
// on our hidden textarea on reload
- if (ie) setTimeout(bind(resetInput, this, true), 20);
+ if (old_ie) setTimeout(bind(resetInput, this, true), 20);
registerEventHandlers(this);
// IE throws unspecified error in certain cases, when
@@ -193,6 +199,10 @@ window.CodeMirror = (function() {
function loadMode(cm) {
cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
+ resetModeState(cm);
+ }
+
+ function resetModeState(cm) {
cm.doc.iter(function(line) {
if (line.stateAfter) line.stateAfter = null;
if (line.styles) line.styles = null;
@@ -242,7 +252,6 @@ window.CodeMirror = (function() {
var map = keyMap[cm.options.keyMap], style = map.style;
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
(style ? " cm-keymap-" + style : "");
- cm.state.disableInput = map.disableInput;
}
function themeChanged(cm) {
@@ -448,7 +457,7 @@ window.CodeMirror = (function() {
// updates.
function updateDisplayInner(cm, changes, visible, forced) {
var display = cm.display, doc = cm.doc;
- if (!display.wrapper.clientWidth) {
+ if (!display.wrapper.offsetWidth) {
display.showingFrom = display.showingTo = doc.first;
display.viewOffset = 0;
return;
@@ -533,6 +542,7 @@ window.CodeMirror = (function() {
}
display.showingFrom = from; display.showingTo = to;
+ display.gutters.style.height = "";
updateHeightsInViewport(cm);
updateViewOffset(cm);
@@ -715,9 +725,9 @@ window.CodeMirror = (function() {
if (bgClass)
wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground"), wrap.firstChild);
if (cm.options.lineNumbers || markers) {
- var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " +
+ var gutterWrap = wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
(cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
- wrap.firstChild);
+ lineElement);
if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push(gutterWrap);
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
wrap.lineNumber = gutterWrap.appendChild(
@@ -908,7 +918,7 @@ window.CodeMirror = (function() {
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) {
if (doc.frontier >= cm.display.showingFrom) { // Visible
var oldStyles = line.styles;
- line.styles = highlightLine(cm, line, state);
+ line.styles = highlightLine(cm, line, state, true);
var ischange = !oldStyles || oldStyles.length != line.styles.length;
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) {
@@ -917,7 +927,7 @@ window.CodeMirror = (function() {
}
line.stateAfter = copyState(doc.mode, state);
} else {
- processLine(cm, line, state);
+ processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
}
++doc.frontier;
@@ -961,7 +971,7 @@ window.CodeMirror = (function() {
if (!state) state = startState(doc.mode);
else state = copyState(doc.mode, state);
doc.iter(pos, n, function(line) {
- processLine(cm, line, state);
+ processLine(cm, line.text, state);
var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo;
line.stateAfter = save ? copyState(doc.mode, state) : null;
++pos;
@@ -1051,7 +1061,7 @@ window.CodeMirror = (function() {
// doesn't work when wrapping is on, but in that case the
// situation is slightly better, since IE does cache line-wrapping
// information and only recomputes per-line.
- if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
+ if (old_ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
var fragment = document.createDocumentFragment();
var chunk = 10, n = pre.childNodes.length;
for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
@@ -1111,7 +1121,7 @@ window.CodeMirror = (function() {
}
}
if (!rect) rect = data[i] = measureRect(getRect(node));
- if (cur.measureRight) rect.right = getRect(cur.measureRight).left;
+ if (cur.measureRight) rect.right = getRect(cur.measureRight).left - outer.left;
if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide));
}
removeChildren(cm.display.measure);
@@ -1287,7 +1297,7 @@ window.CodeMirror = (function() {
if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
var ch = x < fromX || x - fromX <= toX - x ? from : to;
var xDiff = x - (ch == from ? fromX : toX);
- while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
xDiff < 0 ? -1 : xDiff ? 1 : 0);
return pos;
@@ -1385,8 +1395,10 @@ window.CodeMirror = (function() {
}
if (!updated && op.selectionChanged) updateSelection(cm);
if (op.updateScrollPos) {
- display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop;
- display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft;
+ var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, newScrollPos.scrollTop));
+ var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, newScrollPos.scrollLeft));
+ display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
+ display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
alignHorizontally(cm);
if (op.scrollToPos)
scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
@@ -1477,7 +1489,7 @@ window.CodeMirror = (function() {
// supported or compatible enough yet to rely on.)
function readInput(cm) {
var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel;
- if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false;
+ if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
input.value = input.value.substring(0, input.value.length - 1);
cm.state.fakedLastChar = false;
@@ -1495,22 +1507,32 @@ window.CodeMirror = (function() {
var same = 0, l = Math.min(prevInput.length, text.length);
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
var from = sel.from, to = sel.to;
+ var inserted = text.slice(same);
if (same < prevInput.length)
from = Pos(from.line, from.ch - (prevInput.length - same));
else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming)
- to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same)));
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + inserted.length));
var updateInput = cm.curOp.updateInput;
- var changeEvent = {from: from, to: to, text: splitLines(text.slice(same)),
- origin: cm.state.pasteIncoming ? "paste" : "+input"};
+ var changeEvent = {from: from, to: to, text: splitLines(inserted),
+ origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
makeChange(cm.doc, changeEvent, "end");
cm.curOp.updateInput = updateInput;
signalLater(cm, "inputRead", cm, changeEvent);
+ if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
+ cm.options.smartIndent && sel.head.ch < 100) {
+ var electric = cm.getModeAt(sel.head).electricChars;
+ if (electric) for (var i = 0; i < electric.length; i++)
+ if (inserted.indexOf(electric.charAt(i)) > -1) {
+ indentLine(cm, sel.head.line, "smart");
+ break;
+ }
+ }
if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
else cm.display.prevInput = text;
if (withOp) endOperation(cm);
- cm.state.pasteIncoming = false;
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
return true;
}
@@ -1545,7 +1567,7 @@ window.CodeMirror = (function() {
function registerEventHandlers(cm) {
var d = cm.display;
on(d.scroller, "mousedown", operation(cm, onMouseDown));
- if (ie)
+ if (old_ie)
on(d.scroller, "dblclick", operation(cm, function(e) {
if (signalDOMEvent(cm, e)) return;
var pos = posFromMouse(cm, e);
@@ -1651,21 +1673,22 @@ window.CodeMirror = (function() {
fastPoll(cm);
});
- function prepareCopy() {
+ function prepareCopy(e) {
if (d.inaccurateSelection) {
d.prevInput = "";
d.inaccurateSelection = false;
d.input.value = cm.getSelection();
selectInput(d.input);
}
+ if (e.type == "cut") cm.state.cutIncoming = true;
}
on(d.input, "cut", prepareCopy);
on(d.input, "copy", prepareCopy);
// Needed to handle Tab key in KHTML
if (khtml) on(d.sizer, "mouseup", function() {
- if (document.activeElement == d.input) d.input.blur();
- focusInput(cm);
+ if (document.activeElement == d.input) d.input.blur();
+ focusInput(cm);
});
}
@@ -1749,6 +1772,9 @@ window.CodeMirror = (function() {
e_preventDefault(e2);
extendSelection(cm.doc, start);
focusInput(cm);
+ // Work around unexplainable focus problem in IE9 (#2127)
+ if (old_ie && !ie_lt9)
+ setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
}
});
// Let the drag handler handle this.
@@ -1823,7 +1849,7 @@ window.CodeMirror = (function() {
}
var move = operation(cm, function(e) {
- if (!ie && !e_button(e)) done(e);
+ if (!old_ie && !e_button(e)) done(e);
else extend(e);
});
var up = operation(cm, done);
@@ -1905,7 +1931,6 @@ window.CodeMirror = (function() {
if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste");
cm.replaceSelection(text, null, "paste");
focusInput(cm);
- onFocus(cm);
}
}
catch(e){}
@@ -1969,7 +1994,7 @@ window.CodeMirror = (function() {
// know one. These don't have to be accurate -- the result of them
// being wrong would just be a slight flicker on the first wheel
// scroll (if it is large enough).
- if (ie) wheelPixelsPerUnit = -.53;
+ if (old_ie) wheelPixelsPerUnit = -.53;
else if (gecko) wheelPixelsPerUnit = 15;
else if (chrome) wheelPixelsPerUnit = -.7;
else if (safari) wheelPixelsPerUnit = -1/3;
@@ -2123,7 +2148,7 @@ window.CodeMirror = (function() {
var cm = this;
if (!cm.state.focused) onFocus(cm);
if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
- if (ie && e.keyCode == 27) e.returnValue = false;
+ if (old_ie && e.keyCode == 27) e.returnValue = false;
var code = e.keyCode;
// IE does strange things with escape.
cm.doc.sel.shift = code == 16 || e.shiftKey;
@@ -2144,10 +2169,6 @@ window.CodeMirror = (function() {
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
- if (this.options.electricChars && this.doc.mode.electricChars &&
- this.options.smartIndent && !isReadOnly(this) &&
- this.doc.mode.electricChars.indexOf(ch) > -1)
- setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75);
if (handleCharBinding(cm, e, ch)) return;
if (ie && !ie_lt9) cm.display.inputHasSelection = null;
fastPoll(cm);
@@ -2196,7 +2217,7 @@ window.CodeMirror = (function() {
var oldCSS = display.input.style.cssText;
display.inputDiv.style.position = "absolute";
display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
- "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: transparent; outline: none;" +
"border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);";
focusInput(cm);
resetInput(cm, true);
@@ -2218,10 +2239,10 @@ window.CodeMirror = (function() {
// Try to detect the user choosing select-all
if (display.input.selectionStart != null) {
- if (!ie || ie_lt9) prepareSelectAllHack();
+ if (!old_ie || ie_lt9) prepareSelectAllHack();
clearTimeout(detectingSelectAll);
var i = 0, poll = function(){
- if (display.prevInput == " " && display.input.selectionStart == 0)
+ if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
operation(cm, commands.selectAll)(cm);
else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
else resetInput(cm);
@@ -2230,7 +2251,7 @@ window.CodeMirror = (function() {
}
}
- if (ie && !ie_lt9) prepareSelectAllHack();
+ if (old_ie && !ie_lt9) prepareSelectAllHack();
if (captureMiddleClick) {
e_stop(e);
var mouseup = function() {
@@ -2503,6 +2524,7 @@ window.CodeMirror = (function() {
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
+ function cmp(a, b) {return a.line - b.line || a.ch - b.ch;}
function copyPos(x) {return Pos(x.line, x.ch);}
// SELECTION
@@ -2647,14 +2669,13 @@ window.CodeMirror = (function() {
if (coords.top + box.top < 0) doScroll = true;
else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
if (doScroll != null && !phantom) {
- var hidden = display.cursor.style.display == "none";
- if (hidden) {
- display.cursor.style.display = "";
- display.cursor.style.left = coords.left + "px";
- display.cursor.style.top = (coords.top - display.viewOffset) + "px";
- }
- display.cursor.scrollIntoView(doScroll);
- if (hidden) display.cursor.style.display = "none";
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
+ (coords.top - display.viewOffset) + "px; height: " +
+ (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
+ coords.left + "px; width: 2px;");
+ cm.display.lineSpace.appendChild(scrollNode);
+ scrollNode.scrollIntoView(doScroll);
+ cm.display.lineSpace.removeChild(scrollNode);
}
}
@@ -2737,7 +2758,10 @@ window.CodeMirror = (function() {
var tabSize = cm.options.tabSize;
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
- if (how == "smart") {
+ if (!aggressive && !/\S/.test(line.text)) {
+ indentation = 0;
+ how = "not";
+ } else if (how == "smart") {
indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
if (indentation == Pass) {
if (!aggressive) return;
@@ -2763,6 +2787,8 @@ window.CodeMirror = (function() {
if (indentString != curSpaceString)
replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+ else if (doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length)
+ setSelection(doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length), 1);
line.stateAfter = null;
}
@@ -2863,7 +2889,7 @@ window.CodeMirror = (function() {
CodeMirror.prototype = {
constructor: CodeMirror,
- focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);},
+ focus: function(){window.focus(); focusInput(this); fastPoll(this);},
setOption: function(option, value) {
var options = this.options, old = options[option];
@@ -2917,7 +2943,7 @@ window.CodeMirror = (function() {
}),
indentSelection: operation(null, function(how) {
var sel = this.doc.sel;
- if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
+ if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how, true);
var e = sel.to.line - (sel.to.ch ? 0 : 1);
for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
}),
@@ -2962,11 +2988,31 @@ window.CodeMirror = (function() {
},
getHelper: function(pos, type) {
- if (!helpers.hasOwnProperty(type)) return;
+ return this.getHelpers(pos, type)[0];
+ },
+
+ getHelpers: function(pos, type) {
+ var found = [];
+ if (!helpers.hasOwnProperty(type)) return helpers;
var help = helpers[type], mode = this.getModeAt(pos);
- return mode[type] && help[mode[type]] ||
- mode.helperType && help[mode.helperType] ||
- help[mode.name];
+ if (typeof mode[type] == "string") {
+ if (help[mode[type]]) found.push(help[mode[type]]);
+ } else if (mode[type]) {
+ for (var i = 0; i < mode[type].length; i++) {
+ var val = help[mode[type][i]];
+ if (val) found.push(val);
+ }
+ } else if (mode.helperType && help[mode.helperType]) {
+ found.push(help[mode.helperType]);
+ } else if (help[mode.name]) {
+ found.push(help[mode.name]);
+ }
+ for (var i = 0; i < help._global.length; i++) {
+ var cur = help._global[i];
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+ found.push(cur.val);
+ }
+ return found;
},
getStateAfter: function(line, precise) {
@@ -3113,7 +3159,10 @@ window.CodeMirror = (function() {
triggerOnKeyDown: operation(null, onKeyDown),
- execCommand: function(cmd) {return commands[cmd](this);},
+ execCommand: function(cmd) {
+ if (commands.hasOwnProperty(cmd))
+ return commands[cmd](this);
+ },
findPosH: function(from, amount, unit, visually) {
var dir = 1;
@@ -3155,14 +3204,18 @@ window.CodeMirror = (function() {
},
moveV: operation(null, function(dir, unit) {
- var sel = this.doc.sel;
- var pos = cursorCoords(this, sel.head, "div");
- if (sel.goalColumn != null) pos.left = sel.goalColumn;
- var target = findPosV(this, pos, dir, unit);
-
- if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
+ var sel = this.doc.sel, target, goal;
+ if (sel.shift || sel.extend || posEq(sel.from, sel.to)) {
+ var pos = cursorCoords(this, sel.head, "div");
+ if (sel.goalColumn != null) pos.left = sel.goalColumn;
+ target = findPosV(this, pos, dir, unit);
+ if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
+ goal = pos.left;
+ } else {
+ target = dir < 0 ? sel.from : sel.to;
+ }
extendSelection(this.doc, target, target, dir);
- sel.goalColumn = pos.left;
+ if (goal != null) sel.goalColumn = goal;
}),
toggleOverwrite: function(value) {
@@ -3272,12 +3325,18 @@ window.CodeMirror = (function() {
option("indentWithTabs", false);
option("smartIndent", true);
option("tabSize", 4, function(cm) {
- loadMode(cm);
+ resetModeState(cm);
clearCaches(cm);
regChange(cm);
}, true);
+ option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
+ cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+ cm.refresh();
+ }, true);
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
option("electricChars", true);
option("rtlMoveVisually", !windows);
+ option("wholeLineUpdateBefore", true);
option("theme", "default", function(cm) {
themeChanged(cm);
@@ -3310,9 +3369,16 @@ window.CodeMirror = (function() {
option("resetSelectionOnContextMenu", true);
option("readOnly", false, function(cm, val) {
- if (val == "nocursor") {onBlur(cm); cm.display.input.blur();}
- else if (!val) resetInput(cm, true);
+ if (val == "nocursor") {
+ onBlur(cm);
+ cm.display.input.blur();
+ cm.display.disabled = true;
+ } else {
+ cm.display.disabled = false;
+ if (!val) resetInput(cm, true);
+ }
});
+ option("disableInput", false, function(cm, val) {if (!val) resetInput(cm, true);}, true);
option("dragDrop", true);
option("cursorBlinkRate", 530);
@@ -3320,12 +3386,13 @@ window.CodeMirror = (function() {
option("cursorHeight", 1);
option("workTime", 100);
option("workDelay", 100);
- option("flattenSpans", true);
+ option("flattenSpans", true, resetModeState, true);
+ option("addModeClass", false, resetModeState, true);
option("pollInterval", 100);
option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;});
option("historyEventDelay", 500);
option("viewportMargin", 10, function(cm){cm.refresh();}, true);
- option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true);
+ option("maxHighlightLength", 10000, resetModeState, true);
option("crudeMeasuringFrom", 10000);
option("moveInputWithCursor", true, function(cm, val) {
if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
@@ -3382,6 +3449,9 @@ window.CodeMirror = (function() {
}
}
modeObj.name = spec.name;
+ if (spec.helperType) modeObj.helperType = spec.helperType;
+ if (spec.modeProps) for (var prop in spec.modeProps)
+ modeObj[prop] = spec.modeProps[prop];
return modeObj;
};
@@ -3412,9 +3482,13 @@ window.CodeMirror = (function() {
var helpers = CodeMirror.helpers = {};
CodeMirror.registerHelper = function(type, name, value) {
- if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {};
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
helpers[type][name] = value;
};
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+ CodeMirror.registerHelper(type, name, value);
+ helpers[type]._global.push({pred: predicate, val: value});
+ };
// UTILITIES
@@ -3519,7 +3593,9 @@ window.CodeMirror = (function() {
indentAuto: function(cm) {cm.indentSelection("smart");},
indentMore: function(cm) {cm.indentSelection("add");},
indentLess: function(cm) {cm.indentSelection("subtract");},
- insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");},
+ insertTab: function(cm) {
+ cm.replaceSelection("\t", "end", "+input");
+ },
defaultTab: function(cm) {
if (cm.somethingSelected()) cm.indentSelection("add");
else cm.replaceSelection("\t", "end", "+input");
@@ -3692,11 +3768,12 @@ window.CodeMirror = (function() {
this.string = string;
this.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0;
+ this.lineStart = 0;
}
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
- sol: function() {return this.pos == 0;},
+ sol: function() {return this.pos == this.lineStart;},
peek: function() {return this.string.charAt(this.pos) || undefined;},
next: function() {
if (this.pos < this.string.length)
@@ -3729,9 +3806,12 @@ window.CodeMirror = (function() {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start;
}
- return this.lastColumnValue;
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ indentation: function() {
+ return countColumn(this.string, null, this.tabSize) -
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
- indentation: function() {return countColumn(this.string, null, this.tabSize);},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
@@ -3747,7 +3827,12 @@ window.CodeMirror = (function() {
return match;
}
},
- current: function(){return this.string.slice(this.start, this.pos);}
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
};
CodeMirror.StringStream = StringStream;
@@ -3799,7 +3884,7 @@ window.CodeMirror = (function() {
if (withOp) endOperation(cm);
};
- TextMarker.prototype.find = function() {
+ TextMarker.prototype.find = function(bothSides) {
var from, to;
for (var i = 0; i < this.lines.length; ++i) {
var line = this.lines[i];
@@ -3810,7 +3895,7 @@ window.CodeMirror = (function() {
if (span.to != null) to = Pos(found, span.to);
}
}
- if (this.type == "bookmark") return from;
+ if (this.type == "bookmark" && !bothSides) return from;
return from && {from: from, to: to};
};
@@ -3847,37 +3932,40 @@ window.CodeMirror = (function() {
}
};
+ var nextMarkerId = 0;
+
function markText(doc, from, to, options, type) {
if (options && options.shared) return markTextShared(doc, from, to, options, type);
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
var marker = new TextMarker(doc, type);
- if (type == "range" && !posLess(from, to)) return marker;
if (options) copyObj(options, marker);
+ if (posLess(to, from) || posEq(from, to) && marker.clearWhenEmpty !== false)
+ return marker;
if (marker.replacedWith) {
marker.collapsed = true;
marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true;
}
- if (marker.collapsed) sawCollapsedSpans = true;
+ if (marker.collapsed) {
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
+ sawCollapsedSpans = true;
+ }
if (marker.addToHistory)
addToHistory(doc, {from: from, to: to, origin: "markText"},
{head: doc.sel.head, anchor: doc.sel.anchor}, NaN);
- var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd, cm = doc.cm, updateMaxLine;
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
doc.iter(curLine, to.line + 1, function(line) {
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine)
updateMaxLine = true;
var span = {from: null, to: null, marker: marker};
- size += line.text.length;
- if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
- if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
- if (marker.collapsed) {
- if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
- if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
- else updateLineHeight(line, 0);
- }
+ if (curLine == from.line) span.from = from.ch;
+ if (curLine == to.line) span.to = to.ch;
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
addMarkedSpan(line, span);
++curLine;
});
@@ -3893,9 +3981,7 @@ window.CodeMirror = (function() {
doc.clearHistory();
}
if (marker.collapsed) {
- if (collapsedAtStart != collapsedAtEnd)
- throw new Error("Inserting collapsed marker overlapping an existing one");
- marker.size = size;
+ marker.id = ++nextMarkerId;
marker.atomic = true;
}
if (cm) {
@@ -3968,7 +4054,7 @@ window.CodeMirror = (function() {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
- if (startsBefore || marker.type == "bookmark" && span.from == startCh && (!isInsert || !span.marker.insertLeft)) {
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
(nw || (nw = [])).push({from: span.from,
to: endsAfter ? null : span.to,
@@ -3982,7 +4068,7 @@ window.CodeMirror = (function() {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
- if (endsAfter || marker.type == "bookmark" && span.from == endCh && (!isInsert || span.marker.insertLeft)) {
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
(nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
to: span.to == null ? null : span.to - endCh,
@@ -4032,13 +4118,9 @@ window.CodeMirror = (function() {
}
}
}
- if (sameLine && first) {
- // Make sure we didn't create any zero-length spans
- for (var i = 0; i < first.length; ++i)
- if (first[i].from != null && first[i].from == first[i].to && first[i].marker.type != "bookmark")
- first.splice(i--, 1);
- if (!first.length) first = null;
- }
+ // Make sure we didn't create any zero-length spans
+ if (first) first = clearEmptySpans(first);
+ if (last && last != first) last = clearEmptySpans(last);
var newMarkers = [first];
if (!sameLine) {
@@ -4055,6 +4137,16 @@ window.CodeMirror = (function() {
return newMarkers;
}
+ function clearEmptySpans(spans) {
+ for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+ spans.splice(i--, 1);
+ }
+ if (!spans.length) return null;
+ return spans;
+ }
+
function mergeOldSpans(doc, change) {
var old = getOldSpans(doc, change);
var stretched = stretchSpansOverChange(doc, change);
@@ -4105,20 +4197,48 @@ window.CodeMirror = (function() {
return parts;
}
- function collapsedSpanAt(line, ch) {
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
+
+ function compareCollapsedMarkers(a, b) {
+ var lenDiff = a.lines.length - b.lines.length;
+ if (lenDiff != 0) return lenDiff;
+ var aPos = a.find(), bPos = b.find();
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+ if (fromCmp) return -fromCmp;
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+ if (toCmp) return toCmp;
+ return b.id - a.id;
+ }
+
+ function collapsedSpanAtSide(line, start) {
var sps = sawCollapsedSpans && line.markedSpans, found;
if (sps) for (var sp, i = 0; i < sps.length; ++i) {
sp = sps[i];
- if (!sp.marker.collapsed) continue;
- if ((sp.from == null || sp.from < ch) &&
- (sp.to == null || sp.to > ch) &&
- (!found || found.width < sp.marker.width))
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
found = sp.marker;
}
return found;
}
- function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
- function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
+
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
+ var line = getLine(doc, lineNo);
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ var found = sp.marker.find(true);
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
+ if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
+ fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
+ return true;
+ }
+ }
function visualLine(doc, line) {
var merged;
@@ -4148,6 +4268,7 @@ window.CodeMirror = (function() {
for (var sp, i = 0; i < line.markedSpans.length; ++i) {
sp = line.markedSpans[i];
if (sp.marker.collapsed && !sp.marker.replacedWith && sp.from == span.to &&
+ (sp.to == null || sp.to != span.from) &&
(sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
lineIsHiddenInner(doc, line, sp)) return true;
}
@@ -4241,6 +4362,7 @@ window.CodeMirror = (function() {
this.height = estimateHeight ? estimateHeight(this) : 1;
};
eventMixin(Line);
+ Line.prototype.lineNo = function() { return lineNo(this); };
function updateLine(line, text, markedSpans, estimateHeight) {
line.text = text;
@@ -4261,7 +4383,7 @@ window.CodeMirror = (function() {
// Run the given mode's parser over a line, update the styles
// array, which contains alternating fragments of text and CSS
// classes.
- function runMode(cm, text, mode, state, f) {
+ function runMode(cm, text, mode, state, f, forceToEnd) {
var flattenSpans = mode.flattenSpans;
if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
var curStart = 0, curStyle = null;
@@ -4270,11 +4392,16 @@ window.CodeMirror = (function() {
while (!stream.eol()) {
if (stream.pos > cm.options.maxHighlightLength) {
flattenSpans = false;
+ if (forceToEnd) processLine(cm, text, state, stream.pos);
stream.pos = text.length;
style = null;
} else {
style = mode.token(stream, state);
}
+ if (cm.options.addModeClass) {
+ var mName = CodeMirror.innerMode(mode, state).mode.name;
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
+ }
if (!flattenSpans || curStyle != style) {
if (curStart < stream.start) f(stream.start, curStyle);
curStart = stream.start; curStyle = style;
@@ -4289,12 +4416,14 @@ window.CodeMirror = (function() {
}
}
- function highlightLine(cm, line, state) {
+ function highlightLine(cm, line, state, forceToEnd) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
var st = [cm.state.modeGen];
// Compute the base array of styles
- runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end, style);});
+ runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
+ st.push(end, style);
+ }, forceToEnd);
// Run overlays, adjust style array.
for (var o = 0; o < cm.state.overlays.length; ++o) {
@@ -4333,17 +4462,18 @@ window.CodeMirror = (function() {
// Lightweight form of highlight -- proceed over this line and
// update state, but don't save a style array.
- function processLine(cm, line, state) {
+ function processLine(cm, text, state, startAt) {
var mode = cm.doc.mode;
- var stream = new StringStream(line.text, cm.options.tabSize);
- if (line.text == "" && mode.blankLine) mode.blankLine(state);
+ var stream = new StringStream(text, cm.options.tabSize);
+ stream.start = stream.pos = startAt || 0;
+ if (text == "" && mode.blankLine) mode.blankLine(state);
while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
mode.token(stream, state);
stream.start = stream.pos;
}
}
- var styleToClassCache = {};
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
function interpretTokenStyle(style, builder) {
if (!style) return null;
for (;;) {
@@ -4356,8 +4486,9 @@ window.CodeMirror = (function() {
else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
builder[prop] += " " + lineClass[2];
}
- return styleToClassCache[style] ||
- (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
+ var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ return cache[style] ||
+ (cache[style] = "cm-" + style.replace(/ +/g, " cm-"));
}
function buildLineContent(cm, realLine, measure, copyWidgets) {
@@ -4374,7 +4505,7 @@ window.CodeMirror = (function() {
builder.measure = line == realLine && measure;
builder.pos = 0;
builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
- if ((ie || webkit) && cm.getOption("lineWrapping"))
+ if ((old_ie || webkit) && cm.getOption("lineWrapping"))
builder.addToken = buildTokenSplitSpaces(builder.addToken);
var next = insertLineContent(line, builder, getLineStyles(cm, line));
if (measure && line == realLine && !builder.measuredSomething) {
@@ -4411,17 +4542,23 @@ window.CodeMirror = (function() {
return builder;
}
- var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;
+ function defaultSpecialCharPlaceholder(ch) {
+ var token = elt("span", "\u2022", "cm-invalidchar");
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
+ return token;
+ }
+
function buildToken(builder, text, style, startStyle, endStyle, title) {
if (!text) return;
- if (!tokenSpecialChars.test(text)) {
+ var special = builder.cm.options.specialChars;
+ if (!special.test(text)) {
builder.col += text.length;
var content = document.createTextNode(text);
} else {
var content = document.createDocumentFragment(), pos = 0;
while (true) {
- tokenSpecialChars.lastIndex = pos;
- var m = tokenSpecialChars.exec(text);
+ special.lastIndex = pos;
+ var m = special.exec(text);
var skipped = m ? m.index - pos : text.length - pos;
if (skipped) {
content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
@@ -4434,8 +4571,7 @@ window.CodeMirror = (function() {
content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
builder.col += tabWidth;
} else {
- var token = elt("span", "\u2022", "cm-invalidchar");
- token.title = "\\u" + m[0].charCodeAt(0).toString(16);
+ var token = builder.cm.options.specialCharPlaceholder(m[0]);
content.appendChild(token);
builder.col += 1;
}
@@ -4455,13 +4591,12 @@ window.CodeMirror = (function() {
function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
var wrapping = builder.cm.options.lineWrapping;
for (var i = 0; i < text.length; ++i) {
- var ch = text.charAt(i), start = i == 0;
- if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) {
- ch = text.slice(i, i + 2);
- ++i;
- } else if (i && wrapping && spanAffectsWrapping(text, i)) {
+ var start = i == 0, to = i + 1;
+ while (to < text.length && isExtendingChar(text.charAt(to))) ++to;
+ var ch = text.slice(i, to);
+ i = to - 1;
+ if (i && wrapping && spanAffectsWrapping(text, i))
builder.pre.appendChild(elt("wbr"));
- }
var old = builder.measure[builder.pos];
var span = builder.measure[builder.pos] =
buildToken(builder, ch, style,
@@ -4470,7 +4605,7 @@ window.CodeMirror = (function() {
// In IE single-space nodes wrap differently than spaces
// embedded in larger text nodes, except when set to
// white-space: normal (issue #1268).
- if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
+ if (old_ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
i < text.length - 1 && !/\s/.test(text.charAt(i + 1)))
span.style.whiteSpace = "normal";
builder.pos += ch.length;
@@ -4538,7 +4673,7 @@ window.CodeMirror = (function() {
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
if (m.title && !title) title = m.title;
- if (m.collapsed && (!collapsed || collapsed.marker.size < m.size))
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
} else if (sp.from > pos && nextChange > sp.from) {
nextChange = sp.from;
@@ -4588,7 +4723,8 @@ window.CodeMirror = (function() {
var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
// First adjust the line structure
- if (from.ch == 0 && to.ch == 0 && lastText == "") {
+ if (from.ch == 0 && to.ch == 0 && lastText == "" &&
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore)) {
// This is a whole-line replace. Treated specially to make
// sure line objects move the way they are supposed to.
for (var i = 0, e = text.length - 1, added = []; i < e; ++i)
@@ -4870,10 +5006,11 @@ window.CodeMirror = (function() {
clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);},
markClean: function() {
- this.cleanGeneration = this.changeGeneration();
+ this.cleanGeneration = this.changeGeneration(true);
},
- changeGeneration: function() {
- this.history.lastOp = this.history.lastOrigin = null;
+ changeGeneration: function(forceSplit) {
+ if (forceSplit)
+ this.history.lastOp = this.history.lastOrigin = null;
return this.history.generation;
},
isClean: function (gen) {
@@ -4895,7 +5032,8 @@ window.CodeMirror = (function() {
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
- insertLeft: options && options.insertLeft};
+ insertLeft: options && options.insertLeft,
+ clearWhenEmpty: false};
pos = clipPos(this, pos);
return markText(this, pos, pos, realOpts, "bookmark");
},
@@ -5176,10 +5314,10 @@ window.CodeMirror = (function() {
anchorBefore: doc.sel.anchor, headBefore: doc.sel.head,
anchorAfter: selAfter.anchor, headAfter: selAfter.head};
hist.done.push(cur);
- hist.generation = ++hist.maxGeneration;
while (hist.done.length > hist.undoDepth)
hist.done.shift();
}
+ hist.generation = ++hist.maxGeneration;
hist.lastTime = time;
hist.lastOp = opId;
hist.lastOrigin = change.origin;
@@ -5475,7 +5613,8 @@ window.CodeMirror = (function() {
return true;
}
- var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/;
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
// DOM UTILITIES
@@ -5548,7 +5687,7 @@ window.CodeMirror = (function() {
if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true;
if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false;
}
- return /[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
+ return /[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|\u2026[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
};
var knownScrollbarWidth;
@@ -5616,14 +5755,14 @@ window.CodeMirror = (function() {
var keyNames = {3: "Enter", 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",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
- 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
- 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
- 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
- 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
CodeMirror.keyNames = keyNames;
(function() {
// Number keys
- for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
// Alphabetic keys
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
// Function keys
@@ -5680,29 +5819,29 @@ window.CodeMirror = (function() {
}
var bidiOther;
function getBidiPartAt(order, pos) {
+ bidiOther = null;
for (var i = 0, found; i < order.length; ++i) {
var cur = order[i];
- if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; }
- if (cur.from == pos || cur.to == pos) {
+ if (cur.from < pos && cur.to > pos) return i;
+ if ((cur.from == pos || cur.to == pos)) {
if (found == null) {
found = i;
} else if (compareBidiLevel(order, cur.level, order[found].level)) {
- bidiOther = found;
+ if (cur.from != cur.to) bidiOther = found;
return i;
} else {
- bidiOther = i;
+ if (cur.from != cur.to) bidiOther = i;
return found;
}
}
}
- bidiOther = null;
return found;
}
function moveInLine(line, pos, dir, byUnit) {
if (!byUnit) return pos + dir;
do pos += dir;
- while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
return pos;
}
@@ -5737,7 +5876,7 @@ window.CodeMirror = (function() {
function moveLogically(line, start, dir, byUnit) {
var target = start + dir;
- if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
return target < 0 || target > line.text.length ? null : target;
}
@@ -5829,7 +5968,7 @@ window.CodeMirror = (function() {
if (type == ",") types[i] = "N";
else if (type == "%") {
for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
- var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N";
+ var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
}
@@ -5854,7 +5993,7 @@ window.CodeMirror = (function() {
if (isNeutral.test(types[i])) {
for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
var before = (i ? types[i-1] : outerType) == "L";
- var after = (end < len - 1 ? types[end] : outerType) == "L";
+ var after = (end < len ? types[end] : outerType) == "L";
var replace = before || after ? "L" : "R";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
@@ -5904,7 +6043,7 @@ window.CodeMirror = (function() {
// THE END
- CodeMirror.version = "3.19.0";
+ CodeMirror.version = "3.21.0";
return CodeMirror;
})();
diff --git a/applications/admin/static/codemirror/mode/css/css.js b/applications/admin/static/codemirror/mode/css/css.js
index f47aba75..8f6fe7df 100644
--- a/applications/admin/static/codemirror/mode/css/css.js
+++ b/applications/admin/static/codemirror/mode/css/css.js
@@ -3,87 +3,80 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
- var indentUnit = config.indentUnit || config.tabSize || 2,
- hooks = parserConfig.hooks || {},
- atMediaTypes = parserConfig.atMediaTypes || {},
- atMediaFeatures = parserConfig.atMediaFeatures || {},
+ var indentUnit = config.indentUnit,
+ tokenHooks = parserConfig.tokenHooks,
+ mediaTypes = parserConfig.mediaTypes || {},
+ mediaFeatures = parserConfig.mediaFeatures || {},
propertyKeywords = parserConfig.propertyKeywords || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
- allowNested = !!parserConfig.allowNested,
- type = null;
+ fontProperties = parserConfig.fontProperties || {},
+ allowNested = parserConfig.allowNested;
+ var type, override;
function ret(style, tp) { type = tp; return style; }
+ // Tokenizers
+
function tokenBase(stream, state) {
var ch = stream.next();
- if (hooks[ch]) {
- // result[0] is style and result[1] is type
- var result = hooks[ch](stream, state);
+ if (tokenHooks[ch]) {
+ var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
- if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
- else if (ch == "=") ret(null, "compare");
- else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
- else if (ch == "\"" || ch == "'") {
+ if (ch == "@") {
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("def", stream.current());
+ } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
+ return ret(null, "compare");
+ } else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
- }
- else if (ch == "#") {
+ } else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
- }
- else if (ch == "!") {
+ } else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
- }
- else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
+ } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
- }
- else if (ch === "-") {
- if (/\d/.test(stream.peek())) {
+ } else if (ch === "-") {
+ if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^[^-]+-/)) {
return ret("meta", "meta");
}
- }
- else if (/[,+>*\/]/.test(ch)) {
+ } else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
- }
- else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
+ } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
- }
- else if (ch == ":") {
- return ret("operator", ch);
- }
- else if (/[;{}\[\]\(\)]/.test(ch)) {
+ } else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
- }
- else if (ch == "u" && stream.match("rl(")) {
+ } else if (ch == "u" && stream.match("rl(")) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
- return ret("property", "variable");
- }
- else {
+ return ret("property", "word");
+ } else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
- return ret("property", "variable");
+ return ret("property", "word");
+ } else {
+ return ret(null, null);
}
}
- function tokenString(quote, nonInclusive) {
+ function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
- if (ch == quote && !escaped)
+ if (ch == quote && !escaped) {
+ if (quote == ")") stream.backUp(1);
break;
+ }
escaped = !escaped && ch == "\\";
}
- if (!escaped) {
- if (nonInclusive) stream.backUp(1);
- state.tokenize = tokenBase;
- }
+ if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
@@ -91,218 +84,238 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\']/, false))
- state.tokenize = tokenString(")", true);
+ state.tokenize = tokenString(")");
else
- state.tokenize = tokenBase;
+ state.tokenize = null;
return ret(null, "(");
}
+ // Context management
+
+ function Context(type, indent, prev) {
+ this.type = type;
+ this.indent = indent;
+ this.prev = prev;
+ }
+
+ function pushContext(state, stream, type) {
+ state.context = new Context(type, stream.indentation() + indentUnit, state.context);
+ return type;
+ }
+
+ function popContext(state) {
+ state.context = state.context.prev;
+ return state.context.type;
+ }
+
+ function pass(type, stream, state) {
+ return states[state.context.type](type, stream, state);
+ }
+ function popAndPass(type, stream, state, n) {
+ for (var i = n || 1; i > 0; i--)
+ state.context = state.context.prev;
+ return pass(type, stream, state);
+ }
+
+ // Parser
+
+ function wordAsValue(stream) {
+ var word = stream.current().toLowerCase();
+ if (valueKeywords.hasOwnProperty(word))
+ override = "atom";
+ else if (colorKeywords.hasOwnProperty(word))
+ override = "keyword";
+ else
+ override = "variable";
+ }
+
+ var states = {};
+
+ states.top = function(type, stream, state) {
+ if (type == "{") {
+ return pushContext(state, stream, "block");
+ } else if (type == "}" && state.context.prev) {
+ return popContext(state);
+ } else if (type == "@media") {
+ return pushContext(state, stream, "media");
+ } else if (type == "@font-face") {
+ return "font_face_before";
+ } else if (type && type.charAt(0) == "@") {
+ return pushContext(state, stream, "at");
+ } else if (type == "hash") {
+ override = "builtin";
+ } else if (type == "word") {
+ override = "tag";
+ } else if (type == "variable-definition") {
+ return "maybeprop";
+ } else if (type == "interpolation") {
+ return pushContext(state, stream, "interpolation");
+ } else if (type == ":") {
+ return "pseudo";
+ } else if (allowNested && type == "(") {
+ return pushContext(state, stream, "params");
+ }
+ return state.context.type;
+ };
+
+ states.block = function(type, stream, state) {
+ if (type == "word") {
+ if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) {
+ override = "property";
+ return "maybeprop";
+ } else if (allowNested) {
+ override = stream.match(/^\s*:/, false) ? "property" : "tag";
+ return "block";
+ } else {
+ override += " error";
+ return "maybeprop";
+ }
+ } else if (type == "meta") {
+ return "block";
+ } else if (!allowNested && (type == "hash" || type == "qualifier")) {
+ override = "error";
+ return "block";
+ } else {
+ return states.top(type, stream, state);
+ }
+ };
+
+ states.maybeprop = function(type, stream, state) {
+ if (type == ":") return pushContext(state, stream, "prop");
+ return pass(type, stream, state);
+ };
+
+ states.prop = function(type, stream, state) {
+ if (type == ";") return popContext(state);
+ if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
+ if (type == "}" || type == "{") return popAndPass(type, stream, state);
+ if (type == "(") return pushContext(state, stream, "parens");
+
+ if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
+ override += " error";
+ } else if (type == "word") {
+ wordAsValue(stream);
+ } else if (type == "interpolation") {
+ return pushContext(state, stream, "interpolation");
+ }
+ return "prop";
+ };
+
+ states.propBlock = function(type, _stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "word") { override = "property"; return "maybeprop"; }
+ return state.context.type;
+ };
+
+ states.parens = function(type, stream, state) {
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == ")") return popContext(state);
+ return "parens";
+ };
+
+ states.pseudo = function(type, stream, state) {
+ if (type == "word") {
+ override = "variable-3";
+ return state.context.type;
+ }
+ return pass(type, stream, state);
+ };
+
+ states.media = function(type, stream, state) {
+ if (type == "(") return pushContext(state, stream, "media_parens");
+ if (type == "}") return popAndPass(type, stream, state);
+ if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
+
+ if (type == "word") {
+ var word = stream.current().toLowerCase();
+ if (word == "only" || word == "not" || word == "and")
+ override = "keyword";
+ else if (mediaTypes.hasOwnProperty(word))
+ override = "attribute";
+ else if (mediaFeatures.hasOwnProperty(word))
+ override = "property";
+ else
+ override = "error";
+ }
+ return state.context.type;
+ };
+
+ states.media_parens = function(type, stream, state) {
+ if (type == ")") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
+ return states.media(type, stream, state);
+ };
+
+ states.font_face_before = function(type, stream, state) {
+ if (type == "{")
+ return pushContext(state, stream, "font_face");
+ return pass(type, stream, state);
+ };
+
+ states.font_face = function(type, stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "word") {
+ if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
+ override = "error";
+ else
+ override = "property";
+ return "maybeprop";
+ }
+ return "font_face";
+ };
+
+ states.at = function(type, stream, state) {
+ if (type == ";") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == "word") override = "tag";
+ else if (type == "hash") override = "builtin";
+ return "at";
+ };
+
+ states.interpolation = function(type, stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "{" || type == ";") return popAndPass(type, stream, state);
+ if (type != "variable") override = "error";
+ return "interpolation";
+ };
+
+ states.params = function(type, stream, state) {
+ if (type == ")") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == "word") wordAsValue(stream);
+ return "params";
+ };
+
return {
startState: function(base) {
- return {tokenize: tokenBase,
- baseIndent: base || 0,
- stack: [],
- lastToken: null};
+ return {tokenize: null,
+ state: "top",
+ context: new Context("top", base || 0, null)};
},
token: function(stream, state) {
-
- // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
- //
- // rule** or **ruleset:
- // A selector + braces combo, or an at-rule.
- //
- // declaration block:
- // A sequence of declarations.
- //
- // declaration:
- // A property + colon + value combo.
- //
- // property value:
- // The entire value of a property.
- //
- // component value:
- // A single piece of a property value. Like the 5px in
- // text-shadow: 0 0 5px blue;. Can also refer to things that are
- // multiple terms, like the 1-4 terms that make up the background-size
- // portion of the background shorthand.
- //
- // term:
- // The basic unit of author-facing CSS, like a single number (5),
- // dimension (5px), string ("foo"), or function. Officially defined
- // by the CSS 2.1 grammar (look for the 'term' production)
- //
- //
- // simple selector:
- // A single atomic selector, like a type selector, an attr selector, a
- // class selector, etc.
- //
- // compound selector:
- // One or more simple selectors without a combinator. div.example is
- // compound, div > .example is not.
- //
- // complex selector:
- // One or more compound selectors chained with combinators.
- //
- // combinator:
- // The parts of selectors that express relationships. There are four
- // currently - the space (descendant combinator), the greater-than
- // bracket (child combinator), the plus sign (next sibling combinator),
- // and the tilda (following sibling combinator).
- //
- // sequence of selectors:
- // One or more of the named type of selector chained with commas.
-
- state.tokenize = state.tokenize || tokenBase;
- if (state.tokenize == tokenBase && stream.eatSpace()) return null;
- var style = state.tokenize(stream, state);
- if (style && typeof style != "string") style = ret(style[0], style[1]);
-
- // Changing style returned based on context
- var context = state.stack[state.stack.length-1];
- if (style == "variable") {
- if (type == "variable-definition") state.stack.push("propertyValue");
- return state.lastToken = "variable-2";
- } else if (style == "property") {
- var word = stream.current().toLowerCase();
- if (context == "propertyValue") {
- if (valueKeywords.hasOwnProperty(word)) {
- style = "string-2";
- } else if (colorKeywords.hasOwnProperty(word)) {
- style = "keyword";
- } else {
- style = "variable-2";
- }
- } else if (context == "rule") {
- if (!propertyKeywords.hasOwnProperty(word)) {
- style += " error";
- }
- } else if (context == "block") {
- // if a value is present in both property, value, or color, the order
- // of preference is property -> color -> value
- if (propertyKeywords.hasOwnProperty(word)) {
- style = "property";
- } else if (colorKeywords.hasOwnProperty(word)) {
- style = "keyword";
- } else if (valueKeywords.hasOwnProperty(word)) {
- style = "string-2";
- } else {
- style = "tag";
- }
- } else if (!context || context == "@media{") {
- style = "tag";
- } else if (context == "@media") {
- if (atMediaTypes[stream.current()]) {
- style = "attribute"; // Known attribute
- } else if (/^(only|not)$/.test(word)) {
- style = "keyword";
- } else if (word == "and") {
- style = "error"; // "and" is only allowed in @mediaType
- } else if (atMediaFeatures.hasOwnProperty(word)) {
- style = "error"; // Known property, should be in @mediaType(
- } else {
- // Unknown, expecting keyword or attribute, assuming attribute
- style = "attribute error";
- }
- } else if (context == "@mediaType") {
- if (atMediaTypes.hasOwnProperty(word)) {
- style = "attribute";
- } else if (word == "and") {
- style = "operator";
- } else if (/^(only|not)$/.test(word)) {
- style = "error"; // Only allowed in @media
- } else {
- // Unknown attribute or property, but expecting property (preceded
- // by "and"). Should be in parentheses
- style = "error";
- }
- } else if (context == "@mediaType(") {
- if (propertyKeywords.hasOwnProperty(word)) {
- // do nothing, remains "property"
- } else if (atMediaTypes.hasOwnProperty(word)) {
- style = "error"; // Known property, should be in parentheses
- } else if (word == "and") {
- style = "operator";
- } else if (/^(only|not)$/.test(word)) {
- style = "error"; // Only allowed in @media
- } else {
- style += " error";
- }
- } else if (context == "@import") {
- style = "tag";
- } else {
- style = "error";
- }
- } else if (style == "atom") {
- if(!context || context == "@media{" || context == "block") {
- style = "builtin";
- } else if (context == "propertyValue") {
- if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
- style += " error";
- }
- } else {
- style = "error";
- }
- } else if (context == "@media" && type == "{") {
- style = "error";
+ if (!state.tokenize && stream.eatSpace()) return null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style && typeof style == "object") {
+ type = style[1];
+ style = style[0];
}
-
- // Push/pop context stack
- if (type == "{") {
- if (context == "@media" || context == "@mediaType") {
- state.stack[state.stack.length-1] = "@media{";
- }
- else {
- var newContext = allowNested ? "block" : "rule";
- state.stack.push(newContext);
- }
- }
- else if (type == "}") {
- if (context == "interpolation") style = "operator";
- // Pop off end of array until { is reached
- while(state.stack.length){
- var removed = state.stack.pop();
- if(removed.indexOf("{") > -1){
- break;
- }
- }
- }
- else if (type == "interpolation") state.stack.push("interpolation");
- else if (type == "@media") state.stack.push("@media");
- else if (type == "@import") state.stack.push("@import");
- else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
- state.stack[state.stack.length-1] = "@mediaType";
- else if (context == "@mediaType" && stream.current() == ",")
- state.stack[state.stack.length-1] = "@media";
- else if (type == "(") {
- if (context == "@media" || context == "@mediaType") {
- // Make sure @mediaType is used to avoid error on {
- state.stack[state.stack.length-1] = "@mediaType";
- state.stack.push("@mediaType(");
- }
- else state.stack.push("(");
- }
- else if (type == ")") {
- // Pop off end of array until ( is reached
- while(state.stack.length){
- var removed = state.stack.pop();
- if(removed.indexOf("(") > -1){
- break;
- }
- }
- }
- else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue");
- else if (context == "propertyValue" && type == ";") state.stack.pop();
- else if (context == "@import" && type == ";") state.stack.pop();
-
- return state.lastToken = style;
+ override = style;
+ state.state = states[state.state](type, stream, state);
+ return override;
},
indent: function(state, textAfter) {
- var n = state.stack.length;
- if (/^\}/.test(textAfter))
- n -= state.stack[n-1] == "propertyValue" ? 2 : 1;
- return state.baseIndent + n * indentUnit;
+ var cx = state.context, ch = textAfter && textAfter.charAt(0);
+ var indent = cx.indent;
+ if (cx.prev &&
+ (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
+ ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
+ ch == "{" && (cx.type == "at" || cx.type == "media"))) {
+ indent = cx.indent - indentUnit;
+ cx = cx.prev;
+ }
+ return indent;
},
electricChars: "}",
@@ -321,12 +334,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return keys;
}
- var atMediaTypes = keySet([
+ var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
- ]);
+ ], mediaTypes = keySet(mediaTypes_);
- var atMediaFeatures = keySet([
+ var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
@@ -335,9 +348,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
- ]);
+ ], mediaFeatures = keySet(mediaFeatures_);
- var propertyKeywords = keySet([
+ var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
@@ -425,9 +438,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
- ]);
+ ], propertyKeywords = keySet(propertyKeywords_);
- var colorKeywords = keySet([
+ var colorKeywords_ = [
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
@@ -454,9 +467,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
- ]);
+ ], colorKeywords = keySet(colorKeywords_);
- var valueKeywords = keySet([
+ var valueKeywords_ = [
"above", "absolute", "activeborder", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
@@ -539,7 +552,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
"xx-large", "xx-small"
- ]);
+ ], valueKeywords = keySet(valueKeywords_);
+
+ var fontProperties_ = [
+ "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
+ "font-stretch", "font-weight", "font-style"
+ ], fontProperties = keySet(fontProperties_);
+
+ var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
+ CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
@@ -553,67 +574,47 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return ["comment", "comment"];
}
+ function tokenSGMLComment(stream, state) {
+ if (stream.skipTo("-->")) {
+ stream.match("-->");
+ state.tokenize = null;
+ } else {
+ stream.skipToEnd();
+ }
+ return ["comment", "comment"];
+ }
+
CodeMirror.defineMIME("text/css", {
- atMediaTypes: atMediaTypes,
- atMediaFeatures: atMediaFeatures,
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
- hooks: {
+ fontProperties: fontProperties,
+ tokenHooks: {
"<": function(stream, state) {
- function tokenSGMLComment(stream, state) {
- var dashes = 0, ch;
- while ((ch = stream.next()) != null) {
- if (dashes >= 2 && ch == ">") {
- state.tokenize = null;
- break;
- }
- dashes = (ch == "-") ? dashes + 1 : 0;
- }
- return ["comment", "comment"];
- }
- if (stream.eat("!")) {
- state.tokenize = tokenSGMLComment;
- return tokenSGMLComment(stream, state);
- }
+ if (!stream.match("!--")) return false;
+ state.tokenize = tokenSGMLComment;
+ return tokenSGMLComment(stream, state);
},
"/": function(stream, state) {
- if (stream.eat("*")) {
- state.tokenize = tokenCComment;
- return tokenCComment(stream, state);
- }
- return false;
+ if (!stream.eat("*")) return false;
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
- atMediaTypes: atMediaTypes,
- atMediaFeatures: atMediaFeatures,
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
+ fontProperties: fontProperties,
allowNested: true,
- hooks: {
- ":": function(stream) {
- if (stream.match(/\s*{/)) {
- return [null, "{"];
- }
- return false;
- },
- "$": function(stream) {
- stream.match(/^[\w-]+/);
- if (stream.peek() == ":") {
- return ["variable", "variable-definition"];
- }
- return ["variable", "variable"];
- },
- ",": function(_stream, state) {
- if (state.stack[state.stack.length - 1] == "propertyValue") {
- return ["operator", ";"];
- }
- },
+ tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
@@ -625,15 +626,58 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return ["operator", "operator"];
}
},
+ ":": function(stream) {
+ if (stream.match(/\s*{/))
+ return [null, "{"];
+ return false;
+ },
+ "$": function(stream) {
+ stream.match(/^[\w-]+/);
+ if (stream.match(/^\s*:/, false))
+ return ["variable-2", "variable-definition"];
+ return ["variable-2", "variable"];
+ },
"#": function(stream) {
- if (stream.eat("{")) {
- return ["operator", "interpolation"];
- } else {
- stream.eatWhile(/[\w\\\-]/);
- return ["atom", "hash"];
- }
+ if (!stream.eat("{")) return false;
+ return [null, "interpolation"];
}
},
- name: "css"
+ name: "css",
+ helperType: "scss"
+ });
+
+ CodeMirror.defineMIME("text/x-less", {
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
+ propertyKeywords: propertyKeywords,
+ colorKeywords: colorKeywords,
+ valueKeywords: valueKeywords,
+ fontProperties: fontProperties,
+ allowNested: true,
+ tokenHooks: {
+ "/": function(stream, state) {
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return ["comment", "comment"];
+ } else if (stream.eat("*")) {
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
+ } else {
+ return ["operator", "operator"];
+ }
+ },
+ "@": function(stream) {
+ if (stream.match(/^(charset|document|font-face|import|keyframes|media|namespace|page|supports)\b/, false)) return false;
+ stream.eatWhile(/[\w\\\-]/);
+ if (stream.match(/^\s*:/, false))
+ return ["variable-2", "variable-definition"];
+ return ["variable-2", "variable"];
+ },
+ "&": function() {
+ return ["atom", "atom"];
+ }
+ },
+ name: "css",
+ helperType: "less"
});
})();
diff --git a/applications/admin/static/codemirror/mode/css/scss.html b/applications/admin/static/codemirror/mode/css/scss.html
index 72781c0d..0677d08f 100644
--- a/applications/admin/static/codemirror/mode/css/scss.html
+++ b/applications/admin/static/codemirror/mode/css/scss.html
@@ -150,7 +150,7 @@ code {
});
- MIME types defined: text/scss.
+ The SCSS mode is a sub-mode of the CSS mode (defined in css.js.
Parsing/Highlighting Tests: normal, verbose.
diff --git a/applications/admin/static/codemirror/mode/css/scss_test.js b/applications/admin/static/codemirror/mode/css/scss_test.js
index bc2a0785..c51cb42b 100644
--- a/applications/admin/static/codemirror/mode/css/scss_test.js
+++ b/applications/admin/static/codemirror/mode/css/scss_test.js
@@ -1,34 +1,33 @@
(function() {
- var mode = CodeMirror.getMode({tabSize: 1}, "text/x-scss");
+ var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
- function IT(name) { test.indentation(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
MT('url_with_quotation',
- "[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }");
+ "[tag foo] { [property background]:[atom url]([string test.jpg]) }");
MT('url_with_double_quotes',
- "[tag foo] { [property background][operator :][string-2 url]([string \"test.jpg\"]) }");
+ "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }");
MT('url_with_single_quotes',
- "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) }");
+ "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }");
MT('string',
"[def @import] [string \"compass/css3\"]");
MT('important_keyword',
- "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) [keyword !important] }");
+ "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }");
MT('variable',
- "[variable-2 $blue][operator :][atom #333]");
+ "[variable-2 $blue]:[atom #333]");
MT('variable_as_attribute',
- "[tag foo] { [property color][operator :][variable-2 $blue] }");
+ "[tag foo] { [property color]:[variable-2 $blue] }");
MT('numbers',
- "[tag foo] { [property padding][operator :][number 10px] [number 10] [number 10em] [number 8in] }");
+ "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }");
MT('number_percentage',
- "[tag foo] { [property width][operator :][number 80%] }");
+ "[tag foo] { [property width]:[number 80%] }");
MT('selector',
"[builtin #hello][qualifier .world]{}");
@@ -40,45 +39,69 @@
"[comment /*foobar*/]");
MT('attribute_with_hyphen',
- "[tag foo] { [property font-size][operator :][number 10px] }");
+ "[tag foo] { [property font-size]:[number 10px] }");
MT('string_after_attribute',
- "[tag foo] { [property content][operator :][string \"::\"] }");
+ "[tag foo] { [property content]:[string \"::\"] }");
MT('directives',
"[def @include] [qualifier .mixin]");
MT('basic_structure',
- "[tag p] { [property background][operator :][keyword red]; }");
+ "[tag p] { [property background]:[keyword red]; }");
MT('nested_structure',
- "[tag p] { [tag a] { [property color][operator :][keyword red]; } }");
+ "[tag p] { [tag a] { [property color]:[keyword red]; } }");
MT('mixin',
"[def @mixin] [tag table-base] {}");
MT('number_without_semicolon',
- "[tag p] {[property width][operator :][number 12]}",
- "[tag a] {[property color][operator :][keyword red];}");
+ "[tag p] {[property width]:[number 12]}",
+ "[tag a] {[property color]:[keyword red];}");
MT('atom_in_nested_block',
- "[tag p] { [tag a] { [property color][operator :][atom #000]; } }");
+ "[tag p] { [tag a] { [property color]:[atom #000]; } }");
MT('interpolation_in_property',
- "[tag foo] { [operator #{][variable-2 $hello][operator }:][number 2]; }");
+ "[tag foo] { #{[variable-2 $hello]}:[number 2]; }");
MT('interpolation_in_selector',
- "[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }");
+ "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }");
MT('interpolation_error',
- "[tag foo][operator #{][error foo][operator }] { [property color][operator :][atom #000]; }");
+ "[tag foo]#{[error foo]} { [property color]:[atom #000]; }");
MT("divide_operator",
- "[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }");
+ "[tag foo] { [property width]:[number 4] [operator /] [number 2] }");
MT('nested_structure_with_id_selector',
- "[tag p] { [builtin #hello] { [property color][operator :][keyword red]; } }");
+ "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }");
- IT('mixin',
- "@mixin container[1 (][2 $a: 10][1 , ][2 $b: 10][1 , ][2 $c: 10]) [1 {]}");
+ MT('indent_mixin',
+ "[def @mixin] [tag container] (",
+ " [variable-2 $a]: [number 10],",
+ " [variable-2 $b]: [number 10])",
+ "{}");
+
+ MT('indent_nested',
+ "[tag foo] {",
+ " [tag bar] {",
+ " }",
+ "}");
+
+ MT('indent_parentheses',
+ "[tag foo] {",
+ " [property color]: [variable darken]([variable-2 $blue],",
+ " [number 9%]);",
+ "}");
+
+ MT('indent_vardef',
+ "[variable-2 $name]:",
+ " [string 'val'];",
+ "[tag tag] {",
+ " [tag inner] {",
+ " [property margin]: [number 3px];",
+ " }",
+ "}");
})();
diff --git a/applications/admin/static/codemirror/mode/css/test.js b/applications/admin/static/codemirror/mode/css/test.js
index 43647833..b3f47767 100644
--- a/applications/admin/static/codemirror/mode/css/test.js
+++ b/applications/admin/static/codemirror/mode/css/test.js
@@ -1,68 +1,19 @@
(function() {
- var mode = CodeMirror.getMode({tabSize: 1}, "css");
+ var mode = CodeMirror.getMode({indentUnit: 2}, "css");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
- function IT(name) { test.indentation(name, mode, Array.prototype.slice.call(arguments, 1)); }
-
- // Requires at least one media query
- MT("atMediaEmpty",
- "[def @media] [error {] }");
-
- MT("atMediaMultiple",
- "[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }");
-
- MT("atMediaCheckStack",
- "[def @media] [attribute screen] { } [tag foo] { }");
-
- MT("atMediaCheckStack",
- "[def @media] [attribute screen] ([property color]) { } [tag foo] { }");
-
- MT("atMediaPropertyOnly",
- "[def @media] ([property color]) { } [tag foo] { }");
-
- MT("atMediaCheckStackInvalidAttribute",
- "[def @media] [attribute&error foobarhello] { [tag foo] { } }");
-
- MT("atMediaCheckStackInvalidAttribute",
- "[def @media] [attribute&error foobarhello] { } [tag foo] { }");
-
- // Error, because "and" is only allowed immediately preceding a media expression
- MT("atMediaInvalidAttribute",
- "[def @media] [attribute&error foobarhello] { }");
-
- // Error, because "and" is only allowed immediately preceding a media expression
- MT("atMediaInvalidAnd",
- "[def @media] [error and] [attribute screen] { }");
-
- // Error, because "not" is only allowed as the first item in each media query
- MT("atMediaInvalidNot",
- "[def @media] [attribute screen] [error not] ([error not]) { }");
-
- // Error, because "only" is only allowed as the first item in each media query
- MT("atMediaInvalidOnly",
- "[def @media] [attribute screen] [error only] ([error only]) { }");
// Error, because "foobarhello" is neither a known type or property, but
// property was expected (after "and"), and it should be in parenthese.
MT("atMediaUnknownType",
- "[def @media] [attribute screen] [operator and] [error foobarhello] { }");
-
- // Error, because "color" is not a known type, but is a known property, and
- // should be in parentheses.
- MT("atMediaInvalidType",
- "[def @media] [attribute screen] [operator and] [error color] { }");
-
- // Error, because "print" is not a known property, but is a known type,
- // and should not be in parenthese.
- MT("atMediaInvalidProperty",
- "[def @media] [attribute screen] [operator and] ([error print]) { }");
+ "[def @media] [attribute screen] [keyword and] [error foobarhello] { }");
// Soft error, because "foobarhello" is not a known property or type.
MT("atMediaUnknownProperty",
- "[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }");
+ "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }");
// Make sure nesting works with media queries
MT("atMediaMaxWidthNested",
- "[def @media] [attribute screen] [operator and] ([property max-width][operator :] [number 25px]) { [tag foo] { } }");
+ "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }");
MT("tagSelector",
"[tag foo] { }");
@@ -74,57 +25,95 @@
"[builtin #foo] { [error #foo] }");
MT("tagSelectorUnclosed",
- "[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }");
+ "[tag foo] { [property margin]: [number 0] } [tag bar] { }");
MT("tagStringNoQuotes",
- "[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }");
+ "[tag foo] { [property font-family]: [variable hello] [variable world]; }");
MT("tagStringDouble",
- "[tag foo] { [property font-family][operator :] [string \"hello world\"]; }");
+ "[tag foo] { [property font-family]: [string \"hello world\"]; }");
MT("tagStringSingle",
- "[tag foo] { [property font-family][operator :] [string 'hello world']; }");
+ "[tag foo] { [property font-family]: [string 'hello world']; }");
MT("tagColorKeyword",
- "[tag foo] {" +
- "[property color][operator :] [keyword black];" +
- "[property color][operator :] [keyword navy];" +
- "[property color][operator :] [keyword yellow];" +
- "}");
+ "[tag foo] {",
+ " [property color]: [keyword black];",
+ " [property color]: [keyword navy];",
+ " [property color]: [keyword yellow];",
+ "}");
MT("tagColorHex3",
- "[tag foo] { [property background][operator :] [atom #fff]; }");
+ "[tag foo] { [property background]: [atom #fff]; }");
MT("tagColorHex6",
- "[tag foo] { [property background][operator :] [atom #ffffff]; }");
+ "[tag foo] { [property background]: [atom #ffffff]; }");
MT("tagColorHex4",
- "[tag foo] { [property background][operator :] [atom&error #ffff]; }");
+ "[tag foo] { [property background]: [atom&error #ffff]; }");
MT("tagColorHexInvalid",
- "[tag foo] { [property background][operator :] [atom&error #ffg]; }");
+ "[tag foo] { [property background]: [atom&error #ffg]; }");
MT("tagNegativeNumber",
- "[tag foo] { [property margin][operator :] [number -5px]; }");
+ "[tag foo] { [property margin]: [number -5px]; }");
MT("tagPositiveNumber",
- "[tag foo] { [property padding][operator :] [number 5px]; }");
+ "[tag foo] { [property padding]: [number 5px]; }");
MT("tagVendor",
- "[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }");
+ "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }");
MT("tagBogusProperty",
- "[tag foo] { [property&error barhelloworld][operator :] [number 0]; }");
+ "[tag foo] { [property&error barhelloworld]: [number 0]; }");
MT("tagTwoProperties",
- "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }");
+ "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
MT("tagTwoPropertiesURL",
- "[tag foo] { [property background][operator :] [string-2 url]([string //example.com/foo.png]); [property padding][operator :] [number 0]; }");
+ "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
MT("commentSGML",
"[comment ]");
- IT("tagSelector",
- "strong, em [1 { background][2 : rgba][3 (255, 255, 0, .2][2 )][1 ;]}");
+ MT("commentSGML2",
+ "[comment ] [tag div] {}");
+
+ MT("indent_tagSelector",
+ "[tag strong], [tag em] {",
+ " [property background]: [atom rgba](",
+ " [number 255], [number 255], [number 0], [number .2]",
+ " );",
+ "}");
+
+ MT("indent_atMedia",
+ "[def @media] {",
+ " [tag foo] {",
+ " [property color]:",
+ " [keyword yellow];",
+ " }",
+ "}");
+
+ MT("indent_comma",
+ "[tag foo] {",
+ " [property font-family]: [variable verdana],",
+ " [atom sans-serif];",
+ "}");
+
+ MT("indent_parentheses",
+ "[tag foo]:[variable-3 before] {",
+ " [property background]: [atom url](",
+ "[string blahblah]",
+ "[string etc]",
+ "[string ]) [keyword !important];",
+ "}");
+
+ MT("font_face",
+ "[def @font-face] {",
+ " [property font-family]: [string 'myfont'];",
+ " [error nonsense]: [string 'abc'];",
+ " [property src]: [atom url]([string http://blah]),",
+ " [atom url]([string http://foo]);",
+ "}");
})();
diff --git a/applications/admin/static/codemirror/mode/htmlembedded/htmlembedded.js b/applications/admin/static/codemirror/mode/htmlembedded/htmlembedded.js
index ff6dfd2f..c316cd34 100644
--- a/applications/admin/static/codemirror/mode/htmlembedded/htmlembedded.js
+++ b/applications/admin/static/codemirror/mode/htmlembedded/htmlembedded.js
@@ -58,8 +58,6 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
};
},
- electricChars: "/{}:",
-
innerMode: function(state) {
if (state.token == scriptingDispatch) return {state: state.scriptState, mode: scriptingMode};
else return {state: state.htmlState, mode: htmlMixedMode};
diff --git a/applications/admin/static/codemirror/mode/htmlmixed/htmlmixed.js b/applications/admin/static/codemirror/mode/htmlmixed/htmlmixed.js
index ec0c21d2..e9eab3b9 100644
--- a/applications/admin/static/codemirror/mode/htmlmixed/htmlmixed.js
+++ b/applications/admin/static/codemirror/mode/htmlmixed/htmlmixed.js
@@ -44,7 +44,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
if (close > -1) stream.backUp(cur.length - close);
else if (m = cur.match(/<\/?$/)) {
stream.backUp(cur.length);
- if (!stream.match(pat, false)) stream.match(cur[0]);
+ if (!stream.match(pat, false)) stream.match(cur);
}
return style;
}
@@ -93,8 +93,6 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
return CodeMirror.Pass;
},
- electricChars: "/{}:",
-
innerMode: function(state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
diff --git a/applications/admin/static/codemirror/mode/javascript/javascript.js b/applications/admin/static/codemirror/mode/javascript/javascript.js
index e8ace32d..fbf574b4 100644
--- a/applications/admin/static/codemirror/mode/javascript/javascript.js
+++ b/applications/admin/static/codemirror/mode/javascript/javascript.js
@@ -15,13 +15,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
- "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
- "this": kw("this")
+ "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
+ "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
@@ -30,7 +31,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var tsKeywords = {
// object-like things
"interface": kw("interface"),
- "class": kw("class"),
"extends": kw("extends"),
"constructor": kw("constructor"),
@@ -40,8 +40,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"protected": kw("protected"),
"static": kw("static"),
- "super": kw("super"),
-
// types
"string": type, "number": type, "bool": type, "any": type
};
@@ -56,19 +54,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
- function chain(stream, state, f) {
- state.tokenize = f;
- return f(stream, state);
- }
-
- function nextUntilUnescaped(stream, end) {
- var escaped = false, next;
+ function readRegexp(stream) {
+ var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
- if (next == end && !escaped)
- return false;
+ if (!escaped) {
+ if (next == "/" && !inSet) return;
+ if (next == "[") inSet = true;
+ else if (inSet && next == "]") inSet = false;
+ }
escaped = !escaped && next == "\\";
}
- return escaped;
}
// Used as scratch variables to communicate multiple values without
@@ -78,50 +73,51 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
type = tp; content = cont;
return style;
}
- function jsTokenBase(stream, state) {
+ function tokenBase(stream, state) {
var ch = stream.next();
- if (ch == '"' || ch == "'")
- return chain(stream, state, jsTokenString(ch));
- else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/))
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
return ret("number", "number");
- else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+ } else if (ch == "." && stream.match("..")) {
+ return ret("spread", "meta");
+ } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
- else if (ch == "0" && stream.eat(/x/i)) {
+ } else if (ch == "=" && stream.eat(">")) {
+ return ret("=>", "operator");
+ } else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
- }
- else if (/\d/.test(ch)) {
+ } else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
- }
- else if (ch == "/") {
+ } else if (ch == "/") {
if (stream.eat("*")) {
- return chain(stream, state, jsTokenComment);
- }
- else if (stream.eat("/")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ } else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
- }
- else if (state.lastType == "operator" || state.lastType == "keyword c" ||
- /^[\[{}\(,;:]$/.test(state.lastType)) {
- nextUntilUnescaped(stream, "/");
+ } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
+ state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
+ readRegexp(stream);
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
return ret("regexp", "string-2");
- }
- else {
+ } else {
stream.eatWhile(isOperatorChar);
- return ret("operator", null, stream.current());
+ return ret("operator", "operator", stream.current());
}
- }
- else if (ch == "#") {
+ } else if (ch == "`") {
+ state.tokenize = tokenQuasi;
+ return tokenQuasi(stream, state);
+ } else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
- }
- else if (isOperatorChar.test(ch)) {
+ } else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
- return ret("operator", null, stream.current());
- }
- else {
+ return ret("operator", "operator", stream.current());
+ } else {
stream.eatWhile(/[\w\$_]/);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
@@ -129,19 +125,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
}
- function jsTokenString(quote) {
+ function tokenString(quote) {
return function(stream, state) {
- if (!nextUntilUnescaped(stream, quote))
- state.tokenize = jsTokenBase;
+ var escaped = false, next;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) break;
+ escaped = !escaped && next == "\\";
+ }
+ if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
- function jsTokenComment(stream, state) {
+ function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
- state.tokenize = jsTokenBase;
+ state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
@@ -149,6 +149,50 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return ret("comment", "comment");
}
+ function tokenQuasi(stream, state) {
+ var escaped = false, next;
+ while ((next = stream.next()) != null) {
+ if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ return ret("quasi", "string-2", stream.current());
+ }
+
+ var brackets = "([{}])";
+ // This is a crude lookahead trick to try and notice that we're
+ // parsing the argument patterns for a fat-arrow function before we
+ // actually hit the arrow token. It only works if the arrow is on
+ // the same line as the arguments and there's no strange noise
+ // (comments) in between. Fallback is to only notice when we hit the
+ // arrow, and not declare the arguments as locals for the arrow
+ // body.
+ function findFatArrow(stream, state) {
+ if (state.fatArrowAt) state.fatArrowAt = null;
+ var arrow = stream.string.indexOf("=>", stream.start);
+ if (arrow < 0) return;
+
+ var depth = 0, sawSomething = false;
+ for (var pos = arrow - 1; pos >= 0; --pos) {
+ var ch = stream.string.charAt(pos);
+ var bracket = brackets.indexOf(ch);
+ if (bracket >= 0 && bracket < 3) {
+ if (!depth) { ++pos; break; }
+ if (--depth == 0) break;
+ } else if (bracket >= 3 && bracket < 6) {
+ ++depth;
+ } else if (/[$\w]/.test(ch)) {
+ sawSomething = true;
+ } else if (sawSomething && !depth) {
+ ++pos;
+ break;
+ }
+ }
+ if (sawSomething && !depth) state.fatArrowAt = pos;
+ }
+
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
@@ -165,6 +209,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
+ for (var cx = state.context; cx; cx = cx.prev) {
+ for (var v = cx.vars; v; v = v.next)
+ if (v.name == varname) return true;
+ }
}
function parseJS(state, style, type, content, stream) {
@@ -211,7 +259,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
- state.globalVars = {name: varname, next: state.globalVars};
+ if (parserConfig.globalVars)
+ state.globalVars = {name: varname, next: state.globalVars};
}
}
@@ -253,16 +302,15 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
};
}
- function statement(type) {
- if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+ function statement(type, value) {
+ if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
if (type == "function") return cont(functiondef);
- if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
- poplex, statement, poplex);
+ if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
@@ -270,6 +318,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
+ if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
+ if (type == "class") return cont(pushlex("form"), className, objlit, poplex);
+ if (type == "export") return cont(pushlex("form"), afterExport, poplex);
+ if (type == "import") return cont(pushlex("form"), afterImport, poplex);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
@@ -279,14 +331,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return expressionInner(type, true);
}
function expressionInner(type, noComma) {
+ if (cx.state.fatArrowAt == cx.stream.start) {
+ var body = noComma ? arrowBodyNoComma : arrowBody;
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
+ else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
+ }
+
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef);
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
- if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
- if (type == "operator") return cont(noComma ? expressionNoComma : expression);
- if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
- if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
+ if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
+ if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
+ if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
+ if (type == "{") return contCommasep(objprop, "}", null, maybeop);
return cont();
}
function maybeexpression(type) {
@@ -305,16 +363,39 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function maybeoperatorNoComma(type, value, noComma) {
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
var expr = noComma == false ? expression : expressionNoComma;
+ if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
if (type == "operator") {
if (/\+\+|--/.test(value)) return cont(me);
if (value == "?") return cont(expression, expect(":"), expr);
return cont(expr);
}
+ if (type == "quasi") { cx.cc.push(me); return quasi(value); }
if (type == ";") return;
- if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me);
+ if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
}
+ function quasi(value) {
+ if (value.slice(value.length - 2) != "${") return cont();
+ return cont(expression, continueQuasi);
+ }
+ function continueQuasi(type) {
+ if (type == "}") {
+ cx.marked = "string-2";
+ cx.state.tokenize = tokenQuasi;
+ return cont();
+ }
+ }
+ function arrowBody(type) {
+ findFatArrow(cx.stream, cx.state);
+ if (type == "{") return pass(statement);
+ return pass(expression);
+ }
+ function arrowBodyNoComma(type) {
+ findFatArrow(cx.stream, cx.state);
+ if (type == "{") return pass(statement);
+ return pass(expressionNoComma);
+ }
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
@@ -328,15 +409,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (value == "get" || value == "set") return cont(getterSetter);
} else if (type == "number" || type == "string") {
cx.marked = type + " property";
+ } else if (type == "[") {
+ return cont(expression, expect("]"), afterprop);
}
- if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma);
+ if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
}
function getterSetter(type) {
- if (type == ":") return cont(expression);
- if (type != "variable") return cont(expect(":"), expression);
+ if (type != "variable") return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
+ function afterprop(type) {
+ if (type == ":") return cont(expressionNoComma);
+ if (type == "(") return pass(functiondef);
+ }
function commasep(what, end) {
function proceed(type) {
if (type == ",") {
@@ -349,75 +435,138 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
return function(type) {
if (type == end) return cont();
- else return pass(what, proceed);
+ return pass(what, proceed);
};
}
+ function contCommasep(what, end, info) {
+ for (var i = 3; i < arguments.length; i++)
+ cx.cc.push(arguments[i]);
+ return cont(pushlex(end, info), commasep(what, end), poplex);
+ }
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type) {
- if (type == ":") return cont(typedef);
- return pass();
+ if (isTS && type == ":") return cont(typedef);
}
function typedef(type) {
if (type == "variable"){cx.marked = "variable-3"; return cont();}
- return pass();
}
- function vardef1(type, value) {
- if (type == "variable") {
+ function vardef() {
+ return pass(pattern, maybetype, maybeAssign, vardefCont);
+ }
+ function pattern(type, value) {
+ if (type == "variable") { register(value); return cont(); }
+ if (type == "[") return contCommasep(pattern, "]");
+ if (type == "{") return contCommasep(proppattern, "}");
+ }
+ function proppattern(type, value) {
+ if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
register(value);
- return isTS ? cont(maybetype, vardef2) : cont(vardef2);
+ return cont(maybeAssign);
}
- return pass();
+ if (type == "variable") cx.marked = "property";
+ return cont(expect(":"), pattern, maybeAssign);
}
- function vardef2(type, value) {
- if (value == "=") return cont(expressionNoComma, vardef2);
- if (type == ",") return cont(vardef1);
+ function maybeAssign(_type, value) {
+ if (value == "=") return cont(expressionNoComma);
+ }
+ function vardefCont(type) {
+ if (type == ",") return cont(vardef);
}
function maybeelse(type, value) {
if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
}
+ function forspec(type) {
+ if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
+ }
function forspec1(type) {
- if (type == "var") return cont(vardef1, expect(";"), forspec2);
+ if (type == "var") return cont(vardef, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
- if (type == "variable") return cont(formaybein);
+ if (type == "variable") return cont(formaybeinof);
return pass(expression, expect(";"), forspec2);
}
- function formaybein(_type, value) {
- if (value == "in") return cont(expression);
+ function formaybeinof(_type, value) {
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
- if (value == "in") return cont(expression);
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
+ if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);}
- if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
}
- function funarg(type, value) {
- if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
+ function funarg(type) {
+ if (type == "spread") return cont(funarg);
+ return pass(pattern, maybetype);
+ }
+ function className(type, value) {
+ if (type == "variable") {register(value); return cont(classNameAfter);}
+ }
+ function classNameAfter(_type, value) {
+ if (value == "extends") return cont(expression);
+ }
+ function objlit(type) {
+ if (type == "{") return contCommasep(objprop, "}");
+ }
+ function afterModule(type, value) {
+ if (type == "string") return cont(statement);
+ if (type == "variable") { register(value); return cont(maybeFrom); }
+ }
+ function afterExport(_type, value) {
+ if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
+ if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
+ return pass(statement);
+ }
+ function afterImport(type) {
+ if (type == "string") return cont();
+ return pass(importSpec, maybeFrom);
+ }
+ function importSpec(type, value) {
+ if (type == "{") return contCommasep(importSpec, "}");
+ if (type == "variable") register(value);
+ return cont();
+ }
+ function maybeFrom(_type, value) {
+ if (value == "from") { cx.marked = "keyword"; return cont(expression); }
+ }
+ function arrayLiteral(type) {
+ if (type == "]") return cont();
+ return pass(expressionNoComma, maybeArrayComprehension);
+ }
+ function maybeArrayComprehension(type) {
+ if (type == "for") return pass(comprehension, expect("]"));
+ if (type == ",") return cont(commasep(expressionNoComma, "]"));
+ return pass(commasep(expressionNoComma, "]"));
+ }
+ function comprehension(type) {
+ if (type == "for") return cont(forspec, comprehension);
+ if (type == "if") return cont(expression, comprehension);
}
// Interface
return {
startState: function(basecolumn) {
- return {
- tokenize: jsTokenBase,
- lastType: null,
+ var state = {
+ tokenize: tokenBase,
+ lastType: "sof",
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
- globalVars: parserConfig.globalVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
+ if (parserConfig.globalVars) state.globalVars = parserConfig.globalVars;
+ return state;
},
token: function(stream, state) {
@@ -425,8 +574,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
+ findFatArrow(stream, state);
}
- if (state.tokenize != jsTokenComment && stream.eatSpace()) return null;
+ if (state.tokenize != tokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
@@ -434,21 +584,21 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
},
indent: function(state, textAfter) {
- if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
- if (state.tokenize != jsTokenBase) return 0;
+ if (state.tokenize == tokenComment) return CodeMirror.Pass;
+ if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
// Kludge to prevent 'maybelse' from blocking lexical scope pops
for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex) lexical = lexical.prev;
- else if (c != maybeelse || /^else\b/.test(textAfter)) break;
+ else if (c != maybeelse) break;
}
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
- if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
diff --git a/applications/admin/static/codemirror/mode/meta.js b/applications/admin/static/codemirror/mode/meta.js
index f6bbd1b4..f37cea55 100644
--- a/applications/admin/static/codemirror/mode/meta.js
+++ b/applications/admin/static/codemirror/mode/meta.js
@@ -18,6 +18,7 @@ CodeMirror.modeInfo = [
{name: 'Eiffel', mime: 'text/x-eiffel', mode: 'eiffel'},
{name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'},
{name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'},
+ {name: 'F#', mime: 'text/x-fsharp', mode: 'mllike'},
{name: 'Gas', mime: 'text/x-gas', mode: 'gas'},
{name: 'Gherkin', mime: 'text/x-feature', mode: 'gherkin'},
{name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'},
@@ -36,7 +37,8 @@ CodeMirror.modeInfo = [
{name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
{name: 'JSON', mime: 'application/json', mode: 'javascript'},
{name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
- {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'},
+ {name: 'Jinja2', mime: null, mode: 'jinja2'},
+ {name: 'Julia', mime: 'text/x-julia', mode: 'julia'},
{name: 'LESS', mime: 'text/x-less', mode: 'less'},
{name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'},
{name: 'Lua', mime: 'text/x-lua', mode: 'lua'},
@@ -44,9 +46,10 @@ CodeMirror.modeInfo = [
{name: 'mIRC', mime: 'text/mirc', mode: 'mirc'},
{name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'},
{name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'},
- {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'},
+ {name: 'OCaml', mime: 'text/x-ocaml', mode: 'mllike'},
{name: 'Octave', mime: 'text/x-octave', mode: 'octave'},
{name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'},
+ {name: 'PEG.js', mime: null, mode: 'pegjs'},
{name: 'Perl', mime: 'text/x-perl', mode: 'perl'},
{name: 'PHP', mime: 'text/x-php', mode: 'php'},
{name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'},
diff --git a/applications/admin/static/codemirror/mode/python/python.js b/applications/admin/static/codemirror/mode/python/python.js
index 802c2dd4..8bea5d19 100644
--- a/applications/admin/static/codemirror/mode/python/python.js
+++ b/applications/admin/static/codemirror/mode/python/python.js
@@ -11,6 +11,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
+ var hangingIndent = parserConf.hangingIndent || parserConf.indentUnit;
var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
@@ -211,6 +212,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
break;
}
}
+ } else if (stream.match(/\s*($|#)/, false)) {
+ // An open paren/bracket/brace with only space or comments after it
+ // on the line will indent the next line a fixed amount, to make it
+ // easier to put arguments, list items, etc. on their own lines.
+ indentUnit = stream.indentation() + hangingIndent;
} else {
indentUnit = stream.column() + stream.current().length;
}
diff --git a/applications/admin/static/codemirror/mode/xml/xml.js b/applications/admin/static/codemirror/mode/xml/xml.js
index 4f49e07f..96b51ff9 100644
--- a/applications/admin/static/codemirror/mode/xml/xml.js
+++ b/applications/admin/static/codemirror/mode/xml/xml.js
@@ -45,7 +45,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
- var tagName, type;
+ var tagName, type, setStyle;
function inText(stream, state) {
function chain(parser) {
@@ -110,6 +110,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
return null;
} else if (ch == "<") {
state.tokenize = inText;
+ state.state = baseState;
+ state.tagName = state.tagStart = null;
var next = state.tokenize(stream, state);
return next ? next + " error" : "error";
} else if (/[\'\"]/.test(ch)) {
@@ -169,139 +171,124 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
};
}
- var curState, curStream, setStyle;
- function pass() {
- for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
+ function Context(state, tagName, startOfLine) {
+ this.prev = state.context;
+ this.tagName = tagName;
+ this.indent = state.indented;
+ this.startOfLine = startOfLine;
+ if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
+ this.noIndent = true;
}
- function cont() {
- pass.apply(null, arguments);
- return true;
+ function popContext(state) {
+ if (state.context) state.context = state.context.prev;
+ }
+ function maybePopContext(state, nextTagName) {
+ var parentTagName;
+ while (true) {
+ if (!state.context) {
+ return;
+ }
+ parentTagName = state.context.tagName.toLowerCase();
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
+ return;
+ }
+ popContext(state);
+ }
}
- function pushContext(tagName, startOfLine) {
- var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
- curState.context = {
- prev: curState.context,
- tagName: tagName,
- indent: curState.indented,
- startOfLine: startOfLine,
- noIndent: noIndent
- };
- }
- function popContext() {
- if (curState.context) curState.context = curState.context.prev;
- }
-
- function element(type) {
+ function baseState(type, stream, state) {
if (type == "openTag") {
- curState.tagName = tagName;
- curState.tagStart = curStream.column();
- return cont(attributes, endtag(curState.startOfLine));
+ state.tagName = tagName;
+ state.tagStart = stream.column();
+ return attrState;
} else if (type == "closeTag") {
var err = false;
- if (curState.context) {
- if (curState.context.tagName != tagName) {
- if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
- popContext();
- }
- err = !curState.context || curState.context.tagName != tagName;
+ if (state.context) {
+ if (state.context.tagName != tagName) {
+ if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName.toLowerCase()))
+ popContext(state);
+ err = !state.context || state.context.tagName != tagName;
}
} else {
err = true;
}
if (err) setStyle = "error";
- return cont(endclosetag(err));
+ return err ? closeStateErr : closeState;
+ } else {
+ return baseState;
}
- return cont();
}
- function endtag(startOfLine) {
- return function(type) {
- var tagName = curState.tagName;
- curState.tagName = curState.tagStart = null;
- if (type == "selfcloseTag" ||
- (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
- maybePopContext(tagName.toLowerCase());
- return cont();
- }
- if (type == "endTag") {
- maybePopContext(tagName.toLowerCase());
- pushContext(tagName, startOfLine);
- return cont();
- }
- return cont();
- };
- }
- function endclosetag(err) {
- return function(type) {
- if (err) setStyle = "error";
- if (type == "endTag") { popContext(); return cont(); }
+ function closeState(type, _stream, state) {
+ if (type != "endTag") {
setStyle = "error";
- return cont(arguments.callee);
- };
- }
- function maybePopContext(nextTagName) {
- var parentTagName;
- while (true) {
- if (!curState.context) {
- return;
- }
- parentTagName = curState.context.tagName.toLowerCase();
- if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
- !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
- return;
- }
- popContext();
+ return closeState;
}
+ popContext(state);
+ return baseState;
+ }
+ function closeStateErr(type, stream, state) {
+ setStyle = "error";
+ return closeState(type, stream, state);
}
- function attributes(type) {
- if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
- if (type == "endTag" || type == "selfcloseTag") return pass();
+ function attrState(type, _stream, state) {
+ if (type == "word") {
+ setStyle = "attribute";
+ return attrEqState;
+ } else if (type == "endTag" || type == "selfcloseTag") {
+ var tagName = state.tagName, tagStart = state.tagStart;
+ state.tagName = state.tagStart = null;
+ if (type == "selfcloseTag" ||
+ Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase())) {
+ maybePopContext(state, tagName.toLowerCase());
+ } else {
+ maybePopContext(state, tagName.toLowerCase());
+ state.context = new Context(state, tagName, tagStart == state.indented);
+ }
+ return baseState;
+ }
setStyle = "error";
- return cont(attributes);
+ return attrState;
}
- function attribute(type) {
- if (type == "equals") return cont(attvalue, attributes);
+ function attrEqState(type, stream, state) {
+ if (type == "equals") return attrValueState;
if (!Kludges.allowMissing) setStyle = "error";
- else if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
- return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
+ return attrState(type, stream, state);
}
- function attvalue(type) {
- if (type == "string") return cont(attvaluemaybe);
- if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
+ function attrValueState(type, stream, state) {
+ if (type == "string") return attrContinuedState;
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
setStyle = "error";
- return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
+ return attrState(type, stream, state);
}
- function attvaluemaybe(type) {
- if (type == "string") return cont(attvaluemaybe);
- else return pass();
+ function attrContinuedState(type, stream, state) {
+ if (type == "string") return attrContinuedState;
+ return attrState(type, stream, state);
}
return {
startState: function() {
- return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
+ return {tokenize: inText,
+ state: baseState,
+ indented: 0,
+ tagName: null, tagStart: null,
+ context: null};
},
token: function(stream, state) {
- if (!state.tagName && stream.sol()) {
- state.startOfLine = true;
+ if (!state.tagName && stream.sol())
state.indented = stream.indentation();
- }
- if (stream.eatSpace()) return null;
- setStyle = type = tagName = null;
+ if (stream.eatSpace()) return null;
+ tagName = type = null;
var style = state.tokenize(stream, state);
- state.type = type;
if ((style || type) && style != "comment") {
- curState = state; curStream = stream;
- while (true) {
- var comb = state.cc.pop() || element;
- if (comb(type || style)) break;
- }
+ setStyle = null;
+ state.state = state.state(type || style, stream, state);
+ if (setStyle)
+ style = setStyle == "error" ? style + " error" : setStyle;
}
- state.startOfLine = false;
- if (setStyle)
- style = setStyle == "error" ? style + " error" : setStyle;
return style;
},
@@ -311,8 +298,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
if (state.tokenize.isInAttribute) {
return state.stringStartCol + 1;
}
- if ((state.tokenize != inTag && state.tokenize != inText) ||
- context && context.noIndent)
+ if (context && context.noIndent) return CodeMirror.Pass;
+ if (state.tokenize != inTag && state.tokenize != inText)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
// Indent the starts of attribute names.
if (state.tagName) {
diff --git a/applications/admin/static/codemirror/package.json b/applications/admin/static/codemirror/package.json
deleted file mode 100644
index 8310ab15..00000000
--- a/applications/admin/static/codemirror/package.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "codemirror",
- "version":"3.19.0",
- "main": "lib/codemirror.js",
- "description": "In-browser code editing made bearable",
- "licenses": [{"type": "MIT",
- "url": "http://codemirror.net/LICENSE"}],
- "directories": {"lib": "./lib"},
- "scripts": {"test": "node ./test/run.js"},
- "devDependencies": {"node-static": "0.6.0"},
- "bugs": "http://github.com/marijnh/CodeMirror/issues",
- "keywords": ["JavaScript", "CodeMirror", "Editor"],
- "homepage": "http://codemirror.net",
- "maintainers":[{"name": "Marijn Haverbeke",
- "email": "marijnh@gmail.com",
- "web": "http://marijnhaverbeke.nl"}],
- "repository": {"type": "git",
- "url": "http://marijnhaverbeke.nl/git/codemirror"}
-}
diff --git a/applications/admin/static/codemirror/theme/ambiance.css b/applications/admin/static/codemirror/theme/ambiance.css
index a69d16e5..3a54b2a0 100644
--- a/applications/admin/static/codemirror/theme/ambiance.css
+++ b/applications/admin/static/codemirror/theme/ambiance.css
@@ -33,7 +33,7 @@
.cm-s-ambiance .CodeMirror-selected {
background: rgba(255, 255, 255, 0.15);
}
-.cm-s-ambiance .CodeMirror-focused .CodeMirror-selected {
+.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected {
background: rgba(255, 255, 255, 0.10);
}
diff --git a/applications/admin/static/codemirror/theme/mbo.css b/applications/admin/static/codemirror/theme/mbo.css
index f3250a73..bb52e6d1 100644
--- a/applications/admin/static/codemirror/theme/mbo.css
+++ b/applications/admin/static/codemirror/theme/mbo.css
@@ -24,11 +24,13 @@
.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}
.cm-s-mbo .CodeMirror-matchingbracket {
- text-decoration: underline;
+ text-decoration: underline;
color: #f5e107 !important;
}
+
+.cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;}
-div.CodeMirror span.CodeMirror-searching {
+.cm-s-mbo span.cm-searching {
background-color: none;
background: none;
box-shadow: 0 0 0 1px #ffffec;
diff --git a/applications/admin/static/codemirror/theme/midnight.css b/applications/admin/static/codemirror/theme/midnight.css
index 66126322..468d87da 100644
--- a/applications/admin/static/codemirror/theme/midnight.css
+++ b/applications/admin/static/codemirror/theme/midnight.css
@@ -1,7 +1,7 @@
/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */
/**/
-.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949 }
+.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }
.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }
/**/
diff --git a/applications/admin/static/codemirror/theme/pastel-on-dark.css b/applications/admin/static/codemirror/theme/pastel-on-dark.css
new file mode 100644
index 00000000..df95699a
--- /dev/null
+++ b/applications/admin/static/codemirror/theme/pastel-on-dark.css
@@ -0,0 +1,49 @@
+/**
+ * Pastel On Dark theme ported from ACE editor
+ * @license MIT
+ * @copyright AtomicPages LLC 2014
+ * @author Dennis Thompson, AtomicPages LLC
+ * @version 1.1
+ * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme
+ */
+
+.cm-s-pastel-on-dark.CodeMirror {
+ background: #2c2827;
+ color: #8F938F;
+ line-height: 1.5;
+ font-family: consolas, Courier, monospace;
+ font-size: 14px;
+}
+.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
+.cm-s-pastel-on-dark .CodeMirror-gutters {
+ background: #34302f;
+ border-right: 0px;
+ padding: 0 3px;
+}
+.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }
+.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
+.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }
+.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }
+.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }
+.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }
+.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-string { color: #66A968; }
+.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
+.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
+.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
+.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }
+.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-error {
+ background: #757aD8;
+ color: #f8f8f0;
+}
+.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; }
+.cm-s-pastel-on-dark .CodeMirror-matchingbracket {
+ border: 1px solid rgba(255,255,255,0.25);
+ color: #8F938F !important;
+ margin: -1px -1px 0 -1px;
+}
diff --git a/applications/admin/static/codemirror/theme/the-matrix.css b/applications/admin/static/codemirror/theme/the-matrix.css
index 9e60b7b0..0c3704a6 100644
--- a/applications/admin/static/codemirror/theme/the-matrix.css
+++ b/applications/admin/static/codemirror/theme/the-matrix.css
@@ -1,5 +1,5 @@
.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
-.cm-s-the-matrix span.CodeMirror-selected { background: #a8f !important; }
+.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; }
.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }
.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }
.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; }