app/assets/javascripts/vendor/ace.js in formagic-0.1.0 vs app/assets/javascripts/vendor/ace.js in formagic-0.2.5

- old
+ new

@@ -1033,10 +1033,13 @@ if (id && exports.hasCssString(id, doc)) return null; var style; + if (id) + cssText += "\n/*# sourceURL=ace/css/" + id + " */"; + if (doc.createStyleSheet) { style = doc.createStyleSheet(); style.cssText = cssText; if (id) style.owningElement.id = id; @@ -1079,46 +1082,10 @@ parseInt(exports.computedStyle(element, "paddingBottom"), 10) + element.clientHeight ); }; - -if (typeof document == "undefined") - return; - -if (window.pageYOffset !== undefined) { - exports.getPageScrollTop = function() { - return window.pageYOffset; - }; - - exports.getPageScrollLeft = function() { - return window.pageXOffset; - }; -} -else { - exports.getPageScrollTop = function() { - return document.body.scrollTop; - }; - - exports.getPageScrollLeft = function() { - return document.body.scrollLeft; - }; -} - -if (window.getComputedStyle) - exports.computedStyle = function(element, style) { - if (style) - return (window.getComputedStyle(element, "") || {})[style] || ""; - return window.getComputedStyle(element, "") || {}; - }; -else - exports.computedStyle = function(element, style) { - if (style) - return element.currentStyle[style]; - return element.currentStyle; - }; - exports.scrollbarWidth = function(document) { var inner = exports.createElement("ace_inner"); inner.style.width = "100%"; inner.style.minWidth = "0px"; inner.style.height = "200px"; @@ -1151,10 +1118,47 @@ body.removeChild(outer); return noScrollbar-withScrollbar; }; + +if (typeof document == "undefined") { + exports.importCssString = function() {}; + return; +} + +if (window.pageYOffset !== undefined) { + exports.getPageScrollTop = function() { + return window.pageYOffset; + }; + + exports.getPageScrollLeft = function() { + return window.pageXOffset; + }; +} +else { + exports.getPageScrollTop = function() { + return document.body.scrollTop; + }; + + exports.getPageScrollLeft = function() { + return document.body.scrollLeft; + }; +} + +if (window.getComputedStyle) + exports.computedStyle = function(element, style) { + if (style) + return (window.getComputedStyle(element, "") || {})[style] || ""; + return window.getComputedStyle(element, "") || {}; + }; +else + exports.computedStyle = function(element, style) { + if (style) + return element.currentStyle[style]; + return element.currentStyle; + }; exports.setInnerHtml = function(el, innerHtml) { var element = el.cloneNode(false);//document.createElement("div"); element.innerHTML = innerHtml; el.parentNode.replaceChild(element, el); return element; @@ -1280,12 +1284,12 @@ 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a', 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', - 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 219: '[', - 220: '\\',221: ']', 222: '\'' + 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', + 219: '[', 220: '\\',221: ']', 222: '\'' } }; var name, i; for (i in ret.FUNCTION_KEYS) { name = ret.FUNCTION_KEYS[i].toLowerCase(); @@ -1449,10 +1453,33 @@ exports.addListener(document, "dragstart", onMouseUp, true); return onMouseUp; }; +exports.addTouchMoveListener = function (el, callback) { + if ("ontouchmove" in el) { + var startx, starty; + exports.addListener(el, "touchstart", function (e) { + var touchObj = e.changedTouches[0]; + startx = touchObj.clientX; + starty = touchObj.clientY; + }); + exports.addListener(el, "touchmove", function (e) { + var factor = 1, + touchObj = e.changedTouches[0]; + + e.wheelX = -(touchObj.clientX - startx) / factor; + e.wheelY = -(touchObj.clientY - starty) / factor; + + startx = touchObj.clientX; + starty = touchObj.clientY; + + callback(e); + }); + } +}; + exports.addMouseWheelListener = function(el, callback) { if ("onmousewheel" in el) { exports.addListener(el, "mousewheel", function(e) { var factor = 8; if (e.wheelDeltaX !== undefined) { @@ -1578,11 +1605,11 @@ var location = "location" in e ? e.location : e.keyLocation; if (keyCode === 17 && location === 1) { if (pressedKeys[keyCode] == 1) ts = e.timeStamp; } else if (keyCode === 18 && hashId === 3 && location === 2) { - var dt = e.timestamp - ts; + var dt = e.timeStamp - ts; if (dt < 50) pressedKeys.altGr = true; } } } @@ -1650,19 +1677,20 @@ addListener(el, "keyup", function(e) { pressedKeys[e.keyCode] = null; }); if (!pressedKeys) { - pressedKeys = Object.create(null); - addListener(window, "focus", function(e) { - pressedKeys = Object.create(null); - }); + resetPressedKeys(); + addListener(window, "focus", resetPressedKeys); } } }; +function resetPressedKeys(e) { + pressedKeys = Object.create(null); +} -if (window.postMessage && !useragent.isOldIE) { +if (typeof window == "object" && window.postMessage && !useragent.isOldIE) { var postMessageId = 1; exports.nextTick = function(callback, win) { win = win || window; var messageName = "zero-timeout-message-" + postMessageId; exports.addListener(win, "message", function listener(e) { @@ -1675,15 +1703,15 @@ win.postMessage(messageName, "*"); }; } -exports.nextFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - window.oRequestAnimationFrame; +exports.nextFrame = typeof window == "object" && (window.requestAnimationFrame + || window.mozRequestAnimationFrame + || window.webkitRequestAnimationFrame + || window.msRequestAnimationFrame + || window.oRequestAnimationFrame); if (exports.nextFrame) exports.nextFrame = exports.nextFrame.bind(window); else exports.nextFrame = function(callback) { @@ -1742,24 +1770,28 @@ copy[i] = array[i]; } return copy; }; -exports.deepCopy = function (obj) { +exports.deepCopy = function deepCopy(obj) { if (typeof obj !== "object" || !obj) return obj; + var copy; + if (Array.isArray(obj)) { + copy = []; + for (var key = 0; key < obj.length; key++) { + copy[key] = deepCopy(obj[key]); + } + return copy; + } var cons = obj.constructor; if (cons === RegExp) return obj; - var copy = cons(); + copy = cons(); for (var key in obj) { - if (typeof obj[key] === "object") { - copy[key] = exports.deepCopy(obj[key]); - } else { - copy[key] = obj[key]; - } + copy[key] = deepCopy(obj[key]); } return copy; }; exports.arrayToMap = function(arr) { @@ -1920,18 +1952,24 @@ isFocused = true; host.onFocus(e); resetSelection(); }); this.focus = function() { + if (tempStyle) return text.focus(); + var top = text.style.top; text.style.position = "fixed"; text.style.top = "-1000px"; text.focus(); setTimeout(function() { text.style.position = ""; + if (text.style.top == "-1000px") + text.style.top = top; }, 0); }; - this.blur = function() { text.blur(); }; + this.blur = function() { + text.blur(); + }; this.isFocused = function() { return isFocused; }; var syncSelection = lang.delayedCall(function() { isFocused && resetSelection(isSelectionEmpty); @@ -2132,11 +2170,11 @@ var onPaste = function(e) { var data = handleClipboardData(e); if (typeof data == "string") { if (data) - host.onPaste(data); + host.onPaste(data, e); if (useragent.isIE) setTimeout(resetSelection); event.preventDefault(e); } else { @@ -2298,11 +2336,11 @@ }; this.onContextMenuClose = onContextMenuClose; var closeTimeout; function onContextMenuClose() { - clearTimeout(closeTimeout) + clearTimeout(closeTimeout); closeTimeout = setTimeout(function () { if (tempStyle) { text.style.cssText = tempStyle; tempStyle = ''; } @@ -2340,10 +2378,11 @@ editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler)); editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler)); editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler)); editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler)); editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler)); + editor.setDefaultHandler("touchmove", this.onTouchMove.bind(mouseHandler)); var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd", "selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"]; exports.forEach(function(x) { @@ -2541,11 +2580,24 @@ this.$lastScrollTime = t; editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); return ev.stop(); } }; + + this.onTouchMove = function (ev) { + var t = ev.domEvent.timeStamp; + var dt = t - (this.$lastScrollTime || 0); + var editor = this.editor; + var isScrolable = editor.renderer.isScrollableBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + if (isScrolable || dt < 200) { + this.$lastScrollTime = t; + editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + return ev.stop(); + } + }; + }).call(DefaultHandlers.prototype); exports.DefaultHandlers = DefaultHandlers; function calcDistance(ax, ay, bx, by) { @@ -3535,11 +3587,11 @@ var AppConfig = require("./lib/app_config").AppConfig; module.exports = exports = new AppConfig(); var global = (function() { - return this; + return this || typeof window != "undefined" && window; })(); var options = { packaged: false, workerPath: null, @@ -3727,10 +3779,11 @@ event.addListener(editor.renderer.scrollBarV.element, "mousedown", focusEditor); event.addListener(editor.renderer.scrollBarH.element, "mousedown", focusEditor); } } event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); + event.addTouchMoveListener(editor.container, this.onTouchMove.bind(this, "touchmove")); var gutterEl = editor.renderer.$gutter; event.addListener(gutterEl, "mousedown", this.onMouseEvent.bind(this, "guttermousedown")); event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick")); event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick")); @@ -3778,10 +3831,18 @@ mouseEvent.wheelX = e.wheelX; mouseEvent.wheelY = e.wheelY; this.editor._emit(name, mouseEvent); }; + + this.onTouchMove = function (name, e) { + var mouseEvent = new MouseEvent(e, this.editor); + mouseEvent.speed = 1;//this.$scrollSpeed * 2; + mouseEvent.wheelX = e.wheelX; + mouseEvent.wheelY = e.wheelY; + this.editor._emit(name, mouseEvent); + }; this.setState = function(state) { this.state = state; }; @@ -4849,11 +4910,11 @@ if (data.start == undefined) { if (this.rangeList) { this.toSingleRange(data[0]); for (var i = data.length; i--; ) { var r = Range.fromPoints(data[i].start, data[i].end); - if (data.isBackwards) + if (data[i].isBackwards) r.cursor = r.start; this.addRange(r, true); } return; } else @@ -5564,10 +5625,13 @@ column += rowTokens[tokenIndex].value.length; } return column; }; + this.getCurrentTokenPosition = function() { + return {row: this.$row, column: this.getCurrentTokenColumn()}; + }; }).call(TokenIterator.prototype); exports.TokenIterator = TokenIterator; }); @@ -5923,10 +5987,75 @@ }).call(Mode.prototype); exports.Mode = Mode; }); +define("ace/apply_delta",["require","exports","module"], function(require, exports, module) { +"use strict"; + +function throwDeltaError(delta, errorText){ + console.log("Invalid Delta:", delta); + throw "Invalid Delta: " + errorText; +} + +function positionInDocument(docLines, position) { + return position.row >= 0 && position.row < docLines.length && + position.column >= 0 && position.column <= docLines[position.row].length; +} + +function validateDelta(docLines, delta) { + if (delta.action != "insert" && delta.action != "remove") + throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); + if (!(delta.lines instanceof Array)) + throwDeltaError(delta, "delta.lines must be an Array"); + if (!delta.start || !delta.end) + throwDeltaError(delta, "delta.start/end must be an present"); + var start = delta.start; + if (!positionInDocument(docLines, delta.start)) + throwDeltaError(delta, "delta.start must be contained in document"); + var end = delta.end; + if (delta.action == "remove" && !positionInDocument(docLines, end)) + throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); + var numRangeRows = end.row - start.row; + var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); + if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) + throwDeltaError(delta, "delta.range must match delta lines"); +} + +exports.applyDelta = function(docLines, delta, doNotValidate) { + + var row = delta.start.row; + var startColumn = delta.start.column; + var line = docLines[row] || ""; + switch (delta.action) { + case "insert": + var lines = delta.lines; + if (lines.length === 1) { + docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + } else { + var args = [row, 1].concat(delta.lines); + docLines.splice.apply(docLines, args); + docLines[row] = line.substring(0, startColumn) + docLines[row]; + docLines[row + delta.lines.length - 1] += line.substring(startColumn); + } + break; + case "remove": + var endColumn = delta.end.column; + var endRow = delta.end.row; + if (row === endRow) { + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); + } else { + docLines.splice( + row, endRow - row + 1, + line.substring(0, startColumn) + docLines[endRow].substring(endColumn) + ); + } + break; + } +} +}); + define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; @@ -5949,74 +6078,50 @@ }; this.getDocument = function() { return this.document; }; this.$insertRight = false; - this.onChange = function(e) { - var delta = e.data; - var range = delta.range; - - if (range.start.row == range.end.row && range.start.row != this.row) + this.onChange = function(delta) { + if (delta.start.row == delta.end.row && delta.start.row != this.row) return; - if (range.start.row > this.row) + if (delta.start.row > this.row) return; - - if (range.start.row == this.row && range.start.column > this.column) - return; - - var row = this.row; - var column = this.column; - var start = range.start; - var end = range.end; - - if (delta.action === "insertText") { - if (start.row === row && start.column <= column) { - if (start.column === column && this.$insertRight) { - } else if (start.row === end.row) { - column += end.column - start.column; - } else { - column -= start.column; - row += end.row - start.row; - } - } else if (start.row !== end.row && start.row < row) { - row += end.row - start.row; - } - } else if (delta.action === "insertLines") { - if (start.row === row && column === 0 && this.$insertRight) { - } - else if (start.row <= row) { - row += end.row - start.row; - } - } else if (delta.action === "removeText") { - if (start.row === row && start.column < column) { - if (end.column >= column) - column = start.column; - else - column = Math.max(0, column - (end.column - start.column)); - - } else if (start.row !== end.row && start.row < row) { - if (end.row === row) - column = Math.max(0, column - end.column) + start.column; - row -= (end.row - start.row); - } else if (end.row === row) { - row -= end.row - start.row; - column = Math.max(0, column - end.column) + start.column; - } - } else if (delta.action == "removeLines") { - if (start.row <= row) { - if (end.row <= row) - row -= end.row - start.row; - else { - row = start.row; - column = 0; - } - } - } - - this.setPosition(row, column, true); + + var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); }; + + function $pointsInOrder(point1, point2, equalPointsInOrder) { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); + } + + function $getTransformedPoint(delta, point, moveIfEqual) { + var deltaIsInsert = delta.action == "insert"; + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); + var deltaStart = delta.start; + var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range. + if ($pointsInOrder(point, deltaStart, moveIfEqual)) { + return { + row: point.row, + column: point.column + }; + } + if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }; + } + + return { + row: deltaStart.row, + column: deltaStart.column + }; + } this.setPosition = function(row, column, noClip) { var pos; if (noClip) { pos = { row: row, @@ -6072,51 +6177,53 @@ }).call(Anchor.prototype); }); -define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { +define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); +var applyDelta = require("./apply_delta").applyDelta; var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; -var Document = function(text) { - this.$lines = []; - if (text.length === 0) { +var Document = function(textOrLines) { + this.$lines = [""]; + if (textOrLines.length === 0) { this.$lines = [""]; - } else if (Array.isArray(text)) { - this._insertLines(0, text); + } else if (Array.isArray(textOrLines)) { + this.insertMergedLines({row: 0, column: 0}, textOrLines); } else { - this.insert({row: 0, column:0}, text); + this.insert({row: 0, column:0}, textOrLines); } }; (function() { oop.implement(this, EventEmitter); this.setValue = function(text) { - var len = this.getLength(); - this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insert({row: 0, column:0}, text); + var len = this.getLength() - 1; + this.remove(new Range(0, 0, len, this.getLine(len).length)); + this.insert({row: 0, column: 0}, text); }; this.getValue = function() { return this.getAllLines().join(this.getNewLineCharacter()); }; this.createAnchor = function(row, column) { return new Anchor(this, row, column); }; - if ("aaa".split(/a/).length === 0) + if ("aaa".split(/a/).length === 0) { this.$split = function(text) { return text.replace(/\r\n|\r/g, "\n").split("\n"); }; - else + } else { this.$split = function(text) { return text.split(/\r\n|\r|\n/); }; + } this.$detectNewLine = function(text) { var match = text.match(/^.*?(\r\n|\r|\n)/m); this.$autoNewLine = match ? match[1] : "\n"; @@ -6159,256 +6266,251 @@ }; this.getLength = function() { return this.$lines.length; }; this.getTextRange = function(range) { - if (range.start.row == range.end.row) { - return this.getLine(range.start.row) - .substring(range.start.column, range.end.column); + return this.getLinesForRange(range).join(this.getNewLineCharacter()); + }; + this.getLinesForRange = function(range) { + var lines; + if (range.start.row === range.end.row) { + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; + } else { + lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); } - var lines = this.getLines(range.start.row, range.end.row); - lines[0] = (lines[0] || "").substring(range.start.column); - var l = lines.length - 1; - if (range.end.row - range.start.row == l) - lines[l] = lines[l].substring(0, range.end.column); - return lines.join(this.getNewLineCharacter()); + return lines; }; - - this.$clipPosition = function(position) { - var length = this.getLength(); - if (position.row >= length) { - position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; - } else if (position.row < 0) - position.row = 0; - return position; + this.insertLines = function(row, lines) { + console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); + return this.insertFullLines(row, lines); }; + this.removeLines = function(firstRow, lastRow) { + console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); + return this.removeFullLines(firstRow, lastRow); + }; + this.insertNewLine = function(position) { + console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead."); + return this.insertMergedLines(position, ["", ""]); + }; this.insert = function(position, text) { - if (!text || text.length === 0) - return position; - - position = this.$clipPosition(position); if (this.getLength() <= 1) this.$detectNewLine(text); - - var lines = this.$split(text); - var firstLine = lines.splice(0, 1)[0]; - var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; - - position = this.insertInLine(position, firstLine); - if (lastLine !== null) { - position = this.insertNewLine(position); // terminate first line - position = this._insertLines(position.row, lines); - position = this.insertInLine(position, lastLine || ""); + + return this.insertMergedLines(position, this.$split(text)); + }; + this.insertInLine = function(position, text) { + var start = this.clippedPos(position.row, position.column); + var end = this.pos(position.row, position.column + text.length); + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: [text] + }, true); + + return this.clonePos(end); + }; + + this.clippedPos = function(row, column) { + var length = this.getLength(); + if (row === undefined) { + row = length; + } else if (row < 0) { + row = 0; + } else if (row >= length) { + row = length - 1; + column = undefined; } - return position; + var line = this.getLine(row); + if (column == undefined) + column = line.length; + column = Math.min(Math.max(column, 0), line.length); + return {row: row, column: column}; }; - this.insertLines = function(row, lines) { - if (row >= this.getLength()) - return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); - return this._insertLines(Math.max(row, 0), lines); + + this.clonePos = function(pos) { + return {row: pos.row, column: pos.column}; }; - this._insertLines = function(row, lines) { - if (lines.length == 0) - return {row: row, column: 0}; - while (lines.length > 20000) { - var end = this._insertLines(row, lines.slice(0, 20000)); - lines = lines.slice(20000); - row = end.row; + + this.pos = function(row, column) { + return {row: row, column: column}; + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length - 1).length; + } else { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); } - - var args = [row, 0]; - args.push.apply(args, lines); - this.$lines.splice.apply(this.$lines, args); - - var range = new Range(row, 0, row + lines.length, 0); - var delta = { - action: "insertLines", - range: range, - lines: lines - }; - this._signal("change", { data: delta }); - return range.end; + return position; }; - this.insertNewLine = function(position) { - position = this.$clipPosition(position); - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column); - this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); - + this.insertFullLines = function(row, lines) { + row = Math.min(Math.max(row, 0), this.getLength()); + var column = 0; + if (row < this.getLength()) { + lines = lines.concat([""]); + column = 0; + } else { + lines = [""].concat(lines); + row--; + column = this.$lines[row].length; + } + this.insertMergedLines({row: row, column: column}, lines); + }; + this.insertMergedLines = function(position, lines) { + var start = this.clippedPos(position.row, position.column); var end = { - row : position.row + 1, - column : 0 + row: start.row + lines.length - 1, + column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: this.getNewLineCharacter() - }; - this._signal("change", { data: delta }); - - return end; + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: lines + }); + + return this.clonePos(end); }; - this.insertInLine = function(position, text) { - if (text.length == 0) - return position; - - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); - - var end = { - row : position.row, - column : position.column + text.length - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: text - }; - this._signal("change", { data: delta }); - - return end; - }; this.remove = function(range) { - if (!(range instanceof Range)) - range = Range.fromPoints(range.start, range.end); - range.start = this.$clipPosition(range.start); - range.end = this.$clipPosition(range.end); - - if (range.isEmpty()) - return range.start; - - var firstRow = range.start.row; - var lastRow = range.end.row; - - if (range.isMultiLine()) { - var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; - var lastFullRow = lastRow - 1; - - if (range.end.column > 0) - this.removeInLine(lastRow, 0, range.end.column); - - if (lastFullRow >= firstFullRow) - this._removeLines(firstFullRow, lastFullRow); - - if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); - this.removeNewLine(range.start.row); - } - } - else { - this.removeInLine(firstRow, range.start.column, range.end.column); - } - return range.start; + var start = this.clippedPos(range.start.row, range.start.column); + var end = this.clippedPos(range.end.row, range.end.column); + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }); + return this.clonePos(start); }; this.removeInLine = function(row, startColumn, endColumn) { - if (startColumn == endColumn) - return; - - var range = new Range(row, startColumn, row, endColumn); - var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); - this.$lines.splice(row, 1, newLine); - - var delta = { - action: "removeText", - range: range, - text: removed - }; - this._signal("change", { data: delta }); - return range.start; + var start = this.clippedPos(row, startColumn); + var end = this.clippedPos(row, endColumn); + + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }, true); + + return this.clonePos(start); }; - this.removeLines = function(firstRow, lastRow) { - if (firstRow < 0 || lastRow >= this.getLength()) - return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); - return this._removeLines(firstRow, lastRow); + this.removeFullLines = function(firstRow, lastRow) { + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + this.applyDelta({ + start: range.start, + end: range.end, + action: "remove", + lines: this.getLinesForRange(range) + }); + return deletedLines; }; - - this._removeLines = function(firstRow, lastRow) { - var range = new Range(firstRow, 0, lastRow + 1, 0); - var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); - - var delta = { - action: "removeLines", - range: range, - nl: this.getNewLineCharacter(), - lines: removed - }; - this._signal("change", { data: delta }); - return removed; - }; this.removeNewLine = function(row) { - var firstLine = this.getLine(row); - var secondLine = this.getLine(row+1); - - var range = new Range(row, firstLine.length, row+1, 0); - var line = firstLine + secondLine; - - this.$lines.splice(row, 2, line); - - var delta = { - action: "removeText", - range: range, - text: this.getNewLineCharacter() - }; - this._signal("change", { data: delta }); + if (row < this.getLength() - 1 && row >= 0) { + this.applyDelta({ + start: this.pos(row, this.getLine(row).length), + end: this.pos(row + 1, 0), + action: "remove", + lines: ["", ""] + }); + } }; this.replace = function(range, text) { - if (!(range instanceof Range)) + if (!range instanceof Range) range = Range.fromPoints(range.start, range.end); - if (text.length == 0 && range.isEmpty()) + if (text.length === 0 && range.isEmpty()) return range.start; if (text == this.getTextRange(range)) return range.end; this.remove(range); + var end; if (text) { - var end = this.insert(range.start, text); + end = this.insert(range.start, text); } else { end = range.start; } - + return end; }; this.applyDeltas = function(deltas) { for (var i=0; i<deltas.length; i++) { - var delta = deltas[i]; - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this.insertLines(range.start.row, delta.lines); - else if (delta.action == "insertText") - this.insert(range.start, delta.text); - else if (delta.action == "removeLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "removeText") - this.remove(range); + this.applyDelta(deltas[i]); } }; this.revertDeltas = function(deltas) { for (var i=deltas.length-1; i>=0; i--) { - var delta = deltas[i]; - - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "insertText") - this.remove(range); - else if (delta.action == "removeLines") - this._insertLines(range.start.row, delta.lines); - else if (delta.action == "removeText") - this.insert(range.start, delta.text); + this.revertDelta(deltas[i]); } }; + this.applyDelta = function(delta, doNotValidate) { + var isInsert = delta.action == "insert"; + if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] + : !Range.comparePoints(delta.start, delta.end)) { + return; + } + + if (isInsert && delta.lines.length > 20000) + this.$splitAndapplyLargeDelta(delta, 20000); + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", delta); + }; + + this.$splitAndapplyLargeDelta = function(delta, MAX) { + var lines = delta.lines; + var l = lines.length; + var row = delta.start.row; + var column = delta.start.column; + var from = 0, to = 0; + do { + from = to; + to += MAX - 1; + var chunk = lines.slice(from, to); + if (to > l) { + delta.lines = chunk; + delta.start.row = row + from; + delta.start.column = column; + break; + } + chunk.push(""); + this.applyDelta({ + start: this.pos(row + from, column), + end: this.pos(row + to, column = 0), + action: delta.action, + lines: chunk + }, true); + } while(true); + }; + this.revertDelta = function(delta) { + this.applyDelta({ + start: this.clonePos(delta.start), + end: this.clonePos(delta.end), + action: (delta.action == "insert" ? "remove" : "insert"), + lines: delta.lines.slice() + }); + }; this.indexToPosition = function(index, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; for (var i = startRow || 0, l = lines.length; i < l; i++) { index -= lines[i].length + newlineLength; @@ -6454,15 +6556,14 @@ var workerStart = new Date(); var currentLine = self.currentLine; var endLine = -1; var doc = self.doc; + var startLine = currentLine; while (self.lines[currentLine]) currentLine++; - - var startLine = currentLine; - + var len = doc.getLength(); var processedLines = 0; self.running = false; while (currentLine < len) { self.$tokenizeRow(currentLine); @@ -6520,17 +6621,16 @@ if (!this.running) this.running = setTimeout(this.$worker, 700); } this.$updateOnChange = function(delta) { - var range = delta.range; - var startRow = range.start.row; - var len = range.end.row - startRow; + var startRow = delta.start.row; + var len = delta.end.row - startRow; if (len === 0) { this.lines[startRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "remove") { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { var args = Array(len + 1); args.unshift(startRow, 1); @@ -6998,18 +7098,17 @@ return; this.session.removeListener('change', this.onChange); this.session = null; }; - this.$onChange = function(e) { - var changeRange = e.data.range; - if (e.data.action[0] == "i"){ - var start = changeRange.start; - var end = changeRange.end; + this.$onChange = function(delta) { + if (delta.action == "insert"){ + var start = delta.start; + var end = delta.end; } else { - var end = changeRange.start; - var start = changeRange.end; + var end = delta.start; + var start = delta.end; } var startRow = start.row; var endRow = end.row; var lineDif = endRow - startRow; @@ -7868,19 +7967,17 @@ this.addFold("...", range); } } }; - this.updateFoldWidgets = function(e) { - var delta = e.data; - var range = delta.range; - var firstRow = range.start.row; - var len = range.end.row - firstRow; + this.updateFoldWidgets = function(delta) { + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; if (len === 0) { this.foldWidgets[firstRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == 'remove') { this.foldWidgets.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); args.unshift(firstRow, 1); this.foldWidgets.splice.apply(this.foldWidgets, args); @@ -7986,11 +8083,11 @@ if (!typeRe){ typeRe = new RegExp( "(\\.?" + token.type.replace(".", "\\.").replace("rparen", ".paren") - .replace(/\b(?:end|start|begin)\b/, "") + .replace(/\b(?:end)\b/, "(?:start|begin|end)") + ")+" ); } var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2; var value = token.value; @@ -8038,11 +8135,11 @@ if (!typeRe){ typeRe = new RegExp( "(\\.?" + token.type.replace(".", "\\.").replace("lparen", ".paren") - .replace(/\b(?:end|start|begin)\b/, "") + .replace(/\b(?:start|begin)\b/, "(?:start|begin|end)") + ")+" ); } var valueIndex = position.column - iterator.getCurrentTokenColumn(); @@ -8104,11 +8201,11 @@ this.$undoSelect = true; this.$foldData = []; this.$foldData.toString = function() { return this.join("\n"); - } + }; this.on("changeFold", this.onChangeFold.bind(this)); this.$onChange = this.onChange.bind(this); if (typeof text != "object" || !text.getLine) text = new Document(text); @@ -8185,17 +8282,16 @@ this.onChangeFold = function(e) { var fold = e.data; this.$resetRowCache(fold.start.row); }; - this.onChange = function(e) { - var delta = e.data; + this.onChange = function(delta) { this.$modified = true; - this.$resetRowCache(delta.range.start.row); + this.$resetRowCache(delta.start.row); - var removedFolds = this.$updateInternalDataOnChange(e); + var removedFolds = this.$updateInternalDataOnChange(delta); if (!this.$fromUndo && this.$undoManager && !delta.ignore) { this.$deltasDoc.push(delta); if (removedFolds && removedFolds.length != 0) { this.$deltasFold.push({ action: "removeFolds", @@ -8205,11 +8301,11 @@ this.$informUndoManager.schedule(); } this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta); - this._signal("change", e); + this._signal("change", delta); }; this.setValue = function(text) { this.doc.setValue(text); this.selection.moveTo(0, 0); @@ -8721,10 +8817,13 @@ return this.doc.insert(position, text); }; this.remove = function(range) { return this.doc.remove(range); }; + this.removeFullLines = function(firstRow, lastRow){ + return this.doc.removeFullLines(firstRow, lastRow); + }; this.undoChanges = function(deltas, dontSelect) { if (!deltas.length) return; this.$fromUndo = true; @@ -8773,43 +8872,40 @@ this.$undoSelect = enable; }; this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { function isInsert(delta) { - var insert = - delta.action === "insertText" || delta.action === "insertLines"; - return isUndo ? !insert : insert; + return isUndo ? delta.action !== "insert" : delta.action === "insert"; } var delta = deltas[0]; var range, point; var lastDeltaIsInsert = false; if (isInsert(delta)) { - range = Range.fromPoints(delta.range.start, delta.range.end); + range = Range.fromPoints(delta.start, delta.end); lastDeltaIsInsert = true; } else { - range = Range.fromPoints(delta.range.start, delta.range.start); + range = Range.fromPoints(delta.start, delta.start); lastDeltaIsInsert = false; } for (var i = 1; i < deltas.length; i++) { delta = deltas[i]; if (isInsert(delta)) { - point = delta.range.start; + point = delta.start; if (range.compare(point.row, point.column) == -1) { - range.setStart(delta.range.start); + range.setStart(point); } - point = delta.range.end; + point = delta.end; if (range.compare(point.row, point.column) == 1) { - range.setEnd(delta.range.end); + range.setEnd(point); } lastDeltaIsInsert = true; } else { - point = delta.range.start; + point = delta.start; if (range.compare(point.row, point.column) == -1) { - range = - Range.fromPoints(delta.range.start, delta.range.start); + range = Range.fromPoints(delta.start, delta.start); } lastDeltaIsInsert = false; } } if (lastUndoRange != null) { @@ -8873,11 +8969,11 @@ return toRange; }; this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) - this.insert({row: row, column:0}, indentString); + this.doc.insertInLine({row: row, column: 0}, indentString); }; this.outdentRows = function (range) { var rowRange = range.collapseRows(); var deleteRange = new Range(0, 0, 0, 0); var size = this.getTabSize(); @@ -8923,15 +9019,15 @@ x = x.clone(); x.start.row += diff; x.end.row += diff; return x; }); - + var lines = dir == 0 ? this.doc.getLines(firstRow, lastRow) - : this.doc.removeLines(firstRow, lastRow); - this.doc.insertLines(firstRow+diff, lines); + : this.doc.removeFullLines(firstRow, lastRow); + this.doc.insertFullLines(firstRow+diff, lines); folds.length && this.addFolds(folds); return diff; }; this.moveLinesUp = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, -1); @@ -9069,38 +9165,27 @@ min : this.$wrapLimitRange.min, max : this.$wrapLimitRange.max }; }; - this.$updateInternalDataOnChange = function(e) { + this.$updateInternalDataOnChange = function(delta) { var useWrapMode = this.$useWrapMode; - var len; - var action = e.data.action; - var firstRow = e.data.range.start.row; - var lastRow = e.data.range.end.row; - var start = e.data.range.start; - var end = e.data.range.end; + var action = delta.action; + var start = delta.start; + var end = delta.end; + var firstRow = start.row; + var lastRow = end.row; + var len = lastRow - firstRow; var removedFolds = null; - - if (action.indexOf("Lines") != -1) { - if (action == "insertLines") { - lastRow = firstRow + (e.data.lines.length); - } else { - lastRow = firstRow; - } - len = e.data.lines ? e.data.lines.length : lastRow - firstRow; - } else { - len = lastRow - firstRow; - } - + this.$updating = true; if (len != 0) { - if (action.indexOf("remove") != -1) { + if (action === "remove") { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; - removedFolds = this.getFoldsInRange(e.data.range); + removedFolds = this.getFoldsInRange(delta); this.removeFolds(removedFolds); var foldLine = this.getFoldLine(end.row); var idx = 0; if (foldLine) { @@ -9153,13 +9238,13 @@ foldLine.shiftRow(len); } } } } else { - len = Math.abs(e.data.range.start.column - e.data.range.end.column); - if (action.indexOf("remove") != -1) { - removedFolds = this.getFoldsInRange(e.data.range); + len = Math.abs(delta.start.column - delta.end.column); + if (action === "remove") { + removedFolds = this.getFoldsInRange(delta); this.removeFolds(removedFolds); len = -len; } var foldLine = this.getFoldLine(firstRow); @@ -9237,21 +9322,46 @@ SPACE = 10, TAB = 11, TAB_SPACE = 12; - this.$computeWrapSplits = function(tokens, wrapLimit) { + this.$computeWrapSplits = function(tokens, wrapLimit, tabSize) { if (tokens.length == 0) { return []; } var splits = []; var displayLength = tokens.length; var lastSplit = 0, lastDocSplit = 0; var isCode = this.$wrapAsCode; + var indentedSoftWrap = this.$indentedSoftWrap; + var maxIndent = wrapLimit <= Math.max(2 * tabSize, 8) + || indentedSoftWrap === false ? 0 : Math.floor(wrapLimit / 2); + + function getWrapIndent() { + var indentation = 0; + if (maxIndent === 0) + return indentation; + if (indentedSoftWrap) { + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (token == SPACE) + indentation += 1; + else if (token == TAB) + indentation += tabSize; + else if (token == TAB_SPACE) + continue; + else + break; + } + } + if (isCode && indentedSoftWrap !== false) + indentation += tabSize; + return Math.min(indentation, maxIndent); + } function addSplit(screenPos) { var displayed = tokens.slice(lastSplit, screenPos); var len = displayed.length; displayed.join(""). replace(/12/g, function() { @@ -9259,17 +9369,21 @@ }). replace(/2/g, function() { len -= 1; }); + if (!splits.length) { + indent = getWrapIndent(); + splits.indent = indent; + } lastDocSplit += len; splits.push(lastDocSplit); lastSplit = screenPos; } - - while (displayLength - lastSplit > wrapLimit) { - var split = lastSplit + wrapLimit; + var indent = 0; + while (displayLength - lastSplit > wrapLimit - indent) { + var split = lastSplit + wrapLimit - indent; if (tokens[split - 1] >= SPACE && tokens[split] >= SPACE) { addSplit(split); continue; } if (tokens[split] == PLACEHOLDER_START || tokens[split] == PLACEHOLDER_BODY) { @@ -9292,11 +9406,11 @@ break; // Breaks the while-loop. } addSplit(split); continue; } - var minSplit = Math.max(split - (isCode ? 10 : wrapLimit-(wrapLimit>>2)), lastSplit - 1); + var minSplit = Math.max(split - (wrapLimit -(wrapLimit>>2)), lastSplit - 1); while (split > minSplit && tokens[split] < PLACEHOLDER_START) { split --; } if (isCode) { while (split > minSplit && tokens[split] < PLACEHOLDER_START) { @@ -9315,11 +9429,11 @@ continue; } split = lastSplit + wrapLimit; if (tokens[split] == CHAR_EXT) split--; - addSplit(split); + addSplit(split - indent); } return splits; }; this.$getDisplayTokens = function(str, offset) { var arr = []; @@ -9391,10 +9505,20 @@ return 1; } else { return this.$wrapData[row].length + 1; } }; + + this.getRowWrapIndent = function(screenRow) { + if (this.$useWrapMode) { + var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); + var splits = this.$wrapData[pos.row]; + return splits.length && splits[0] < pos.column ? splits.indent : 0; + } else { + return 0; + } + } this.getScreenLastRowColumn = function(screenRow) { var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); return this.documentToScreenColumn(pos.row, pos.column); }; this.getDocumentLastRowColumn = function(docRow, docColumn) { @@ -9481,24 +9605,25 @@ }; } else { line = this.getLine(docRow); foldLine = null; } - + var wrapIndent = 0; if (this.$useWrapMode) { var splits = this.$wrapData[docRow]; if (splits) { var splitIndex = Math.floor(screenRow - row); column = splits[splitIndex]; if(splitIndex > 0 && splits.length) { + wrapIndent = splits.indent; docColumn = splits[splitIndex - 1] || splits[splits.length - 1]; line = line.substring(docColumn); } } } - docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; + docColumn += this.$getStringScreenWidth(line, screenColumn - wrapIndent)[1]; if (this.$useWrapMode && docColumn >= column) docColumn = column - 1; if (foldLine) return foldLine.idxToPosition(docColumn); @@ -9566,10 +9691,11 @@ foldStartRow = foldLine.start.row; } else { textLine = this.getLine(docRow).substring(0, docColumn); foldStartRow = docRow; } + var wrapIndent = 0; if (this.$useWrapMode) { var wrapRow = this.$wrapData[foldStartRow]; if (wrapRow) { var screenRowOffset = 0; while (textLine.length >= wrapRow[screenRowOffset]) { @@ -9577,16 +9703,17 @@ screenRowOffset++; } textLine = textLine.substring( wrapRow[screenRowOffset - 1] || 0, textLine.length ); + wrapIndent = screenRowOffset > 0 ? wrapRow.indent : 0; } } return { row: screenRow, - column: this.$getStringScreenWidth(textLine)[0] + column: wrapIndent + this.$getStringScreenWidth(textLine)[0] }; }; this.documentToScreenColumn = function(row, docColumn) { return this.documentToScreenPosition(row, docColumn).column; }; @@ -9727,10 +9854,11 @@ } } }, initialValue: "auto" }, + indentedSoftWrap: { initialValue: true }, firstLineNumber: { set: function() {this._signal("changeBreakpoint");}, initialValue: 1 }, useWorker: { @@ -10132,13 +10260,16 @@ } } } }; - this.bindKey = function(key, command, asDefault) { - if (typeof key == "object") + this.bindKey = function(key, command, position) { + if (typeof key == "object") { + if (position == undefined) + position = key.position; key = key[this.platform]; + } if (!key) return; if (typeof command == "function") return this.addCommand({exec: command, bindKey: key, name: command.name || key}); @@ -10155,15 +10286,19 @@ }, this); chain += " "; } var binding = this.parseKeys(keyPart); var id = KEY_MODS[binding.hashId] + binding.key; - this._addCommandToBinding(chain + id, command, asDefault); + this._addCommandToBinding(chain + id, command, position); }, this); }; - this._addCommandToBinding = function(keyId, command, asDefault) { + function getPosition(command) { + return typeof command == "object" && command.bindKey + && command.bindKey.position || 0; + } + this._addCommandToBinding = function(keyId, command, position) { var ckb = this.commandKeyBinding, i; if (!command) { delete ckb[keyId]; } else if (!ckb[keyId] || this.$singleCommand) { ckb[keyId] = command; @@ -10171,15 +10306,25 @@ if (!Array.isArray(ckb[keyId])) { ckb[keyId] = [ckb[keyId]]; } else if ((i = ckb[keyId].indexOf(command)) != -1) { ckb[keyId].splice(i, 1); } - - if (asDefault || command.isDefault) - ckb[keyId].unshift(command); - else - ckb[keyId].push(command); + + if (typeof position != "number") { + if (position || command.isDefault) + position = -100; + else + position = getPosition(command); + } + var commands = ckb[keyId]; + for (i = 0; i < commands.length; i++) { + var other = commands[i]; + var otherPos = getPosition(other); + if (otherPos > position) + break; + } + commands.splice(i, 0, command); } }; this.addCommands = function(commands) { commands && Object.keys(commands).forEach(function(name) { @@ -10261,14 +10406,22 @@ data.$keyChain = data.$keyChain || key; return {command: "null"}; } } - if (data.$keyChain && keyCode > 0) - data.$keyChain = ""; + if (data.$keyChain) { + if ((!hashId || hashId == 4) && keyString.length == 1) + data.$keyChain = data.$keyChain.slice(0, -key.length - 1); // wait for input + else if (hashId == -1 || keyCode > 0) + data.$keyChain = ""; // reset keyChain + } return {command: command}; }; + + this.getStatusText = function(editor, data) { + return data.$keyChain || ""; + }; }).call(HashHandler.prototype); exports.HashHandler = HashHandler; exports.MultiHashHandler = MultiHashHandler; @@ -10769,10 +10922,15 @@ name: "passKeysToBrowser", bindKey: bindKey(null, null), exec: function() {}, passEvent: true, readOnly: true +}, { + name: "copy", + exec: function(editor) { + }, + readOnly: true }, { name: "cut", exec: function(editor) { var range = editor.getSelectionRange(); @@ -10784,10 +10942,16 @@ } }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { + name: "paste", + exec: function(editor, args) { + editor.$handlePaste(args); + }, + scrollIntoView: "cursor" +}, { name: "removeline", bindKey: bindKey("Ctrl-D", "Command-D"), exec: function(editor) { editor.removeLines(); }, scrollIntoView: "cursor", multiSelectAction: "forEachLine" @@ -11162,24 +11326,27 @@ this.curOp = { command: commadEvent.command || {}, args: commadEvent.args, scrollTop: this.renderer.scrollTop }; - if (this.curOp.command.name) + if (this.curOp.command.name && this.curOp.command.scrollIntoView !== undefined) this.$blockScrolling++; }; this.endOperation = function(e) { if (this.curOp) { if (e && e.returnValue === false) return this.curOp = null; this._signal("beforeEndOperation"); var command = this.curOp.command; - if (command.name && this.$blockScrolling) + if (command.name && this.$blockScrolling > 0) this.$blockScrolling--; - if (command && command.scrollIntoView) { - switch (command.scrollIntoView) { + var scrollIntoView = command && command.scrollIntoView; + if (scrollIntoView) { + switch (scrollIntoView) { + case "center-animate": + scrollIntoView = "animate"; case "center": this.renderer.scrollCursorIntoView(null, 0.5); break; case "animate": case "cursor": @@ -11193,11 +11360,11 @@ } break; default: break; } - if (command.scrollIntoView == "animate") + if (scrollIntoView == "animate") this.renderer.animateScrolling(this.curOp.scrollTop); } this.prevOp = this.curOp; this.curOp = null; @@ -11257,10 +11424,12 @@ return this.keyBinding.getKeyboardHandler(); }; this.setSession = function(session) { if (this.session == session) return; + if (this.curOp) this.endOperation(); + this.curOp = {}; var oldSession = this.session; if (oldSession) { this.session.removeEventListener("change", this.$onDocumentChange); this.session.removeEventListener("changeMode", this.$onChangeMode); @@ -11356,10 +11525,12 @@ this._signal("changeSession", { session: session, oldSession: oldSession }); + this.curOp = null; + oldSession && oldSession._signal("changeEditor", {oldEditor: this}); session && session._signal("changeEditor", {editor: this}); }; this.getSession = function() { return this.session; @@ -11540,22 +11711,16 @@ }; this.$cursorChange = function() { this.renderer.updateCursor(); }; - this.onDocumentChange = function(e) { - var delta = e.data; - var range = delta.range; - var lastRow; + this.onDocumentChange = function(delta) { + var wrap = this.session.$useWrapMode; + var lastRow = (delta.start.row == delta.end.row ? delta.end.row : Infinity); + this.renderer.updateLines(delta.start.row, lastRow, wrap); - if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines") - lastRow = range.end.row; - else - lastRow = Infinity; - this.renderer.updateLines(range.start.row, lastRow, this.session.$useWrapMode); - - this._signal("change", e); + this._signal("change", delta); this.$cursorChange(); this.$updateHighlightActiveLine(); }; this.onTokenizerUpdate = function(e) { @@ -11716,17 +11881,20 @@ this.commands.exec("copy", this); }; this.onCut = function() { this.commands.exec("cut", this); }; - this.onPaste = function(text) { - if (this.$readOnly) - return; - - var e = {text: text}; + this.onPaste = function(text, event) { + var e = {text: text, event: event}; + this.commands.exec("paste", this, e); + }; + + this.$handlePaste = function(e) { + if (typeof e == "string") + e = {text: e}; this._signal("paste", e); - text = e.text; + var text = e.text; if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { this.insert(text); } else { var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; @@ -11740,11 +11908,10 @@ this.session.remove(range); this.session.insert(range.start, lines[i]); } } - this.renderer.scrollCursorIntoView(); }; this.execCommand = function(command, args) { return this.commands.exec(command, this, args); }; @@ -12183,19 +12350,11 @@ } } }; this.removeLines = function() { var rows = this.$getSelectedRows(); - var range; - if (rows.first === 0 || rows.last+1 < this.session.getLength()) - range = new Range(rows.first, 0, rows.last+1, 0); - else - range = new Range( - rows.first-1, this.session.getLine(rows.first-1).length, - rows.last, this.session.getLine(rows.last).length - ); - this.session.remove(range); + this.session.removeFullLines(rows.first, rows.last); this.clearSelection(); }; this.duplicateSelection = function() { var sel = this.selection; @@ -12898,10 +13057,11 @@ newLineMode: "session", useWorker: "session", useSoftTabs: "session", tabSize: "session", wrap: "session", + indentedSoftWrap: "session", foldStyle: "session", mode: "session" }); exports.Editor = Editor; @@ -12913,46 +13073,43 @@ this.reset(); }; (function() { this.execute = function(options) { - var deltas = options.args[0]; + var deltaSets = options.args[0]; this.$doc = options.args[1]; if (options.merge && this.hasUndo()){ this.dirtyCounter--; - deltas = this.$undoStack.pop().concat(deltas); + deltaSets = this.$undoStack.pop().concat(deltaSets); } - this.$undoStack.push(deltas); + this.$undoStack.push(deltaSets); this.$redoStack = []; - if (this.dirtyCounter < 0) { this.dirtyCounter = NaN; } this.dirtyCounter++; }; this.undo = function(dontSelect) { - var deltas = this.$undoStack.pop(); + var deltaSets = this.$undoStack.pop(); var undoSelectionRange = null; - if (deltas) { - undoSelectionRange = - this.$doc.undoChanges(deltas, dontSelect); - this.$redoStack.push(deltas); + if (deltaSets) { + undoSelectionRange = this.$doc.undoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$redoStack.push(deltaSets); this.dirtyCounter--; } return undoSelectionRange; }; this.redo = function(dontSelect) { - var deltas = this.$redoStack.pop(); + var deltaSets = this.$redoStack.pop(); var redoSelectionRange = null; - if (deltas) { + if (deltaSets) { redoSelectionRange = - this.$doc.redoChanges(deltas, dontSelect); - this.$undoStack.push(deltas); + this.$doc.redoChanges(this.$deserializeDeltas(deltaSets), dontSelect); + this.$undoStack.push(deltaSets); this.dirtyCounter++; } - return redoSelectionRange; }; this.reset = function() { this.$undoStack = []; this.$redoStack = []; @@ -12968,11 +13125,52 @@ this.dirtyCounter = 0; }; this.isClean = function() { return this.dirtyCounter === 0; }; - + this.$serializeDeltas = function(deltaSets) { + return cloneDeltaSetsObj(deltaSets, $serializeDelta); + }; + this.$deserializeDeltas = function(deltaSets) { + return cloneDeltaSetsObj(deltaSets, $deserializeDelta); + }; + + function $serializeDelta(delta){ + return { + action: delta.action, + start: delta.start, + end: delta.end, + lines: delta.lines.length == 1 ? null : delta.lines, + text: delta.lines.length == 1 ? delta.lines[0] : null, + }; + } + + function $deserializeDelta(delta) { + return { + action: delta.action, + start: delta.start, + end: delta.end, + lines: delta.lines || [delta.text] + }; + } + + function cloneDeltaSetsObj(deltaSets_old, fnGetModifiedDelta) { + var deltaSets_new = new Array(deltaSets_old.length); + for (var i = 0; i < deltaSets_old.length; i++) { + var deltaSet_old = deltaSets_old[i]; + var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)}; + + for (var j = 0; j < deltaSet_old.deltas.length; j++) { + var delta_old = deltaSet_old.deltas[j]; + deltaSet_new.deltas[j] = fnGetModifiedDelta(delta_old); + } + + deltaSets_new[i] = deltaSet_new; + } + return deltaSets_new; + } + }).call(UndoManager.prototype); exports.UndoManager = UndoManager; }); @@ -13045,19 +13243,17 @@ else if (type == "info" && (!rowInfo.className)) rowInfo.className = " ace_info"; } }; - this.$updateAnnotations = function (e) { + this.$updateAnnotations = function (delta) { if (!this.$annotations.length) return; - var delta = e.data; - var range = delta.range; - var firstRow = range.start.row; - var len = range.end.row - firstRow; + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; if (len === 0) { - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == 'remove') { this.$annotations.splice(firstRow, len + 1, null); } else { var args = new Array(len + 1); args.unshift(firstRow, 1); this.$annotations.splice.apply(this.$annotations, args); @@ -13291,69 +13487,78 @@ if (marker.type == "text") this.drawTextMarker(html, range, marker.clazz, config); else this.drawMultiLineMarker(html, range, marker.clazz, config); } else { - this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); + this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config); } } this.element.innerHTML = html.join(""); }; this.$getTop = function(row, layerConfig) { return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; }; - this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { - var row = range.start.row; - var lineRange = new Range( - row, range.start.column, - row, this.session.getScreenLastRowColumn(row) - ); - this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle); - row = range.end.row; - lineRange = new Range(row, 0, row, range.end.column); - this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle); - - for (row = range.start.row + 1; row < range.end.row; row++) { - lineRange.start.row = row; - lineRange.end.row = row; - lineRange.end.column = this.session.getScreenLastRowColumn(row); - this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle); + function getBorderClass(tl, tr, br, bl) { + return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0); + } + this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { + var session = this.session; + var start = range.start.row; + var end = range.end.row; + var row = start; + var prev = 0; + var curr = 0; + var next = session.getScreenLastRowColumn(row); + var lineRange = new Range(row, range.start.column, row, curr); + for (; row <= end; row++) { + lineRange.start.row = lineRange.end.row = row; + lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row); + lineRange.end.column = next; + prev = curr; + curr = next; + next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column; + this.drawSingleLineMarker(stringBuilder, lineRange, + clazz + (row == start ? " ace_start" : "") + " ace_br" + + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end), + layerConfig, row == end ? 0 : 1, extraStyle); } }; this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { var padding = this.$padding; var height = config.lineHeight; var top = this.$getTop(range.start.row, config); var left = padding + range.start.column * config.characterWidth; extraStyle = extraStyle || ""; stringBuilder.push( - "<div class='", clazz, " ace_start' style='", + "<div class='", clazz, " ace_br1 ace_start' style='", "height:", height, "px;", "right:0;", "top:", top, "px;", "left:", left, "px;", extraStyle, "'></div>" ); top = this.$getTop(range.end.row, config); var width = range.end.column * config.characterWidth; stringBuilder.push( - "<div class='", clazz, "' style='", + "<div class='", clazz, " ace_br12' style='", "height:", height, "px;", "width:", width, "px;", "top:", top, "px;", "left:", padding, "px;", extraStyle, "'></div>" ); height = (range.end.row - range.start.row - 1) * config.lineHeight; - if (height < 0) + if (height <= 0) return; top = this.$getTop(range.start.row + 1, config); + + var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8); stringBuilder.push( - "<div class='", clazz, "' style='", + "<div class='", clazz, (radiusClass ? " ace_br" + radiusClass : ""), "' style='", "height:", height, "px;", "right:0;", "top:", top, "px;", "left:", padding, "px;", extraStyle, "'></div>" ); @@ -13428,11 +13633,11 @@ this.EOF_CHAR = "\xB6"; this.EOL_CHAR_LF = "\xAC"; this.EOL_CHAR_CRLF = "\xa4"; this.EOL_CHAR = this.EOL_CHAR_LF; - this.TAB_CHAR = "\u2192"; //"\u21E5"; + this.TAB_CHAR = "\u2014"; //"\u21E5"; this.SPACE_CHAR = "\xB7"; this.$padding = 0; this.$updateEolChar = function() { var EOL_CHAR = this.session.doc.getNewLineCharacter() == "\n" @@ -13504,15 +13709,14 @@ this.tabSize = tabSize; var tabStr = this.$tabStrings = [0]; for (var i = 1; i < tabSize + 1; i++) { if (this.showInvisibles) { tabStr.push("<span class='ace_invisible ace_invisible_tab'>" - + this.TAB_CHAR - + lang.stringRepeat("\xa0", i - 1) + + lang.stringRepeat(this.TAB_CHAR, i) + "</span>"); } else { - tabStr.push(lang.stringRepeat("\xa0", i)); + tabStr.push(lang.stringRepeat(" ", i)); } } if (this.displayIndentGuides) { this.$indentGuideRe = /\s\S| \t|\t |\s$/; var className = "ace_indent-guide"; @@ -13521,13 +13725,13 @@ if (this.showInvisibles) { className += " ace_invisible"; spaceClass = " ace_invisible_space"; tabClass = " ace_invisible_tab"; var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); - var tabContent = this.TAB_CHAR + lang.stringRepeat("\xa0", this.tabSize - 1); + var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize); } else{ - var spaceContent = lang.stringRepeat("\xa0", this.tabSize); + var spaceContent = lang.stringRepeat(" ", this.tabSize); var tabContent = spaceContent; } this.$tabStrings[" "] = "<span class='" + className + spaceClass + "'>" + spaceContent + "</span>"; this.$tabStrings["\t"] = "<span class='" + className + tabClass + "'>" + tabContent + "</span>"; @@ -13692,20 +13896,22 @@ "lparen": true }; this.$renderToken = function(stringBuilder, screenColumn, token, value) { var self = this; - var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; + var replaceReg = /\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; var replaceFunc = function(c, a, b, tabIdx, idx4) { if (a) { - return self.showInvisibles ? - "<span class='ace_invisible ace_invisible_space'>" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "</span>" : - lang.stringRepeat("\xa0", c.length); + return self.showInvisibles + ? "<span class='ace_invisible ace_invisible_space'>" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "</span>" + : c; } else if (c == "&") { return "&#38;"; } else if (c == "<") { return "&#60;"; + } else if (c == ">") { + return "&#62;"; } else if (c == "\t") { var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); screenColumn += tabSize - 1; return self.$tabStrings[tabSize]; } else if (c == "\u3000") { @@ -13789,10 +13995,12 @@ "<div class='ace_line' style='height:", this.config.lineHeight, "px'>" ); } + stringBuilder.push(lang.stringRepeat("\xa0", splits.indent)); + split ++; screenColumn = 0; splitChars = splits[split] || Number.MAX_VALUE; } if (value.length != 0) { @@ -13939,29 +14147,31 @@ define("ace/layer/cursor",["require","exports","module","ace/lib/dom"], function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); -var IE8; +var isIE8; var Cursor = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_cursor-layer"; parentEl.appendChild(this.element); - if (IE8 === undefined) - IE8 = "opacity" in this.element; + if (isIE8 === undefined) + isIE8 = !("opacity" in this.element.style); this.isVisible = false; this.isBlinking = true; this.blinkInterval = 1000; this.smoothBlinking = false; this.cursors = []; this.cursor = this.addCursor(); dom.addCssClass(this.element, "ace_hidden-cursors"); - this.$updateCursors = this.$updateVisibility.bind(this); + this.$updateCursors = (isIE8 + ? this.$updateVisibility + : this.$updateOpacity).bind(this); }; (function() { this.$updateVisibility = function(val) { @@ -13998,17 +14208,15 @@ this.restartTimer(); } }; this.setSmoothBlinking = function(smoothBlinking) { - if (smoothBlinking != this.smoothBlinking && !IE8) { + if (smoothBlinking != this.smoothBlinking && !isIE8) { this.smoothBlinking = smoothBlinking; dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking); this.$updateCursors(true); - this.$updateCursors = (smoothBlinking - ? this.$updateOpacity - : this.$updateVisibility).bind(this); + this.$updateCursors = (this.$updateOpacity).bind(this); this.restartTimer(); } }; this.addCursor = function() { @@ -14396,13 +14604,13 @@ }; this.setPolling = function(val) { if (val) { this.$pollSizeChanges(); - } else { - if (this.$pollSizeChangesTimer) - this.$pollSizeChangesTimer; + } else if (this.$pollSizeChangesTimer) { + clearInterval(this.$pollSizeChangesTimer); + this.$pollSizeChangesTimer = 0; } }; this.$measureSizes = function() { if (CHAR_COUNT === 50) { @@ -14596,10 +14804,11 @@ text-indent: -1em;\ -ms-user-select: text;\ -moz-user-select: text;\ -webkit-user-select: text;\ user-select: text;\ +white-space: pre!important;\ }\ .ace_text-input.ace_composition {\ background: inherit;\ color: inherit;\ z-index: 1000;\ @@ -14639,11 +14848,12 @@ z-index: 4;\ position: absolute;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ -border-left: 2px solid\ +border-left: 2px solid;\ +transform: translatez(0);\ }\ .ace_slim-cursors .ace_cursor {\ border-left-width: 1px;\ }\ .ace_overwrite-cursors .ace_cursor {\ @@ -14820,13 +15030,28 @@ .ace_highlight-marker {\ background-color: rgba(255, 255, 0,0.2);\ position: absolute;\ z-index: 8;\ }\ +.ace_br1 {border-top-left-radius : 3px;}\ +.ace_br2 {border-top-right-radius : 3px;}\ +.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}\ +.ace_br4 {border-bottom-right-radius: 3px;}\ +.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}\ +.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}\ +.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}\ +.ace_br8 {border-bottom-left-radius : 3px;}\ +.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}\ +.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}\ +.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ +.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\ "; -dom.importCssString(editorCss, "ace_editor"); +dom.importCssString(editorCss, "ace_editor.css"); var VirtualRenderer = function(container, theme) { var _self = this; this.container = container || dom.createElement("div"); @@ -15232,11 +15457,11 @@ }; this.getContainerElement = function() { return this.container; }; this.getMouseEventTarget = function() { - return this.content; + return this.scroller; }; this.getTextAreaContainer = function() { return this.container; }; this.$moveTextAreaToCursor = function() { @@ -15461,10 +15686,12 @@ var maxHeight = this.$maxLines * this.lineHeight; var desiredHeight = Math.max( (this.$minLines||1) * this.lineHeight, Math.min(maxHeight, height) ) + this.scrollMargin.v + (this.$extraHeight || 0); + if (this.$horizScroll) + desiredHeight += this.scrollBarH.getHeight(); var vScroll = height > maxHeight; if (desiredHeight != this.desiredHeight || this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { if (vScroll != this.$vScroll) { @@ -15480,48 +15707,49 @@ this._signal("autosize"); } }; this.$computeLayerConfig = function() { - if (this.$maxLines && this.lineHeight > 1) - this.$autosize(); - var session = this.session; var size = this.$size; var hideScrollbars = size.height <= 2 * this.lineHeight; var screenLines = this.session.getScreenLength(); var maxHeight = screenLines * this.lineHeight; - var offset = this.scrollTop % this.lineHeight; - var minHeight = size.scrollerHeight + this.lineHeight; - var longestLine = this.$getLongestLine(); var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || size.scrollerWidth - longestLine - 2 * this.$padding < 0); var hScrollChanged = this.$horizScroll !== horizScroll; if (hScrollChanged) { this.$horizScroll = horizScroll; this.scrollBarH.setVisible(horizScroll); } + var vScrollBefore = this.$vScroll; // autosize can change vscroll value in which case we need to update longestLine + if (this.$maxLines && this.lineHeight > 1) + this.$autosize(); + + var offset = this.scrollTop % this.lineHeight; + var minHeight = size.scrollerHeight + this.lineHeight; var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd : 0; maxHeight += scrollPastEnd; - this.session.setScrollTop(Math.max(-this.scrollMargin.top, - Math.min(this.scrollTop, maxHeight - size.scrollerHeight + this.scrollMargin.bottom))); + var sm = this.scrollMargin; + this.session.setScrollTop(Math.max(-sm.top, + Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom))); - this.session.setScrollLeft(Math.max(-this.scrollMargin.left, Math.min(this.scrollLeft, - longestLine + 2 * this.$padding - size.scrollerWidth + this.scrollMargin.right))); + this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft, + longestLine + 2 * this.$padding - size.scrollerWidth + sm.right))); var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || - size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop); - var vScrollChanged = this.$vScroll !== vScroll; + size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top); + var vScrollChanged = vScrollBefore !== vScroll; if (vScrollChanged) { this.$vScroll = vScroll; this.scrollBarV.setVisible(vScroll); } @@ -16201,23 +16429,26 @@ this.$doc = doc; this.call("setValue", [doc.getValue()]); doc.on("change", this.changeListener); }; - this.changeListener = function(e) { + this.changeListener = function(delta) { if (!this.deltaQueue) { - this.deltaQueue = [e.data]; + this.deltaQueue = []; setTimeout(this.$sendDeltaQueue, 0); - } else - this.deltaQueue.push(e.data); + } + if (delta.action == "insert") + this.deltaQueue.push(delta.start, delta.lines); + else + this.deltaQueue.push(delta.start, delta.end); }; this.$sendDeltaQueue = function() { var q = this.deltaQueue; if (!q) return; this.deltaQueue = null; - if (q.length > 20 && q.length > this.$doc.getLength() >> 1) { + if (q.length > 50 && q.length > this.$doc.getLength() >> 1) { this.call("setValue", [this.$doc.getValue()]); } else this.emit("change", {data: q}); }; @@ -16369,41 +16600,40 @@ this.othersActive = false; for (var i = 0; i < this.others.length; i++) { this.session.removeMarker(this.others[i].markerId); } }; - this.onUpdate = function(event) { - var delta = event.data; - var range = delta.range; + this.onUpdate = function(delta) { + var range = delta; if(range.start.row !== range.end.row) return; if(range.start.row !== this.pos.row) return; if (this.$updating) return; this.$updating = true; - var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column; + var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column; if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) { var distanceFromStart = range.start.column - this.pos.column; this.length += lengthDiff; if(!this.session.$fromUndo) { - if(delta.action === "insertText") { + if(delta.action === 'insert') { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; - this.doc.insert(newPos, delta.text); + this.doc.insertMergedLines(newPos, delta.lines); } - } else if(delta.action === "removeText") { + } else if(delta.action === 'remove') { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff)); } } - if(range.start.column === this.pos.column && delta.action === "insertText") { + if(range.start.column === this.pos.column && delta.action === 'insert') { setTimeout(function() { this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; var newPos = {row: other.row, column: other.column - lengthDiff}; @@ -16411,11 +16641,11 @@ newPos.column += lengthDiff; other.setPosition(newPos.row, newPos.column); } }.bind(this), 0); } - else if(range.start.column === this.pos.column && delta.action === "removeText") { + else if(range.start.column === this.pos.column && delta.action === 'remove') { setTimeout(function() { for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; if(other.row === range.start.row && range.start.column < other.column) { other.setPosition(other.row, other.column - lengthDiff); @@ -16523,19 +16753,19 @@ var screenCursor = screenAnchor; var selectionMode; if (editor.$mouseHandler.$enableJumpToDef) { if (ctrl && alt || accel && alt) - selectionMode = "add"; - else if (alt) + selectionMode = shift ? "block" : "add"; + else if (alt && editor.$blockSelectEnabled) selectionMode = "block"; } else { if (accel && !alt) { selectionMode = "add"; if (!isMultiSelect && shift) return; - } else if (alt) { + } else if (alt && editor.$blockSelectEnabled) { selectionMode = "block"; } } if (selectionMode && useragent.isMac && ev.ctrlKey) { @@ -16557,11 +16787,11 @@ editor.$blockScrolling++; editor.inVirtualSelectionMode = true; if (shift) { oldRange = null; - range = selection.ranges[0]; + range = selection.ranges[0] || range; editor.removeSelectionMarker(range); } editor.once("mouseup", function() { var tmpSel = selection.toOrientedRange(); @@ -16656,76 +16886,76 @@ exports.defaultCommands = [{ name: "addCursorAbove", exec: function(editor) { editor.selectMoreLines(-1); }, bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "addCursorBelow", exec: function(editor) { editor.selectMoreLines(1); }, bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "addCursorAboveSkipCurrent", exec: function(editor) { editor.selectMoreLines(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "addCursorBelowSkipCurrent", exec: function(editor) { editor.selectMoreLines(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "selectMoreBefore", exec: function(editor) { editor.selectMore(-1); }, bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "selectMoreAfter", exec: function(editor) { editor.selectMore(1); }, bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "selectNextBefore", exec: function(editor) { editor.selectMore(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "selectNextAfter", exec: function(editor) { editor.selectMore(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }, { name: "splitIntoLines", exec: function(editor) { editor.multiSelect.splitIntoLines(); }, bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, - readonly: true + readOnly: true }, { name: "alignCursors", exec: function(editor) { editor.alignCursors(); }, bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}, scrollIntoView: "cursor" }, { name: "findAll", exec: function(editor) { editor.findAll(); }, bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"}, scrollIntoView: "cursor", - readonly: true + readOnly: true }]; exports.multiSelectCommands = [{ name: "singleSelection", bindKey: "esc", exec: function(editor) { editor.exitMultiSelectMode(); }, scrollIntoView: "cursor", - readonly: true, + readOnly: true, isAvailable: function(editor) {return editor && editor.inMultiSelectMode} }]; var HashHandler = require("../keyboard/hash_handler").HashHandler; exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); @@ -17323,13 +17553,13 @@ } while (/[=:]/.test(line) && --fr > 0); if (fr < 0) fr = 0; if (lr >= max) lr = max - 1; } - var lines = this.session.doc.removeLines(fr, lr); + var lines = this.session.removeFullLines(fr, lr); lines = this.$reAlignText(lines, guessRange); - this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n"); + this.session.insert({row: fr, column: 0}, lines.join("\n") + "\n"); if (!guessRange) { range.start.column = 0; range.end.column = lines[lines.length - 1].length; } this.selection.setRange(range); @@ -17486,11 +17716,12 @@ function addAltCursorListeners(editor){ var el = editor.textInput.getElement(); var altCursor = false; event.addListener(el, "keydown", function(e) { - if (e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey)) { + var altDown = e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey); + if (editor.$blockSelectEnabled && altDown) { if (!altCursor) { editor.renderer.setMouseCursor("crosshair"); altCursor = true; } } else if (altCursor) { @@ -17522,10 +17753,16 @@ this.off("changeSession", this.$multiselectOnSessionChange); this.off("mousedown", onMouseDown); } }, value: true + }, + enableBlockSelect: { + set: function(val) { + this.$blockSelectEnabled = val; + }, + value: true } }); @@ -17718,11 +17955,10 @@ .ace-tm .ace_marker-layer .ace_selection {\ background: rgb(181, 213, 255);\ }\ .ace-tm.ace_multiselect .ace_selection.ace_start {\ box-shadow: 0 0 3px 0px white;\ -border-radius: 2px;\ }\ .ace-tm .ace_marker-layer .ace_step {\ background: rgb(252, 255, 0);\ }\ .ace-tm .ace_marker-layer .ace_stack {\ @@ -17834,21 +18070,19 @@ w.el.parentNode.removeChild(w.el); } }); }; - this.updateOnChange = function(e) { + this.updateOnChange = function(delta) { var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; - - var delta = e.data; - var range = delta.range; - var startRow = range.start.row; - var len = range.end.row - startRow; + + var startRow = delta.start.row; + var len = delta.end.row - startRow; if (len === 0) { - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == 'remove') { var removed = lineWidgets.splice(startRow + 1, len); removed.forEach(function(w) { w && this.removeLineWidget(w); }, this); this.$updateRows(); @@ -18234,10 +18468,10 @@ if (el && /input|textarea/i.test(el.tagName)) { var oldNode = el; value = oldNode.value; el = dom.createElement("pre"); oldNode.parentNode.replaceChild(el, oldNode); - } else { + } else if (el) { value = dom.getInnerText(el); el.innerHTML = ''; } var doc = exports.createEditSession(value); \ No newline at end of file