diff --git a/rhodecode/public/css/codemirror.css b/rhodecode/public/css/codemirror.css --- a/rhodecode/public/css/codemirror.css +++ b/rhodecode/public/css/codemirror.css @@ -192,6 +192,16 @@ div.CodeMirror span.CodeMirror-nonmatchi white-space: pre-wrap; word-break: normal; } +.CodeMirror-code pre { + border-right: 30px solid transparent; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; +} +.CodeMirror-wrap .CodeMirror-code pre { + border-right: none; + width: auto; +} .CodeMirror-linebackground { position: absolute; left: 0; right: 0; top: 0; bottom: 0; diff --git a/rhodecode/public/js/codemirror.js b/rhodecode/public/js/codemirror.js --- a/rhodecode/public/js/codemirror.js +++ b/rhodecode/public/js/codemirror.js @@ -1,4 +1,4 @@ -// CodeMirror version 3.14 +// CodeMirror version 3.15 // // CodeMirror is the only global var we claim window.CodeMirror = (function() { @@ -30,6 +30,7 @@ window.CodeMirror = (function() { var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/); if (opera_version) opera_version = Number(opera_version[1]); + 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); @@ -403,11 +404,12 @@ window.CodeMirror = (function() { // DISPLAY DRAWING - function updateDisplay(cm, changes, viewPort) { + function updateDisplay(cm, changes, viewPort, forced) { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; var visible = visibleLines(cm.display, cm.doc, viewPort); for (;;) { - if (!updateDisplayInner(cm, changes, visible)) break; + if (!updateDisplayInner(cm, changes, visible, forced)) break; + forced = false; updated = true; updateSelection(cm); updateScrollbars(cm); @@ -433,7 +435,7 @@ window.CodeMirror = (function() { // Uses a set of changes plus the current scroll position to // determine which DOM updates have to be made, and makes the // updates. - function updateDisplayInner(cm, changes, visible) { + function updateDisplayInner(cm, changes, visible, forced) { var display = cm.display, doc = cm.doc; if (!display.wrapper.clientWidth) { display.showingFrom = display.showingTo = doc.first; @@ -442,7 +444,7 @@ window.CodeMirror = (function() { } // Bail out if the visible area is already rendered and nothing changed. - if (changes.length == 0 && + if (!forced && changes.length == 0 && visible.from > display.showingFrom && visible.to < display.showingTo) return; @@ -495,7 +497,7 @@ window.CodeMirror = (function() { if (range.from >= range.to) intact.splice(i--, 1); else intactLines += range.to - range.from; } - if (intactLines == to - from && from == display.showingFrom && to == display.showingTo) { + if (!forced && intactLines == to - from && from == display.showingFrom && to == display.showingTo) { updateViewOffset(cm); return; } @@ -520,6 +522,14 @@ window.CodeMirror = (function() { } display.showingFrom = from; display.showingTo = to; + updateHeightsInViewport(cm); + updateViewOffset(cm); + + return true; + } + + function updateHeightsInViewport(cm) { + var display = cm.display; var prevBottom = display.lineDiv.offsetTop; for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) { if (ie_lt8) { @@ -539,9 +549,6 @@ window.CodeMirror = (function() { widgets[i].height = widgets[i].node.offsetHeight; } } - updateViewOffset(cm); - - return true; } function updateViewOffset(cm) { @@ -670,10 +677,10 @@ window.CodeMirror = (function() { if (!/\bCodeMirror-linewidget\b/.test(n.className)) { reuse.removeChild(n); } else { - for (var i = 0, first = true; i < line.widgets.length; ++i) { + for (var i = 0; i < line.widgets.length; ++i) { var widget = line.widgets[i]; - if (!widget.above) { insertBefore = n; first = false; } if (widget.node == n.firstChild) { + if (!widget.above && !insertBefore) insertBefore = n; positionLineWidget(widget, n, reuse, dims); ++widgetsSeen; break; @@ -966,11 +973,13 @@ window.CodeMirror = (function() { if (r) break; if (dir < 0 && pos == 0) dir = 1; } - var rightV = (pos < ch || bias == "right") && r.topRight != null; + bias = pos > ch ? "left" : pos < ch ? "right" : bias; + if (bias == "left" && r.leftSide) r = r.leftSide; + else if (bias == "right" && r.rightSide) r = r.rightSide; return {left: pos < ch ? r.right : r.left, right: pos > ch ? r.left : r.right, - top: rightV ? r.topRight : r.top, - bottom: rightV ? r.bottomRight : r.bottom}; + top: r.top, + bottom: r.bottom}; } function findCachedMeasurement(cm, line) { @@ -1007,7 +1016,7 @@ window.CodeMirror = (function() { function measureLineInner(cm, line) { var display = cm.display, measure = emptyArray(line.text.length); - var pre = lineContent(cm, line, measure); + var pre = lineContent(cm, line, measure, true); // IE does not cache element positions of inline elements between // calls to getBoundingClientRect. This makes the loop below, @@ -1043,48 +1052,50 @@ window.CodeMirror = (function() { if (ie_lt9 && display.measure.first != pre) removeChildrenAndAdd(display.measure, pre); - function categorizeVSpan(top, bot) { + function measureRect(rect) { + var top = rect.top - outer.top, bot = rect.bottom - outer.top; if (bot > maxBot) bot = maxBot; if (top < 0) top = 0; - for (var j = 0; j < vranges.length; j += 2) { - var rtop = vranges[j], rbot = vranges[j+1]; + for (var i = vranges.length - 2; i >= 0; i -= 2) { + var rtop = vranges[i], rbot = vranges[i+1]; if (rtop > bot || rbot < top) continue; if (rtop <= top && rbot >= bot || top <= rtop && bot >= rbot || Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) { - vranges[j] = Math.min(top, rtop); - vranges[j+1] = Math.max(bot, rbot); - return j; + vranges[i] = Math.min(top, rtop); + vranges[i+1] = Math.max(bot, rbot); + break; } } - vranges.push(top, bot); - return j; + if (i < 0) { i = vranges.length; vranges.push(top, bot); } + return {left: rect.left - outer.left, + right: rect.right - outer.left, + top: i, bottom: null}; + } + function finishRect(rect) { + rect.bottom = vranges[rect.top+1]; + rect.top = vranges[rect.top]; } for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) { - var size, node = cur; + var node = cur, rect = null; // A widget might wrap, needs special care if (/\bCodeMirror-widget\b/.test(cur.className) && cur.getClientRects) { if (cur.firstChild.nodeType == 1) node = cur.firstChild; - var rects = node.getClientRects(), rLeft = rects[0], rRight = rects[rects.length - 1]; + var rects = node.getClientRects(); if (rects.length > 1) { - var vCatLeft = categorizeVSpan(rLeft.top - outer.top, rLeft.bottom - outer.top); - var vCatRight = categorizeVSpan(rRight.top - outer.top, rRight.bottom - outer.top); - data[i] = {left: rLeft.left - outer.left, right: rRight.right - outer.left, - top: vCatLeft, topRight: vCatRight}; - continue; + rect = data[i] = measureRect(rects[0]); + rect.rightSide = measureRect(rects[rects.length - 1]); } } - size = getRect(node); - var vCat = categorizeVSpan(size.top - outer.top, size.bottom - outer.top); - var right = size.right; - if (cur.measureRight) right = getRect(cur.measureRight).left; - data[i] = {left: size.left - outer.left, right: right - outer.left, top: vCat}; + if (!rect) rect = data[i] = measureRect(getRect(node)); + if (cur.measureRight) rect.right = getRect(cur.measureRight).left; + if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); } for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { - var vr = cur.top, vrRight = cur.topRight; - cur.top = vranges[vr]; cur.bottom = vranges[vr+1]; - if (vrRight != null) { cur.topRight = vranges[vrRight]; cur.bottomRight = vranges[vrRight+1]; } + finishRect(cur); + if (cur.leftSide) finishRect(cur.leftSide); + if (cur.rightSide) finishRect(cur.rightSide); } return data; } @@ -1098,7 +1109,7 @@ window.CodeMirror = (function() { var cached = !hasBadSpan && findCachedMeasurement(cm, line); if (cached) return measureChar(cm, line, line.text.length, cached.measure, "right").right; - var pre = lineContent(cm, line); + var pre = lineContent(cm, line, null, true); var end = pre.appendChild(zeroWidthElement(cm.display.measure)); removeChildrenAndAdd(cm.display.measure, pre); return getRect(end).right - getRect(cm.display.lineDiv).left; @@ -1302,6 +1313,7 @@ window.CodeMirror = (function() { // An array of ranges of lines that have to be updated. See // updateDisplay. changes: [], + forceUpdate: false, updateInput: null, userSelChange: null, textChanged: null, @@ -1334,8 +1346,8 @@ window.CodeMirror = (function() { var coords = cursorCoords(cm, doc.sel.head); newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); } - if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null) { - updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop); + if (op.changes.length || op.forceUpdate || newScrollPos && newScrollPos.scrollTop != null) { + updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop, op.forceUpdate); if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop; } if (!updated && op.selectionChanged) updateSelection(cm); @@ -2105,6 +2117,7 @@ window.CodeMirror = (function() { var detectingSelectAll; function onContextMenu(cm, e) { + if (signalDOMEvent(cm, e, "contextmenu")) return; var display = cm.display, sel = cm.doc.sel; if (eventInWidget(display, e)) return; @@ -2755,7 +2768,7 @@ window.CodeMirror = (function() { function findWordAt(line, pos) { var start = pos.ch, end = pos.ch; if (line) { - if (pos.xRel < 0 || end == line.length) --start; else ++end; + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; var startChar = line.charAt(start); var check = isWordChar(startChar) ? isWordChar : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} @@ -2796,7 +2809,7 @@ window.CodeMirror = (function() { removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) - if ((typeof map == "string" ? maps[i].name : maps[i]) == map) { + if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) { maps.splice(i, 1); return true; } @@ -2860,6 +2873,7 @@ window.CodeMirror = (function() { pos = clipPos(this.doc, pos); var styles = getLineStyles(this, getLine(this.doc, pos.line)); var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + if (ch == 0) return styles[2]; for (;;) { var mid = (before + after) >> 1; if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; @@ -2868,6 +2882,20 @@ window.CodeMirror = (function() { } }, + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + if (!helpers.hasOwnProperty(type)) return; + var help = helpers[type], mode = this.getModeAt(pos); + return mode[type] && help[mode[type]] || + mode.helperType && help[mode.helperType] || + help[mode.name]; + }, + getStateAfter: function(line, precise) { var doc = this.doc; line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); @@ -3097,17 +3125,16 @@ window.CodeMirror = (function() { updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop); }), - setSize: function(width, height) { + setSize: operation(null, function(width, height) { function interpret(val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } if (width != null) this.display.wrapper.style.width = interpret(width); if (height != null) this.display.wrapper.style.height = interpret(height); - this.refresh(); - }, - - on: function(type, f) {on(this, type, f);}, - off: function(type, f) {off(this, type, f);}, + if (this.options.lineWrapping) + this.display.measureLineCache.length = this.display.measureLineCachePos = 0; + this.curOp.forceUpdate = true; + }), operation: function(f){return runInOp(this, f);}, @@ -3132,6 +3159,7 @@ window.CodeMirror = (function() { getScrollerElement: function(){return this.display.scroller;}, getGutterElement: function(){return this.display.gutters;} }; + eventMixin(CodeMirror); // OPTION DEFAULTS @@ -3256,7 +3284,7 @@ window.CodeMirror = (function() { }; CodeMirror.getMode = function(options, spec) { - spec = CodeMirror.resolveMode(spec); + var spec = CodeMirror.resolveMode(spec); var mfactory = modes[spec.name]; if (!mfactory) return CodeMirror.getMode(options, "text/plain"); var modeObj = mfactory(options, spec); @@ -3269,6 +3297,7 @@ window.CodeMirror = (function() { } } modeObj.name = spec.name; + return modeObj; }; @@ -3296,6 +3325,16 @@ window.CodeMirror = (function() { var initHooks = []; CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {}; + helpers[type][name] = value; + }; + + // UTILITIES + + CodeMirror.isWordChar = isWordChar; + // MODE STATE HANDLING // Utility functions for working with state. Exported because modes @@ -3321,6 +3360,7 @@ window.CodeMirror = (function() { CodeMirror.innerMode = function(mode, state) { while (mode.innerMode) { var info = mode.innerMode(state); + if (!info || info.mode == mode) break; state = info.state; mode = info.mode; } @@ -3633,11 +3673,16 @@ window.CodeMirror = (function() { this.doc = doc; } CodeMirror.TextMarker = TextMarker; + eventMixin(TextMarker); TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; @@ -3666,7 +3711,6 @@ window.CodeMirror = (function() { if (cm) reCheckSelection(cm); } if (withOp) endOperation(cm); - signalLater(this, "clear"); }; TextMarker.prototype.find = function() { @@ -3694,7 +3738,9 @@ window.CodeMirror = (function() { if (node.offsetHeight != line.height) updateLineHeight(line, node.offsetHeight); break; } - runInOp(cm, function() { cm.curOp.selectionChanged = true; }); + runInOp(cm, function() { + cm.curOp.selectionChanged = cm.curOp.forceUpdate = cm.curOp.updateMaxLine = true; + }); } }; @@ -3767,7 +3813,7 @@ window.CodeMirror = (function() { } if (cm) { if (updateMaxLine) cm.curOp.updateMaxLine = true; - if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed) + if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed) regChange(cm, from.line, to.line + 1); if (marker.atomic) reCheckSelection(cm); } @@ -3785,6 +3831,7 @@ window.CodeMirror = (function() { } } CodeMirror.SharedTextMarker = SharedTextMarker; + eventMixin(SharedTextMarker); SharedTextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; @@ -4037,11 +4084,12 @@ window.CodeMirror = (function() { // LINE WIDGETS var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { - for (var opt in options) if (options.hasOwnProperty(opt)) + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt]; this.cm = cm; this.node = node; }; + eventMixin(LineWidget); function widgetOperation(f) { return function() { var withOp = !this.cm.curOp; @@ -4056,7 +4104,9 @@ window.CodeMirror = (function() { if (no == null || !ws) return; for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); if (!ws.length) this.line.widgets = null; + var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop; updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this))); + if (aboveVisible) addToScrollPos(this.cm, 0, -this.height); regChange(this.cm, no, no + 1); }); LineWidget.prototype.changed = widgetOperation(function() { @@ -4080,10 +4130,12 @@ window.CodeMirror = (function() { var widget = new LineWidget(cm, node, options); if (widget.noHScroll) cm.display.alignWidgets = true; changeLine(cm, handle, function(line) { - (line.widgets || (line.widgets = [])).push(widget); + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); widget.line = line; if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { - var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop; + var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, 0, widget.height); } @@ -4096,12 +4148,12 @@ window.CodeMirror = (function() { // Line objects. These hold state related to a line, including // highlighting info (the styles array). - function makeLine(text, markedSpans, estimateHeight) { - var line = {text: text}; - attachMarkedSpans(line, markedSpans); - line.height = estimateHeight ? estimateHeight(line) : 1; - return line; - } + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); function updateLine(line, text, markedSpans, estimateHeight) { line.text = text; @@ -4207,13 +4259,14 @@ window.CodeMirror = (function() { (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); } - function lineContent(cm, realLine, measure) { + function lineContent(cm, realLine, measure, copyWidgets) { var merged, line = realLine, empty = true; while (merged = collapsedSpanAtStart(line)) line = getLine(cm.doc, merged.find().from.line); - var builder = {pre: elt("pre"), col: 0, pos: 0, display: !measure, - measure: null, measuredSomething: false, cm: cm}; + var builder = {pre: elt("pre"), col: 0, pos: 0, + measure: null, measuredSomething: false, cm: cm, + copyWidgets: copyWidgets}; if (line.textClass) builder.pre.className = line.textClass; do { @@ -4256,7 +4309,7 @@ window.CodeMirror = (function() { } var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; - function buildToken(builder, text, style, startStyle, endStyle) { + function buildToken(builder, text, style, startStyle, endStyle, title) { if (!text) return; if (!tokenSpecialChars.test(text)) { builder.col += text.length; @@ -4289,7 +4342,9 @@ window.CodeMirror = (function() { var fullStyle = style || ""; if (startStyle) fullStyle += startStyle; if (endStyle) fullStyle += endStyle; - return builder.pre.appendChild(elt("span", [content], fullStyle)); + var token = elt("span", [content], fullStyle); + if (title) token.title = title; + return builder.pre.appendChild(token); } builder.pre.appendChild(content); } @@ -4304,9 +4359,11 @@ window.CodeMirror = (function() { } else 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, start && startStyle, i == text.length - 1 && endStyle); + if (old) span.leftSide = old.leftSide || old; // In IE single-space nodes wrap differently than spaces // embedded in larger text nodes, except when set to // white-space: normal (issue #1268). @@ -4325,20 +4382,28 @@ window.CodeMirror = (function() { out += " "; return out; } - return function(builder, text, style, startStyle, endStyle) { - return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle); + return function(builder, text, style, startStyle, endStyle, title) { + return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle, title); }; } - function buildCollapsedSpan(builder, size, widget) { + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.replacedWith; if (widget) { - if (!builder.display) widget = widget.cloneNode(true); + if (builder.copyWidgets) widget = widget.cloneNode(true); + builder.pre.appendChild(widget); if (builder.measure) { - builder.measure[builder.pos] = size ? widget - : builder.pre.appendChild(zeroWidthElement(builder.cm.display.measure)); + if (size) { + builder.measure[builder.pos] = widget; + } else { + var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.display.measure); + if (marker.type != "bookmark" || marker.insertLeft) + builder.pre.insertBefore(elt, widget); + else + builder.pre.appendChild(elt); + } builder.measuredSomething = true; } - builder.pre.appendChild(widget); } builder.pos += size; } @@ -4354,10 +4419,10 @@ window.CodeMirror = (function() { } var len = allText.length, pos = 0, i = 1, text = "", style; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; for (;;) { if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = ""; + spanStyle = spanEndStyle = spanStartStyle = title = ""; collapsed = null; nextChange = Infinity; var foundBookmark = null; for (var j = 0; j < spans.length; ++j) { @@ -4367,17 +4432,17 @@ window.CodeMirror = (function() { if (m.className) spanStyle += " " + m.className; 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)) collapsed = sp; } else if (sp.from > pos && nextChange > sp.from) { nextChange = sp.from; } - if (m.type == "bookmark" && sp.from == pos && m.replacedWith) - foundBookmark = m.replacedWith; + if (m.type == "bookmark" && sp.from == pos && m.replacedWith) foundBookmark = m; } if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos, - collapsed.from != null && collapsed.marker.replacedWith); + collapsed.marker, collapsed.from == null); if (collapsed.to == null) return collapsed.marker.find(); } if (foundBookmark && !collapsed) buildCollapsedSpan(builder, 0, foundBookmark); @@ -4391,7 +4456,7 @@ window.CodeMirror = (function() { if (!collapsed) { var tokenText = end > upto ? text.slice(0, upto - pos) : text; builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : ""); + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title); } if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} pos = end; @@ -4421,7 +4486,7 @@ window.CodeMirror = (function() { // 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) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); update(lastLine, lastLine.text, lastSpans); if (nlines) doc.remove(from.line, nlines); if (added.length) doc.insert(from.line, added); @@ -4430,8 +4495,8 @@ window.CodeMirror = (function() { update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { for (var added = [], i = 1, e = text.length - 1; i < e; ++i) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); - added.push(makeLine(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added); } @@ -4442,7 +4507,7 @@ window.CodeMirror = (function() { update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); for (var i = 1, e = text.length - 1, added = []; i < e; ++i) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); if (nlines > 1) doc.remove(from.line + 1, nlines - 1); doc.insert(from.line + 1, added); } @@ -4585,7 +4650,7 @@ window.CodeMirror = (function() { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); if (firstLine == null) firstLine = 0; - BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; this.cantEdit = false; @@ -4650,6 +4715,11 @@ window.CodeMirror = (function() { getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, getLineNumber: function(line) {return lineNo(line);}, + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(this, line); + }, + lineCount: function() {return this.size;}, firstLine: function() {return this.first;}, lastLine: function() {return this.first + this.size - 1;}, @@ -4820,6 +4890,8 @@ window.CodeMirror = (function() { return function() {return method.apply(this.doc, arguments);}; })(Doc.prototype[prop]); + eventMixin(Doc); + function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { @@ -4963,7 +5035,8 @@ window.CodeMirror = (function() { } function historyChangeFromChange(doc, change) { - var histChange = {from: change.from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + var from = { line: change.from.line, ch: change.from.ch }; + var histChange = {from: from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); return histChange; @@ -5183,9 +5256,9 @@ window.CodeMirror = (function() { delayedCallbacks.push(bnd(arr[i])); } - function signalDOMEvent(cm, e) { - signal(cm, e.type, cm, e); - return e_defaultPrevented(e); + function signalDOMEvent(cm, e, override) { + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; } function fireDelayed() { @@ -5202,6 +5275,11 @@ window.CodeMirror = (function() { CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal; + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + // MISC UTILITIES // Number of pixels added to scroller and sizer to hide scrollbar @@ -5353,10 +5431,12 @@ window.CodeMirror = (function() { spanAffectsWrapping = function(str, i) { return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1)); }; - else if (webkit) + else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent)) spanAffectsWrapping = function(str, i) { - if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) - return true; + if (i > 1 && str.charCodeAt(i - 1) == 45) { + 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)); }; @@ -5443,11 +5523,15 @@ window.CodeMirror = (function() { function iterateBidiSections(order, from, to, f) { if (!order) return f(from, to, "ltr"); + var found = false; for (var i = 0; i < order.length; ++i) { var part = order[i]; - if (part.from < to && part.to > from || from == to && part.to == from) + if (part.from < to && part.to > from || from == to && part.to == from) { f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); - } + found = true; + } + } + if (!found) f(from, to, "ltr"); } function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } @@ -5709,7 +5793,7 @@ window.CodeMirror = (function() { // THE END - CodeMirror.version = "3.14.0"; + CodeMirror.version = "3.15.0"; return CodeMirror; })(); diff --git a/rhodecode/public/js/mode/clike/clike.js b/rhodecode/public/js/mode/clike/clike.js --- a/rhodecode/public/js/mode/clike/clike.js +++ b/rhodecode/public/js/mode/clike/clike.js @@ -158,7 +158,8 @@ CodeMirror.defineMode("clike", function( electricChars: "{}", blockCommentStart: "/*", blockCommentEnd: "*/", - lineComment: "//" + lineComment: "//", + fold: "brace" }; }); diff --git a/rhodecode/public/js/mode/coffeescript/coffeescript.js b/rhodecode/public/js/mode/coffeescript/coffeescript.js --- a/rhodecode/public/js/mode/coffeescript/coffeescript.js +++ b/rhodecode/public/js/mode/coffeescript/coffeescript.js @@ -339,7 +339,8 @@ CodeMirror.defineMode('coffeescript', fu return state.scopes[0].offset; }, - lineComment: "#" + lineComment: "#", + fold: "indent" }; return external; }); diff --git a/rhodecode/public/js/mode/css/css.js b/rhodecode/public/js/mode/css/css.js --- a/rhodecode/public/js/mode/css/css.js +++ b/rhodecode/public/js/mode/css/css.js @@ -103,7 +103,8 @@ CodeMirror.defineMode("css-base", functi startState: function(base) { return {tokenize: tokenBase, baseIndent: base || 0, - stack: []}; + stack: [], + lastToken: null}; }, token: function(stream, state) { @@ -163,7 +164,7 @@ CodeMirror.defineMode("css-base", functi var context = state.stack[state.stack.length-1]; if (style == "variable") { if (type == "variable-definition") state.stack.push("propertyValue"); - return "variable-2"; + return state.lastToken = "variable-2"; } else if (style == "property") { var word = stream.current().toLowerCase(); if (context == "propertyValue") { @@ -251,7 +252,6 @@ CodeMirror.defineMode("css-base", functi // Push/pop context stack if (type == "{") { if (context == "@media" || context == "@mediaType") { - state.stack.pop(); state.stack[state.stack.length-1] = "@media{"; } else { @@ -260,8 +260,7 @@ CodeMirror.defineMode("css-base", functi } } else if (type == "}") { - var lastState = state.stack[state.stack.length - 1]; - if (lastState == "interpolation") style = "operator"; + if (context == "interpolation") style = "operator"; state.stack.pop(); if (context == "propertyValue") state.stack.pop(); } @@ -269,26 +268,44 @@ CodeMirror.defineMode("css-base", functi 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.push("@mediaType"); - else if (context == "@mediaType" && stream.current() == ",") state.stack.pop(); - else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType("); - else if (context == "@mediaType(" && type == ")") state.stack.pop(); - else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue"); + 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 if (type == ")") { + if (context == "propertyValue" && state.stack[state.stack.length-2] == "@mediaType(") { + // In @mediaType( without closing ; after propertyValue + state.stack.pop(); + state.stack.pop(); + } + else if (context == "@mediaType(") { + state.stack.pop(); + } + } + 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 style; + + return state.lastToken = style; }, indent: function(state, textAfter) { var n = state.stack.length; if (/^\}/.test(textAfter)) - n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1; + n -= state.stack[n-1] == "propertyValue" ? 2 : 1; return state.baseIndent + n * indentUnit; }, electricChars: "}", blockCommentStart: "/*", - blockCommentEnd: "*/" + blockCommentEnd: "*/", + fold: "brace" }; }); @@ -384,15 +401,15 @@ CodeMirror.defineMode("css-base", functi "text-decoration-color", "text-decoration-line", "text-decoration-skip", "text-decoration-style", "text-emphasis", "text-emphasis-color", "text-emphasis-position", "text-emphasis-style", "text-height", - "text-indent", "text-justify", "text-outline", "text-shadow", - "text-space-collapse", "text-transform", "text-underline-position", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", "text-wrap", "top", "transform", "transform-origin", "transform-style", "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function", "unicode-bidi", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", - "word-spacing", "word-wrap", "z-index", + "word-spacing", "word-wrap", "z-index", "zoom", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", diff --git a/rhodecode/public/js/mode/css/scss_test.js b/rhodecode/public/js/mode/css/scss_test.js --- a/rhodecode/public/js/mode/css/scss_test.js +++ b/rhodecode/public/js/mode/css/scss_test.js @@ -64,7 +64,7 @@ "[tag p] { [tag a] { [property color][operator :][atom #000]; } }"); MT('interpolation_in_property', - "[tag foo] { [operator #{][variable-2 $hello][operator }:][atom #000]; }"); + "[tag foo] { [operator #{][variable-2 $hello][operator }:][number 2]; }"); MT('interpolation_in_selector', "[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }"); diff --git a/rhodecode/public/js/mode/css/test.js b/rhodecode/public/js/mode/css/test.js --- a/rhodecode/public/js/mode/css/test.js +++ b/rhodecode/public/js/mode/css/test.js @@ -15,6 +15,12 @@ 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] { }"); @@ -53,6 +59,10 @@ MT("atMediaUnknownProperty", "[def @media] [attribute screen] [operator and] ([property&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] { } }"); + MT("tagSelector", "[tag foo] { }"); @@ -108,6 +118,9 @@ MT("tagTwoProperties", "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }"); + MT("tagTwoPropertiesURL", + "[tag foo] { [property background][operator :] [string-2 url]([string //example.com/foo.png]); [property padding][operator :] [number 0]; }"); + MT("commentSGML", "[comment ]"); })(); diff --git a/rhodecode/public/js/mode/groovy/groovy.js b/rhodecode/public/js/mode/groovy/groovy.js --- a/rhodecode/public/js/mode/groovy/groovy.js +++ b/rhodecode/public/js/mode/groovy/groovy.js @@ -203,7 +203,8 @@ CodeMirror.defineMode("groovy", function else return ctx.indented + (closing ? 0 : config.indentUnit); }, - electricChars: "{}" + electricChars: "{}", + fold: "brace" }; }); diff --git a/rhodecode/public/js/mode/jade/index.html b/rhodecode/public/js/mode/jade/index.html new file mode 100644 --- /dev/null +++ b/rhodecode/public/js/mode/jade/index.html @@ -0,0 +1,54 @@ + + +
+ +Created by Drew Bratcher. Managed as part of an Adobe Brackets extension at https://github.com/dbratcher/brackets-jade.
+MIME type defined: text/x-jade.
MIME types defined: text/nginx.
^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
^((//=)|(>>=)|(<<=)|(\\*\\*=))
^[_A-Za-z][_A-Za-z0-9]*
MIME types defined: text/x-python.
MIME types defined: text/x-python and text/x-cython.