From 316bb55f17a325deb091834cd4a60bcda17fabd1 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 12:12:26 +0400 Subject: [PATCH 01/15] fix inserting long text --- lib/ace/document.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index 24d82cc3..14e04ff9 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -56,7 +56,7 @@ var Document = function(text) { // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. - if (text.length == 0) { + if (text.length === 0) { this.$lines = [""]; } else if (Array.isArray(text)) { this._insertLines(0, text); @@ -107,10 +107,10 @@ var Document = function(text) { **/ // check for IE split bug - 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 this.$split = function(text) { return text.split(/\r\n|\r|\n/); @@ -136,11 +136,11 @@ var Document = function(text) { case "unix": return "\n"; default: - return this.$autoNewLine; + return this.$autoNewLine || "\n"; } }; - this.$autoNewLine = "\n"; + this.$autoNewLine = ""; this.$newLineMode = "auto"; /** * [Sets the new line mode.]{: #Document.setNewLineMode.desc} @@ -311,9 +311,10 @@ var Document = function(text) { // apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) // to circumvent that we have to break huge inserts into smaller chunks here - if (lines.length > 0xFFFF) { - var end = this._insertLines(row, lines.slice(0xFFFF)); - lines = lines.slice(0, 0xFFFF); + while (lines.length > 0xF000) { + var end = this._insertLines(row, lines.slice(0, 0xF000)); + lines = lines.slice(0xF000); + row = end.row; } var args = [row, 0]; @@ -327,7 +328,7 @@ var Document = function(text) { lines: lines }; this._signal("change", { data: delta }); - return end || range.end; + return range.end; }; /** From f4d1dc7c13dd28d9bf5d8268e1d984e2768de72a Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 1 Nov 2013 00:28:01 +0400 Subject: [PATCH 02/15] create wrap data lazily --- lib/ace/edit_session.js | 44 ++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 8f772db7..cc7d72b0 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1556,10 +1556,7 @@ var EditSession = function(text, mode) { // If wrapMode is activaed, the wrapData array has to be initialized. if (useWrapMode) { var len = this.getLength(); - this.$wrapData = []; - for (var i = 0; i < len; i++) { - this.$wrapData.push([]); - } + this.$wrapData = Array(len); this.$updateWrapData(0, len - 1); } @@ -1719,16 +1716,10 @@ var EditSession = function(text, mode) { lastRow = firstRow; } else { - var args; - if (useWrapMode) { - args = [firstRow, 0]; - for (var i = 0; i < len; i++) args.push([]); - this.$wrapData.splice.apply(this.$wrapData, args); - } else { - args = Array(len); - args.unshift(firstRow, 0); - this.$rowLengthCache.splice.apply(this.$rowLengthCache, args); - } + var args = Array(len); + args.unshift(firstRow, 0); + var arr = useWrapMode ? this.$wrapData : this.$rowLengthCache + arr.splice.apply(arr, args); // If some new line is added inside of a foldLine, then split // the fold line up. @@ -1833,8 +1824,7 @@ var EditSession = function(text, mode) { lines[foldLine.end.row].length + 1 ); - wrapData[foldLine.start.row] - = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + wrapData[foldLine.start.row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); row = foldLine.end.row + 1; } } @@ -2023,9 +2013,6 @@ var EditSession = function(text, mode) { * The first position indicates the number of columns for `str` on screen.
* The second value contains the position of the document column that this function read until. * - * - * - * **/ this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { if (maxScreenColumn == 0) @@ -2326,14 +2313,16 @@ var EditSession = function(text, mode) { // Clamp textLine if in wrapMode. if (this.$useWrapMode) { var wrapRow = this.$wrapData[foldStartRow]; - var screenRowOffset = 0; - while (textLine.length >= wrapRow[screenRowOffset]) { - screenRow ++; - screenRowOffset++; + if (wrapRow) { + var screenRowOffset = 0; + while (textLine.length >= wrapRow[screenRowOffset]) { + screenRow ++; + screenRowOffset++; + } + textLine = textLine.substring( + wrapRow[screenRowOffset - 1] || 0, textLine.length + ); } - textLine = textLine.substring( - wrapRow[screenRowOffset - 1] || 0, textLine.length - ); } return { @@ -2387,7 +2376,8 @@ var EditSession = function(text, mode) { var foldStart = fold ? fold.start.row :Infinity; while (row < lastRow) { - screenRows += this.$wrapData[row].length + 1; + var splits = this.$wrapData[row]; + screenRows += splits ? splits.length + 1 : 1; row ++; if (row > foldStart) { row = fold.end.row+1; From f352165725fd75539dc6093d551de92c61faf7ac Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 12:30:30 +0400 Subject: [PATCH 03/15] move text measuring into separate module --- lib/ace/edit_session.js | 11 ++- lib/ace/layer/font_metrics.js | 158 ++++++++++++++++++++++++++++++++++ lib/ace/layer/text.js | 133 +++------------------------- lib/ace/virtual_renderer.js | 8 +- 4 files changed, 183 insertions(+), 127 deletions(-) create mode 100644 lib/ace/layer/font_metrics.js diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index cc7d72b0..e4b3d54c 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -2393,14 +2393,17 @@ var EditSession = function(text, mode) { return screenRows; }; - - // For every keystroke this gets called once per char in the whole doc!! - // Wouldn't hurt to make it a bit faster for c >= 0x1100 - + /** * @private * */ + this.$setFontMetrics = function(fm) { + // todo + } + + // For every keystroke this gets called once per char in the whole doc!! + // Wouldn't hurt to make it a bit faster for c >= 0x1100 function isFullWidth(c) { if (c < 0x1100) return false; diff --git a/lib/ace/layer/font_metrics.js b/lib/ace/layer/font_metrics.js new file mode 100644 index 00000000..45fa44cb --- /dev/null +++ b/lib/ace/layer/font_metrics.js @@ -0,0 +1,158 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var CHAR_COUNT = 0; + +var FontMetrics = exports.FontMetrics = function(parentEl, interval) { + this.el = dom.createElement("div"); + this.$setMeasureNodeStyles(this.el.style, true); + + this.$main = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$main.style); + + this.$measureNode = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$measureNode.style); + + + this.el.appendChild(this.$main); + this.el.appendChild(this.$measureNode); + parentEl.appendChild(this.el); + + if (!CHAR_COUNT) + this.$testFractionalRect(); + this.$measureNode.textContent = lang.stringRepeat("X", CHAR_COUNT); + + this.$characterSize = {width: 0, height: 0}; + this.checkForSizeChanges(); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.$characterSize = {width: 0, height: 0}; + + this.$testFractionalRect = function() { + var el = dom.createElement("div"); + this.$setMeasureNodeStyles(el.style); + el.style.width = "0.2px"; + document.documentElement.appendChild(el); + var w = el.getBoundingClientRect().width; + if (w > 0 && w < 1) + CHAR_COUNT = 1; + else + CHAR_COUNT = 100; + el.parentNode.removeChild(el); + }; + + this.$setMeasureNodeStyles = function(style, isRoot) { + style.width = style.height = "auto"; + style.left = style.top = "-100px"; + style.visibility = "hidden"; + style.position = "fixed"; + style.whiteSpace = "pre"; + style.font = "inherit"; + style.overflow = isRoot ? "hidden" : "visible"; + }; + + this.checkForSizeChanges = function() { + var size = this.$measureSizes(); + if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { + this.$measureNode.style.fontWeight = "bold"; + var boldSize = this.$measureSizes(); + this.$measureNode.style.fontWeight = ""; + this.$characterSize = size; + this.charSizes = Object.create(null); + this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; + this._emit("changeCharacterSize", {data: size}); + } + }; + + this.$pollSizeChanges = function() { + if (this.$pollSizeChangesTimer) + return this.$pollSizeChangesTimer; + var self = this; + return this.$pollSizeChangesTimer = setInterval(function() { + self.checkForSizeChanges(); + }, 500); + }; + + this.setPolling = function(val) { + if (val) { + this.$pollSizeChanges(); + } else { + if (this.$pollSizeChangesTimer) + this.$pollSizeChangesTimer; + } + }; + + this.$measureSizes = function() { + var rect = this.$measureNode.getBoundingClientRect(); + var size = { + height: rect.height, + width: rect.width / CHAR_COUNT + }; + // Size and width can be null if the editor is not visible or + // detached from the document + if (size.width === 0 || size.height === 0) + return null; + return size; + }; + + this.$measureCharWidth = function(ch) { + this.$main.textContent = lang.stringRepeat(ch, CHAR_COUNT); + var rect = this.$main.getBoundingClientRect(); + return rect.width / CHAR_COUNT; + }; + + this.getCharacterWidth = function(ch) { + var w = this.charSizes[ch]; + if (w === undefined) { + this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; + } + return w; + }; + + this.destroy = function() { + clearInterval(this.$pollSizeChangesTimer); + if (this.el && this.el.parentNode) + this.el.parentNode.removeChild(this.el); + }; + +}).call(FontMetrics.prototype); + +}); diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 4290233d..50b00196 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -41,10 +41,6 @@ var Text = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_text-layer"; parentEl.appendChild(this.element); - - this.$characterSize = {width: 0, height: 0}; - this.checkForSizeChanges(); - this.$pollSizeChanges(); }; (function() { @@ -63,132 +59,27 @@ var Text = function(parentEl) { }; this.getLineHeight = function() { - return this.$characterSize.height || 0; + return this.$fontMetrics.$characterSize.height || 0; }; this.getCharacterWidth = function() { - return this.$characterSize.width || 0; + return this.$fontMetrics.$characterSize.width || 0; }; + + this.$setFontMetrics = function(measure) { + this.$fontMetrics = measure; + this.$fontMetrics.on("changeCharacterSize", function(e) { + this._signal("changeCharacterSize", e); + }.bind(this)); + this.$pollSizeChanges(); + } this.checkForSizeChanges = function() { - var size = this.$measureSizes(); - if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { - this.$measureNode.style.fontWeight = "bold"; - var boldSize = this.$measureSizes(); - this.$measureNode.style.fontWeight = ""; - this.$characterSize = size; - this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; - this._emit("changeCharacterSize", {data: size}); - } + this.$fontMetrics.checkForSizeChanges(); }; - this.$pollSizeChanges = function() { - var self = this; - this.$pollSizeChangesTimer = setInterval(function() { - self.checkForSizeChanges(); - }, 500); + return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); }; - - this.$fontStyles = { - fontFamily : 1, - fontSize : 1, - fontWeight : 1, - fontStyle : 1, - lineHeight : 1 - }; - - this.$measureSizes = useragent.isIE || useragent.isOldGecko ? function() { - var n = 1000; - if (!this.$measureNode) { - var measureNode = this.$measureNode = dom.createElement("div"); - var style = measureNode.style; - - style.width = style.height = "auto"; - style.left = style.top = (-n * 40) + "px"; - - style.visibility = "hidden"; - style.position = "fixed"; - style.overflow = "visible"; - style.whiteSpace = "nowrap"; - - // in FF 3.6 monospace fonts can have a fixed sub pixel width. - // that's why we have to measure many characters - // Note: characterWidth can be a float! - measureNode.innerHTML = lang.stringRepeat("Xy", n); - - if (this.element.ownerDocument.body) { - this.element.ownerDocument.body.appendChild(measureNode); - } else { - var container = this.element.parentNode; - while (!dom.hasCssClass(container, "ace_editor")) - container = container.parentNode; - container.appendChild(measureNode); - } - } - - // Size and width can be null if the editor is not visible or - // detached from the document - if (!this.element.offsetWidth) - return null; - - var style = this.$measureNode.style; - var computedStyle = dom.computedStyle(this.element); - for (var prop in this.$fontStyles) - style[prop] = computedStyle[prop]; - - var size = { - height: this.$measureNode.offsetHeight, - width: this.$measureNode.offsetWidth / (n * 2) - }; - - // Size and width can be null if the editor is not visible or - // detached from the document - if (size.width == 0 || size.height == 0) - return null; - - return size; - } - : function() { - if (!this.$measureNode) { - var measureNode = this.$measureNode = dom.createElement("div"); - var style = measureNode.style; - - style.width = style.height = "auto"; - style.left = style.top = -100 + "px"; - - style.visibility = "hidden"; - style.position = "fixed"; - style.overflow = "visible"; - style.whiteSpace = "nowrap"; - - // fixes fractional fixed-width fonts; see http://git.io/CavZNw - measureNode.innerHTML = lang.stringRepeat("X", 100); - - var container = this.element.parentNode; - while (container && !dom.hasCssClass(container, "ace_editor")) - container = container.parentNode; - - if (!container) - return this.$measureNode = null; - - container.appendChild(measureNode); - } - - var rect = this.$measureNode.getBoundingClientRect(); - - var size = { - height: rect.height, - width: rect.width / 100 - }; - - // Size and width can be null if the editor is not visible or - // detached from the document - if (size.width == 0 || size.height == 0) - return null; - - return size; - }; - this.setSession = function(session) { this.session = session; this.$computeTabString(); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index f1757d92..4559f79d 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -42,6 +42,7 @@ var CursorLayer = require("./layer/cursor").Cursor; var HScrollBar = require("./scrollbar").HScrollBar; var VScrollBar = require("./scrollbar").VScrollBar; var RenderLoop = require("./renderloop").RenderLoop; +var FontMetrics = require("./layer/font_metrics").FontMetrics; var EventEmitter = require("./lib/event_emitter").EventEmitter; var editorCss = require("./requirejs/text!./css/editor.css"); @@ -125,10 +126,12 @@ var VirtualRenderer = function(container, theme) { column : 0 }; - this.$textLayer.addEventListener("changeCharacterSize", function() { + this.$fontMetrics = new FontMetrics(this.container, 500); + this.$textLayer.$setFontMetrics(this.$fontMetrics); + this.$textLayer.addEventListener("changeCharacterSize", function(e) { _self.updateCharacterSize(); _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); - _self._signal("changeCharacterSize"); + _self._signal("changeCharacterSize", e); }); this.$size = { @@ -235,6 +238,7 @@ var VirtualRenderer = function(container, theme) { this.$gutterLayer.setSession(session); this.$textLayer.setSession(session); this.$loop.schedule(this.CHANGE_FULL); + this.session.$setFontMetrics(this.$fontMetrics); }; /** From 6e9c9417fc67f46f8748497d6ebe8a90941515da Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 12:33:54 +0400 Subject: [PATCH 04/15] cleanup --- lib/ace/edit_session.js | 22 ++++++++++----------- lib/ace/ext/error_marker.js | 12 ++++++------ lib/ace/layer/gutter.js | 3 ++- lib/ace/lib/event.js | 27 ++++++++++++-------------- lib/ace/mouse/multi_select_handler.js | 2 +- lib/ace/multi_select.js | 4 +++- lib/ace/virtual_renderer.js | 4 ++-- lib/ace/worker/worker.js | 28 +++++++++++++-------------- lib/ace/worker/worker_client.js | 16 ++++++++++----- 9 files changed, 62 insertions(+), 56 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index e4b3d54c..ce526bd5 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -470,7 +470,7 @@ var EditSession = function(text, mode) { * @param {Number} tabSize The new tab size **/ this.setTabSize = function(tabSize) { - this.setOption("tabSize", tabSize) + this.setOption("tabSize", tabSize); }; /** * Returns the current tab size. @@ -486,7 +486,7 @@ var EditSession = function(text, mode) { * **/ this.isTabStop = function(position) { - return this.$useSoftTabs && (position.column % this.$tabSize == 0); + return this.$useSoftTabs && (position.column % this.$tabSize === 0); }; this.$overwrite = false; @@ -500,7 +500,7 @@ var EditSession = function(text, mode) { * **/ this.setOverwrite = function(overwrite) { - this.setOption("overwrite", overwrite) + this.setOption("overwrite", overwrite); }; /** @@ -622,14 +622,14 @@ var EditSession = function(text, mode) { clazz : clazz, inFront: !!inFront, id: id - } + }; if (inFront) { this.$frontMarkers[id] = marker; - this._signal("changeFrontMarker") + this._signal("changeFrontMarker"); } else { this.$backMarkers[id] = marker; - this._signal("changeBackMarker") + this._signal("changeBackMarker"); } return id; @@ -652,10 +652,10 @@ var EditSession = function(text, mode) { if (inFront) { this.$frontMarkers[id] = marker; - this._signal("changeFrontMarker") + this._signal("changeFrontMarker"); } else { this.$backMarkers[id] = marker; - this._signal("changeBackMarker") + this._signal("changeBackMarker"); } return marker; @@ -1043,14 +1043,14 @@ var EditSession = function(text, mode) { }; this.getLineWidgetMaxWidth = function() { - if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth + if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth; var width = 0; this.lineWidgets.forEach(function(w) { if (w && w.screenWidth > width) width = w.screenWidth; }); return this.lineWidgetWidth = width; - } + }; this.$computeWidth = function(force) { if (this.$modified || force) { @@ -1268,7 +1268,7 @@ var EditSession = function(text, mode) { // Check if this range and the last undo range has something in common. // If true, merge the ranges. if (lastUndoRange != null) { - if (Range.comparePoints(lastUndoRange.start, range.start) == 0) { + if (Range.comparePoints(lastUndoRange.start, range.start) === 0) { lastUndoRange.start.column += range.end.column - range.start.column; lastUndoRange.end.column += range.end.column - range.start.column; } diff --git a/lib/ace/ext/error_marker.js b/lib/ace/ext/error_marker.js index 5e87529e..18de2b88 100644 --- a/lib/ace/ext/error_marker.js +++ b/lib/ace/ext/error_marker.js @@ -143,12 +143,12 @@ exports.showErrorMarker = function(editor, dir) { el.className = "error_widget " + gutterAnno.className; el.innerHTML = gutterAnno.text.join("
"); - var kb = { - handleKeyboard:function(_,hashId, keyString) { - if (hashId === 0 && keyString === "esc") { - w.destroy(); - return true; - } + el.appendChild(dom.createElement("div")); + + var kb = function(_, hashId, keyString) { + if (hashId === 0 && (keyString === "esc" || keyString === "return")) { + w.destroy(); + return {command: "null"}; } }; diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 620a2690..7b206f61 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -120,7 +120,8 @@ var Gutter = function(parentEl) { this.update = function(config) { var session = this.session; var firstRow = config.firstRow; - var lastRow = Math.min(config.lastRow + 1, session.getLength() - 1); // needed to compensate + var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar + session.getLength() - 1); var fold = session.getNextFoldLine(firstRow); var foldStart = fold ? fold.start.row : Infinity; var foldWidgets = this.$showFoldWidgets && session.foldWidgets; diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 6721b19c..8966f001 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -33,7 +33,6 @@ define(function(require, exports, module) { var keys = require("./keys"); var useragent = require("./useragent"); -var dom = require("./dom"); exports.addListener = function(elem, type, callback) { if (elem.addEventListener) { @@ -170,7 +169,7 @@ exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbac }; exports.addListener(el, "mousedown", function(e) { - if (exports.getButton(e) != 0) { + if (exports.getButton(e) !== 0) { clicks = 0; } else if (e.detail > 1) { clicks++; @@ -210,22 +209,23 @@ exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbac } }; -function normalizeCommandKeys(callback, e, keyCode) { - var hashId = 0; - if ((useragent.isOpera && !("KeyboardEvent" in window)) && useragent.isMac) { - hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) - | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); - } else { - hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) - | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); +var getModifierHash = useragent.isMac && useragent.isOpera && !("KeyboardEvent" in window) + ? function(e) { + return 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); } + : function(e) { + return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + }; + +function normalizeCommandKeys(callback, e, keyCode) { + var hashId = getModifierHash(e); if (!useragent.isMac && pressedKeys) { if (pressedKeys[91] || pressedKeys[92]) hashId |= 8; if (pressedKeys.altGr) { if ((3 & hashId) != 3) - pressedKeys.altGr = 0 + pressedKeys.altGr = 0; else return; } @@ -267,12 +267,11 @@ function normalizeCommandKeys(callback, e, keyCode) { if (!hashId && keyCode === 13) { if (e.location || e.keyLocation === 3) { - callback(e, hashId, -keyCode) + callback(e, hashId, -keyCode); if (e.defaultPrevented) return; } } - // If there is no hashId and the keyCode is not a function key, then // we don't call the callback as we don't handle a command key here @@ -281,8 +280,6 @@ function normalizeCommandKeys(callback, e, keyCode) { return false; } - - return callback(e, hashId, keyCode); } diff --git a/lib/ace/mouse/multi_select_handler.js b/lib/ace/mouse/multi_select_handler.js index dc01bd6c..f9c79c4a 100644 --- a/lib/ace/mouse/multi_select_handler.js +++ b/lib/ace/mouse/multi_select_handler.js @@ -51,7 +51,7 @@ function onMouseDown(e) { } if (!ctrl && !alt) { - if (button == 0 && e.editor.inMultiSelectMode) + if (button === 0 && e.editor.inMultiSelectMode) e.editor.exitMultiSelectMode(); return; } diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index d2b3c474..0df59244 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -437,6 +437,7 @@ var Editor = require("./editor").Editor; this.commands.removeDefaultHandler("exec", this.$onMultiSelectExec); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); + this._emit("changeSelection"); }; this.$onMultiSelectExec = function(e) { @@ -487,9 +488,10 @@ var Editor = require("./editor").Editor; i--; } tmpSel.fromOrientedRange(rangeList.ranges[i]); + tmpSel.id = rangeList.ranges[i].marker; this.selection = session.selection = tmpSel; var cmdResult = cmd.exec(this, args || {}); - if (!result == undefined) + if (result !== undefined) result = cmdResult; tmpSel.toOrientedRange(rangeList.ranges[i]); } diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 4559f79d..c5eb42a9 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -33,7 +33,6 @@ define(function(require, exports, module) { var oop = require("./lib/oop"); var dom = require("./lib/dom"); -var useragent = require("./lib/useragent"); var config = require("./config"); var GutterLayer = require("./layer/gutter").Gutter; var MarkerLayer = require("./layer/marker").Marker; @@ -153,7 +152,8 @@ var VirtualRenderer = function(container, theme) { minHeight : 1, maxHeight : 1, offset : 0, - height : 1 + height : 1, + gutterOffset: 1 }; this.scrollMargin = { diff --git a/lib/ace/worker/worker.js b/lib/ace/worker/worker.js index 2646ed17..e642a6ae 100644 --- a/lib/ace/worker/worker.js +++ b/lib/ace/worker/worker.js @@ -42,7 +42,7 @@ window.normalizeModule = function(parentId, moduleName) { window.require = function(parentId, id) { if (!id) { - id = parentId + id = parentId; parentId = null; } if (!id.charAt) @@ -81,14 +81,14 @@ window.define = function(id, deps, factory) { } } else if (arguments.length == 1) { factory = id; - deps = [] + deps = []; id = window.require.id; } if (!deps.length) // If there is no dependencies, we inject 'require', 'exports' and // 'module' as dependencies, to provide CommonJS compatibility. - deps = ['require', 'exports', 'module'] + deps = ['require', 'exports', 'module']; if (id.indexOf("text!") === 0) return; @@ -105,12 +105,12 @@ window.define = function(id, deps, factory) { switch(dep) { // Because 'require', 'exports' and 'module' aren't actual // dependencies, we must handle them seperately. - case 'require': return req - case 'exports': return module.exports - case 'module': return module + case 'require': return req; + case 'exports': return module.exports; + case 'module': return module; // But for all other dependencies, we can just go ahead and // require them. - default: return req(dep) + default: return req(dep); } })); if (returnExports) @@ -119,11 +119,11 @@ window.define = function(id, deps, factory) { } }; }; -window.define.amd = {} +window.define.amd = {}; window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { require.tlns = topLevelNamespaces; -} +}; window.initSender = function initSender() { @@ -155,10 +155,10 @@ window.initSender = function initSender() { }).call(Sender.prototype); return new Sender(); -} +}; -window.main = null; -window.sender = null; +var main = window.main = null; +var sender = window.sender = null; window.onmessage = function(e) { var msg = e.data; @@ -171,9 +171,9 @@ window.onmessage = function(e) { else if (msg.init) { initBaseUrls(msg.tlns); require("ace/lib/es5-shim"); - sender = initSender(); + sender = window.sender = initSender(); var clazz = require(msg.module)[msg.classname]; - main = new clazz(sender); + main = window.main = new clazz(sender); } else if (msg.event && sender) { sender._signal(msg.event, msg.data); diff --git a/lib/ace/worker/worker_client.js b/lib/ace/worker/worker_client.js index cb18998f..4aebe641 100644 --- a/lib/ace/worker/worker_client.js +++ b/lib/ace/worker/worker_client.js @@ -179,16 +179,15 @@ var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) { }; this.$workerBlob = function(workerUrl) { - var script = 'importScripts("' + workerUrl + '");'; + var script = "importScripts('" + workerUrl + "');"; try { - var blob = new Blob([script], {'type': 'application/javascript'}); + return new Blob([script], {"type": "application/javascript"}); } catch (e) { // Backwards-compatibility var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; var blobBuilder = new BlobBuilder(); blobBuilder.append(script); - blob = blobBuilder.getBlob('application/javascript'); + return blobBuilder.getBlob("application/javascript"); } - return blob; }; }).call(WorkerClient.prototype); @@ -202,6 +201,7 @@ var UIWorkerClient = function(topLevelNamespaces, mod, classname) { this.messageBuffer = []; var main = null; + var emitSync = false; var sender = Object.create(EventEmitter); var _self = this; @@ -209,8 +209,14 @@ var UIWorkerClient = function(topLevelNamespaces, mod, classname) { this.$worker.terminate = function() {}; this.$worker.postMessage = function(e) { _self.messageBuffer.push(e); - main && setTimeout(processNext); + if (main) { + if (emitSync) + setTimeout(processNext); + else + processNext(); + } }; + this.setEmitSync = function(val) { emitSync = val }; var processNext = function() { var msg = _self.messageBuffer.shift(); From 4a80bd7b3ddffbb146cdc460da75efbd19156b27 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 13:26:52 +0400 Subject: [PATCH 05/15] fix cstyle behavior in multicursor mode --- lib/ace/editor.js | 7 +- lib/ace/mode/behaviour/cstyle.js | 206 ++++++++++++++++++------------- 2 files changed, 121 insertions(+), 92 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 06ce384b..cecec203 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -660,7 +660,7 @@ var Editor = function(renderer, session) { if (this.$highlightActiveLine) { if ((this.$selectionStyle != "line" || !this.selection.isMultiLine())) highlight = this.getCursorPosition(); - if (this.renderer.$maxLines && this.session.getLength() === 1) + if (this.renderer.$maxLines && this.session.getLength() === 1 && !(this.renderer.$minLines > 1)) highlight = false; } @@ -846,14 +846,13 @@ var Editor = function(renderer, session) { * Inserts `text` into wherever the cursor is pointing. * @param {String} text The new text to add * - * **/ - this.insert = function(text) { + this.insert = function(text, pasted) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); - if (this.getBehavioursEnabled()) { + if (this.getBehavioursEnabled() && !pasted) { // Get a transform if the current mode wants one. var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); if (transform) { diff --git a/lib/ace/mode/behaviour/cstyle.js b/lib/ace/mode/behaviour/cstyle.js index 5bdd997c..2709168e 100644 --- a/lib/ace/mode/behaviour/cstyle.js +++ b/lib/ace/mode/behaviour/cstyle.js @@ -41,89 +41,34 @@ var SAFE_INSERT_IN_TOKENS = var SAFE_INSERT_BEFORE_TOKENS = ["text", "paren.rparen", "punctuation.operator", "comment"]; +var context; +var contextCache = {} +var initContext = function(editor) { + var id = -1; + if (editor.multiSelect) { + id = editor.selection.id; + if (contextCache.rangeCount != editor.multiSelect.rangeCount) + contextCache = {rangeCount: editor.multiSelect.rangeCount}; + } + if (contextCache[id]) + return context = contextCache[id]; + context = contextCache[id] = { + autoInsertedBrackets: 0, + autoInsertedRow: -1, + autoInsertedLineEnd: "", + maybeInsertedBrackets: 0, + maybeInsertedRow: -1, + maybeInsertedLineStart: "", + maybeInsertedLineEnd: "" + }; +}; -var autoInsertedBrackets = 0; -var autoInsertedRow = -1; -var autoInsertedLineEnd = ""; -var maybeInsertedBrackets = 0; -var maybeInsertedRow = -1; -var maybeInsertedLineStart = ""; -var maybeInsertedLineEnd = ""; - -var CstyleBehaviour = function () { - - CstyleBehaviour.isSaneInsertion = function(editor, session) { - var cursor = editor.getCursorPosition(); - var iterator = new TokenIterator(session, cursor.row, cursor.column); - - // Don't insert in the middle of a keyword/identifier/lexical - if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { - // Look ahead in case we're at the end of a token - var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); - if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) - return false; - } - - // Only insert in front of whitespace/comments - iterator.stepForward(); - return iterator.getCurrentTokenRow() !== cursor.row || - this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); - }; - - CstyleBehaviour.$matchTokenType = function(token, types) { - return types.indexOf(token.type || token) > -1; - }; - - CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { - var cursor = editor.getCursorPosition(); - var line = session.doc.getLine(cursor.row); - // Reset previous state if text or context changed too much - if (!this.isAutoInsertedClosing(cursor, line, autoInsertedLineEnd[0])) - autoInsertedBrackets = 0; - autoInsertedRow = cursor.row; - autoInsertedLineEnd = bracket + line.substr(cursor.column); - autoInsertedBrackets++; - }; - - CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { - var cursor = editor.getCursorPosition(); - var line = session.doc.getLine(cursor.row); - if (!this.isMaybeInsertedClosing(cursor, line)) - maybeInsertedBrackets = 0; - maybeInsertedRow = cursor.row; - maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; - maybeInsertedLineEnd = line.substr(cursor.column); - maybeInsertedBrackets++; - }; - - CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { - return autoInsertedBrackets > 0 && - cursor.row === autoInsertedRow && - bracket === autoInsertedLineEnd[0] && - line.substr(cursor.column) === autoInsertedLineEnd; - }; - - CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { - return maybeInsertedBrackets > 0 && - cursor.row === maybeInsertedRow && - line.substr(cursor.column) === maybeInsertedLineEnd && - line.substr(0, cursor.column) == maybeInsertedLineStart; - }; - - CstyleBehaviour.popAutoInsertedClosing = function() { - autoInsertedLineEnd = autoInsertedLineEnd.substr(1); - autoInsertedBrackets--; - }; - - CstyleBehaviour.clearMaybeInsertedClosing = function() { - maybeInsertedBrackets = 0; - maybeInsertedRow = -1; - }; - - this.add("braces", "insertion", function (state, action, editor, session, text) { +var CstyleBehaviour = function() { + this.add("braces", "insertion", function(state, action, editor, session, text) { var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); if (text == '{') { + initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { @@ -147,6 +92,7 @@ var CstyleBehaviour = function () { } } } else if (text == '}') { + initContext(editor); var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar == '}') { var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); @@ -159,9 +105,10 @@ var CstyleBehaviour = function () { } } } else if (text == "\n" || text == "\r\n") { + initContext(editor); var closing = ""; if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) { - closing = lang.stringRepeat("}", maybeInsertedBrackets); + closing = lang.stringRepeat("}", context.maybeInsertedBrackets); CstyleBehaviour.clearMaybeInsertedClosing(); } var rightChar = line.substring(cursor.column, cursor.column + 1); @@ -173,6 +120,7 @@ var CstyleBehaviour = function () { } else if (closing) { var next_indent = this.$getIndent(line); } else { + CstyleBehaviour.clearMaybeInsertedClosing(); return; } var indent = next_indent + session.getTabString(); @@ -186,22 +134,24 @@ var CstyleBehaviour = function () { } }); - this.add("braces", "deletion", function (state, action, editor, session, range) { + this.add("braces", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '{') { + initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.end.column, range.end.column + 1); if (rightChar == '}') { range.end.column++; return range; } else { - maybeInsertedBrackets--; + context.maybeInsertedBrackets--; } } }); - this.add("parens", "insertion", function (state, action, editor, session, text) { + this.add("parens", "insertion", function(state, action, editor, session, text) { if (text == '(') { + initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && editor.getWrapBehavioursEnabled()) { @@ -217,6 +167,7 @@ var CstyleBehaviour = function () { }; } } else if (text == ')') { + initContext(editor); var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); var rightChar = line.substring(cursor.column, cursor.column + 1); @@ -233,9 +184,10 @@ var CstyleBehaviour = function () { } }); - this.add("parens", "deletion", function (state, action, editor, session, range) { + this.add("parens", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '(') { + initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == ')') { @@ -245,8 +197,9 @@ var CstyleBehaviour = function () { } }); - this.add("brackets", "insertion", function (state, action, editor, session, text) { + this.add("brackets", "insertion", function(state, action, editor, session, text) { if (text == '[') { + initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && editor.getWrapBehavioursEnabled()) { @@ -262,6 +215,7 @@ var CstyleBehaviour = function () { }; } } else if (text == ']') { + initContext(editor); var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); var rightChar = line.substring(cursor.column, cursor.column + 1); @@ -278,9 +232,10 @@ var CstyleBehaviour = function () { } }); - this.add("brackets", "deletion", function (state, action, editor, session, range) { + this.add("brackets", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '[') { + initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == ']') { @@ -290,8 +245,9 @@ var CstyleBehaviour = function () { } }); - this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { + this.add("string_dquotes", "insertion", function(state, action, editor, session, text) { if (text == '"' || text == "'") { + initContext(editor); var quote = text; var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); @@ -350,9 +306,10 @@ var CstyleBehaviour = function () { } }); - this.add("string_dquotes", "deletion", function (state, action, editor, session, range) { + this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == selected) { @@ -364,6 +321,79 @@ var CstyleBehaviour = function () { }; + +CstyleBehaviour.isSaneInsertion = function(editor, session) { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + + // Don't insert in the middle of a keyword/identifier/lexical + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { + // Look ahead in case we're at the end of a token + var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); + if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) + return false; + } + + // Only insert in front of whitespace/comments + iterator.stepForward(); + return iterator.getCurrentTokenRow() !== cursor.row || + this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); +}; + +CstyleBehaviour.$matchTokenType = function(token, types) { + return types.indexOf(token.type || token) > -1; +}; + +CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + // Reset previous state if text or context changed too much + if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0])) + context.autoInsertedBrackets = 0; + context.autoInsertedRow = cursor.row; + context.autoInsertedLineEnd = bracket + line.substr(cursor.column); + context.autoInsertedBrackets++; +}; + +CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isMaybeInsertedClosing(cursor, line)) + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = cursor.row; + context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; + context.maybeInsertedLineEnd = line.substr(cursor.column); + context.maybeInsertedBrackets++; +}; + +CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { + return context.autoInsertedBrackets > 0 && + cursor.row === context.autoInsertedRow && + bracket === context.autoInsertedLineEnd[0] && + line.substr(cursor.column) === context.autoInsertedLineEnd; +}; + +CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { + return context.maybeInsertedBrackets > 0 && + cursor.row === context.maybeInsertedRow && + line.substr(cursor.column) === context.maybeInsertedLineEnd && + line.substr(0, cursor.column) == context.maybeInsertedLineStart; +}; + +CstyleBehaviour.popAutoInsertedClosing = function() { + context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1); + context.autoInsertedBrackets--; +}; + +CstyleBehaviour.clearMaybeInsertedClosing = function() { + if (context) { + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = -1; + } +}; + + + oop.inherits(CstyleBehaviour, Behaviour); exports.CstyleBehaviour = CstyleBehaviour; From 42a368ed029b745a5508db45e7eac215204aeeb9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 13:46:07 +0400 Subject: [PATCH 06/15] add selection.moveTo --- lib/ace/autocomplete/popup.js | 3 +-- lib/ace/edit_session.js | 8 ++++---- lib/ace/editor.js | 15 +++++---------- lib/ace/ext/emmet.js | 3 +-- lib/ace/ext/error_marker.js | 3 +-- lib/ace/keyboard/vim/commands.js | 9 +++------ lib/ace/keyboard/vim/maps/motions.js | 3 +-- lib/ace/keyboard/vim/maps/util.js | 6 ++---- lib/ace/mouse/default_handlers.js | 8 +++----- lib/ace/mouse/multi_select_handler.js | 11 ++++------- lib/ace/selection.js | 21 +++++++++++++++++++++ 11 files changed, 46 insertions(+), 44 deletions(-) diff --git a/lib/ace/autocomplete/popup.js b/lib/ace/autocomplete/popup.js index ca40cad1..02ef21ee 100644 --- a/lib/ace/autocomplete/popup.js +++ b/lib/ace/autocomplete/popup.js @@ -86,8 +86,7 @@ var AcePopup = function(parentNode) { popup.on("mousedown", function(e) { var pos = e.getDocumentPosition(); - popup.moveCursorToPosition(pos); - popup.selection.clearSelection(); + popup.selection.moveToPosition(pos); selectionMarker.start.row = selectionMarker.end.row = pos.row; e.stop(); }); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index ce526bd5..9689ea5c 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -281,13 +281,13 @@ var EditSession = function(text, mode) { **/ this.setValue = function(text) { this.doc.setValue(text); - this.selection.moveCursorTo(0, 0); - this.selection.clearSelection(); + this.selection.moveTo(0, 0); this.$resetRowCache(0); this.$deltas = []; this.$deltasDoc = []; this.$deltasFold = []; + this.setUndoManager(this.$undoManager); this.getUndoManager().reset(); }; @@ -412,7 +412,7 @@ var EditSession = function(text, mode) { } self.mergeUndoDeltas = false; self.$deltas = []; - } + }; this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); } }; @@ -696,7 +696,7 @@ var EditSession = function(text, mode) { this.$searchHighlight = this.addDynamicMarker(highlight); } this.$searchHighlight.setRegexp(re); - } + }; // experimental this.highlightLines = function(startRow, endRow, clazz, inFront) { diff --git a/lib/ace/editor.js b/lib/ace/editor.js index cecec203..0efbdd93 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1941,8 +1941,7 @@ var Editor = function(renderer, session) { else this.selection.selectTo(pos.row, pos.column); } else { - this.clearSelection(); - this.moveCursorTo(pos.row, pos.column); + this.selection.moveTo(pos.row, pos.column); } } }; @@ -1977,8 +1976,7 @@ var Editor = function(renderer, session) { * @related Editor.moveCursorTo **/ this.navigateTo = function(row, column) { - this.clearSelection(); - this.moveCursorTo(row, column); + this.selection.moveTo(row, column); }; /** @@ -1993,8 +1991,7 @@ var Editor = function(renderer, session) { return this.moveCursorToPosition(selectionStart); } this.selection.clearSelection(); - times = times || 1; - this.selection.moveCursorBy(-times, 0); + this.selection.moveCursorBy(-times || -1, 0); }; /** @@ -2009,8 +2006,7 @@ var Editor = function(renderer, session) { return this.moveCursorToPosition(selectionEnd); } this.selection.clearSelection(); - times = times || 1; - this.selection.moveCursorBy(times, 0); + this.selection.moveCursorBy(times || 1, 0); }; /** @@ -2154,8 +2150,7 @@ var Editor = function(renderer, session) { this.$blockScrolling += 1; var selection = this.getSelectionRange(); - this.clearSelection(); - this.selection.moveCursorTo(0, 0); + this.selection.moveTo(0, 0); for (var i = ranges.length - 1; i >= 0; --i) { if(this.$tryReplace(ranges[i], replacement)) { diff --git a/lib/ace/ext/emmet.js b/lib/ace/ext/emmet.js index 6647da40..896a66d8 100644 --- a/lib/ace/ext/emmet.js +++ b/lib/ace/ext/emmet.js @@ -130,8 +130,7 @@ AceEmmetEditor.prototype = { */ setCaretPos: function(index){ var pos = this.ace.indexToPosition(index); - this.ace.clearSelection(); - this.ace.selection.moveCursorToPosition(pos); + this.ace.selection.moveToPosition(pos); }, /** diff --git a/lib/ace/ext/error_marker.js b/lib/ace/ext/error_marker.js index 18de2b88..2f5466b0 100644 --- a/lib/ace/ext/error_marker.js +++ b/lib/ace/ext/error_marker.js @@ -122,8 +122,7 @@ exports.showErrorMarker = function(editor, dir) { }; } editor.session.unfold(pos.row); - editor.selection.moveCursorToPosition(pos); - editor.selection.clearSelection(); + editor.selection.moveToPosition(pos); var w = { row: pos.row, diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js index dd3357d6..e48446f4 100644 --- a/lib/ace/keyboard/vim/commands.js +++ b/lib/ace/keyboard/vim/commands.js @@ -201,8 +201,7 @@ var actions = exports.actions = { //editor.selection.selectLine(); //editor.selection.selectLeft(); var row = editor.getCursorPosition().row; - editor.selection.clearSelection(); - editor.selection.moveCursorTo(row, 0); + editor.selection.moveTo(row, 0); editor.selection.selectLineEnd(); editor.selection.visualLineStart = row; @@ -582,13 +581,11 @@ var handleCursorMove = exports.onCursorMove = function(editor, e) { var cursorRow = editor.getCursorPosition().row; if(originRow <= cursorRow) { var endLine = editor.session.getLine(cursorRow); - editor.selection.clearSelection(); - editor.selection.moveCursorTo(originRow, 0); + editor.selection.moveTo(originRow, 0); editor.selection.selectTo(cursorRow, endLine.length); } else { var endLine = editor.session.getLine(originRow); - editor.selection.clearSelection(); - editor.selection.moveCursorTo(originRow, endLine.length); + editor.selection.moveTo(originRow, endLine.length); editor.selection.selectTo(cursorRow, 0); } } diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js index ae457d54..630ba66a 100644 --- a/lib/ace/keyboard/vim/maps/motions.js +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -53,8 +53,7 @@ function Motion(m) { var a = getPos(editor, range, count, param, false); if (!a) return; - editor.clearSelection(); - editor.moveCursorTo(a.row, a.column); + editor.selection.moveTo(a.row, a.column); }; m.sel = function(editor, range, count, param) { var a = getPos(editor, range, count, param, true); diff --git a/lib/ace/keyboard/vim/maps/util.js b/lib/ace/keyboard/vim/maps/util.js index af0e07c7..a216c2cc 100644 --- a/lib/ace/keyboard/vim/maps/util.js +++ b/lib/ace/keyboard/vim/maps/util.js @@ -122,13 +122,11 @@ module.exports = { }, copyLine: function(editor) { var pos = editor.getCursorPosition(); - editor.selection.clearSelection(); - editor.moveCursorTo(pos.row, pos.column); + editor.selection.moveTo(pos.row, pos.column); editor.selection.selectLine(); registers._default.isLine = true; registers._default.text = editor.getCopyText().replace(/\n$/, ""); - editor.selection.clearSelection(); - editor.moveCursorTo(pos.row, pos.column); + editor.selection.moveTo(pos.row, pos.column); } }; }); diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js index 84e0ac48..6e97bc5d 100644 --- a/lib/ace/mouse/default_handlers.js +++ b/lib/ace/mouse/default_handlers.js @@ -72,8 +72,7 @@ function DefaultHandlers(mouseHandler) { var selectionEmpty = selectionRange.isEmpty(); if (selectionEmpty) { - editor.moveCursorToPosition(pos); - editor.selection.clearSelection(); + editor.selection.moveToPosition(pos); } // 2: contextmenu, 1: linux paste @@ -93,6 +92,7 @@ function DefaultHandlers(mouseHandler) { } } + this.captureMouse(ev); if (!inSelection || this.$clickSelection || ev.getShiftKey() || editor.inMultiSelectMode) { // Directly pick STATE_SELECT, since the user is not clicking inside // a selection. @@ -101,7 +101,6 @@ function DefaultHandlers(mouseHandler) { this.mousedownEvent.time = Date.now(); this.startSelect(pos); } - this.captureMouse(ev); return ev.preventDefault(); }; @@ -114,8 +113,7 @@ function DefaultHandlers(mouseHandler) { editor.selection.selectToPosition(pos); } else if (!this.$clickSelection) { - editor.moveCursorToPosition(pos); - editor.selection.clearSelection(); + editor.selection.moveToPosition(pos); } if (editor.renderer.scroller.setCapture) { editor.renderer.scroller.setCapture(); diff --git a/lib/ace/mouse/multi_select_handler.js b/lib/ace/mouse/multi_select_handler.js index f9c79c4a..88dc6668 100644 --- a/lib/ace/mouse/multi_select_handler.js +++ b/lib/ace/mouse/multi_select_handler.js @@ -32,7 +32,6 @@ define(function(require, exports, module) { var event = require("../lib/event"); - // mouse function isSamePoint(p1, p2) { return p1.row == p2.row && p1.column == p2.column; @@ -79,8 +78,7 @@ function onMouseDown(e) { return; screenCursor = newCursor; - editor.selection.moveCursorToPosition(cursor); - editor.selection.clearSelection(); + editor.selection.moveToPosition(cursor); editor.renderer.scrollCursorIntoView(); editor.removeSelectionMarkers(rectSel); @@ -95,7 +93,7 @@ function onMouseDown(e) { - if (ctrl && !shift && !alt && button == 0) { + if (ctrl && !alt && !shift && button === 0) { if (!isMultiSelect && inSelection) return; // dragging @@ -122,7 +120,7 @@ function onMouseDown(e) { editor.$blockScrolling--; }); - } else if (alt && button == 0) { + } else if (alt && button === 0) { e.stop(); if (isMultiSelect && !ctrl) @@ -135,8 +133,7 @@ function onMouseDown(e) { screenAnchor = session.documentToScreenPosition(selection.lead); blockSelect(); } else { - selection.moveCursorToPosition(pos); - selection.clearSelection(); + selection.moveToPosition(pos); } diff --git a/lib/ace/selection.js b/lib/ace/selection.js index adfb6518..712021ad 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -298,6 +298,27 @@ var Selection = function(session) { }); }; + /** + * Moves the selection cursor to the indicated row and column. + * @param {Number} row The row to select to + * @param {Number} column The column to select to + * + **/ + this.moveTo = function(row, column) { + this.clearSelection(); + this.moveCursorTo(row, column); + }; + + /** + * Moves the selection cursor to the row and column indicated by `pos`. + * @param {Object} pos An object containing the row and column + **/ + this.moveToPosition = function(pos) { + this.clearSelection(); + this.moveCursorToPosition(pos); + }; + + /** * * Moves the selection up one row. From 5783bae0587406e6482c08490da4360e131a3263 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 13:49:42 +0400 Subject: [PATCH 07/15] add event.getModifierString to convert hash into readable string --- lib/ace/keyboard/vim.js | 4 ++-- lib/ace/lib/event.js | 4 ++++ lib/ace/lib/keys.js | 11 ++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js index fdd88117..3ae4842f 100644 --- a/lib/ace/keyboard/vim.js +++ b/lib/ace/keyboard/vim.js @@ -145,8 +145,8 @@ exports.handler = { if (hashId == -1 || hashId == 1 || hashId === 0 && key.length > 1) { if (cmds.inputBuffer.idle && startCommands[key]) return startCommands[key]; - cmds.inputBuffer.push(editor, key); - return {command: "null", passEvent: false}; + var isHandled = cmds.inputBuffer.push(editor, key); + return {command: "null", passEvent: !isHandled}; } // if no modifier || shift: wait for input. else if (key.length == 1 && (hashId === 0 || hashId == 4)) { return {command: "null", passEvent: true}; diff --git a/lib/ace/lib/event.js b/lib/ace/lib/event.js index 8966f001..9ad0c3ac 100644 --- a/lib/ace/lib/event.js +++ b/lib/ace/lib/event.js @@ -217,6 +217,10 @@ var getModifierHash = useragent.isMac && useragent.isOpera && !("KeyboardEvent" return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); }; +exports.getModifierString = function(e) { + return keys.KEY_MODS[getModifierHash(e)]; +}; + function normalizeCommandKeys(callback, e, keyCode) { var hashId = getModifierHash(e); diff --git a/lib/ace/lib/keys.js b/lib/ace/lib/keys.js index 916d9f00..78cede51 100644 --- a/lib/ace/lib/keys.js +++ b/lib/ace/lib/keys.js @@ -133,6 +133,15 @@ var Keys = (function() { // workaround for firefox bug ret[173] = '-'; + + (function() { + var mods = ["cmd", "ctrl", "alt", "shift"]; + for (var i = Math.pow(2, mods.length); i--;) { + ret.KEY_MODS[i] = mods.filter(function(x) { + return i & ret.KEY_MODS[x]; + }).join("-") + "-"; + } + })(); return ret; })(); @@ -140,6 +149,6 @@ oop.mixin(exports, Keys); exports.keyCodeToString = function(keyCode) { return (Keys[keyCode] || String.fromCharCode(keyCode)).toLowerCase(); -} +}; }); From 9c80485d919caf71252494009e6458ada851aa73 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 15 Feb 2014 14:07:31 +0400 Subject: [PATCH 08/15] allow setting editor session to null --- lib/ace/editor.js | 139 +++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 0efbdd93..300e4399 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -289,14 +289,13 @@ var Editor = function(renderer, session) { * Sets a new editsession to use. This method also emits the `'changeSession'` event. * @param {EditSession} session The new session to use * - * **/ this.setSession = function(session) { if (this.session == session) return; - if (this.session) { - var oldSession = this.session; + var oldSession = this.session; + if (oldSession) { this.session.removeEventListener("change", this.$onDocumentChange); this.session.removeEventListener("changeMode", this.$onChangeMode); this.session.removeEventListener("tokenizerUpdate", this.$onTokenizerUpdate); @@ -318,76 +317,80 @@ var Editor = function(renderer, session) { } this.session = session; - - this.$onDocumentChange = this.onDocumentChange.bind(this); - session.addEventListener("change", this.$onDocumentChange); - this.renderer.setSession(session); - - this.$onChangeMode = this.onChangeMode.bind(this); - session.addEventListener("changeMode", this.$onChangeMode); - - this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); - session.addEventListener("tokenizerUpdate", this.$onTokenizerUpdate); - - this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); - session.addEventListener("changeTabSize", this.$onChangeTabSize); - - this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); - session.addEventListener("changeWrapLimit", this.$onChangeWrapLimit); - - this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); - session.addEventListener("changeWrapMode", this.$onChangeWrapMode); - - this.$onChangeFold = this.onChangeFold.bind(this); - session.addEventListener("changeFold", this.$onChangeFold); - - this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); - this.session.addEventListener("changeFrontMarker", this.$onChangeFrontMarker); - - this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); - this.session.addEventListener("changeBackMarker", this.$onChangeBackMarker); - - this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); - this.session.addEventListener("changeBreakpoint", this.$onChangeBreakpoint); - - this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); - this.session.addEventListener("changeAnnotation", this.$onChangeAnnotation); - - this.$onCursorChange = this.onCursorChange.bind(this); - this.session.addEventListener("changeOverwrite", this.$onCursorChange); - - this.$onScrollTopChange = this.onScrollTopChange.bind(this); - this.session.addEventListener("changeScrollTop", this.$onScrollTopChange); - - this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); - this.session.addEventListener("changeScrollLeft", this.$onScrollLeftChange); - - this.selection = session.getSelection(); - this.selection.addEventListener("changeCursor", this.$onCursorChange); - - this.$onSelectionChange = this.onSelectionChange.bind(this); - this.selection.addEventListener("changeSelection", this.$onSelectionChange); - - this.onChangeMode(); - - this.$blockScrolling += 1; - this.onCursorChange(); - this.$blockScrolling -= 1; - - this.onScrollTopChange(); - this.onScrollLeftChange(); - this.onSelectionChange(); - this.onChangeFrontMarker(); - this.onChangeBackMarker(); - this.onChangeBreakpoint(); - this.onChangeAnnotation(); - this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); - this.renderer.updateFull(); + if (session) { + this.$onDocumentChange = this.onDocumentChange.bind(this); + session.addEventListener("change", this.$onDocumentChange); + this.renderer.setSession(session); + + this.$onChangeMode = this.onChangeMode.bind(this); + session.addEventListener("changeMode", this.$onChangeMode); + + this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); + session.addEventListener("tokenizerUpdate", this.$onTokenizerUpdate); + + this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); + session.addEventListener("changeTabSize", this.$onChangeTabSize); + + this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); + session.addEventListener("changeWrapLimit", this.$onChangeWrapLimit); + + this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); + session.addEventListener("changeWrapMode", this.$onChangeWrapMode); + + this.$onChangeFold = this.onChangeFold.bind(this); + session.addEventListener("changeFold", this.$onChangeFold); + + this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); + this.session.addEventListener("changeFrontMarker", this.$onChangeFrontMarker); + + this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); + this.session.addEventListener("changeBackMarker", this.$onChangeBackMarker); + + this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); + this.session.addEventListener("changeBreakpoint", this.$onChangeBreakpoint); + + this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); + this.session.addEventListener("changeAnnotation", this.$onChangeAnnotation); + + this.$onCursorChange = this.onCursorChange.bind(this); + this.session.addEventListener("changeOverwrite", this.$onCursorChange); + + this.$onScrollTopChange = this.onScrollTopChange.bind(this); + this.session.addEventListener("changeScrollTop", this.$onScrollTopChange); + + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + this.session.addEventListener("changeScrollLeft", this.$onScrollLeftChange); + + this.selection = session.getSelection(); + this.selection.addEventListener("changeCursor", this.$onCursorChange); + + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.addEventListener("changeSelection", this.$onSelectionChange); + + this.onChangeMode(); + + this.$blockScrolling += 1; + this.onCursorChange(); + this.$blockScrolling -= 1; + + this.onScrollTopChange(); + this.onScrollLeftChange(); + this.onSelectionChange(); + this.onChangeFrontMarker(); + this.onChangeBackMarker(); + this.onChangeBreakpoint(); + this.onChangeAnnotation(); + this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); + this.renderer.updateFull(); + } this._signal("changeSession", { session: session, oldSession: oldSession }); + + oldSession && oldSession._signal("changeEditor", {oldEditor: this}); + session && session._signal("changeEditor", {editor: this}); }; /** From 3694a025322696cc0dad9e3087cc849e065c3264 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 12 Feb 2014 23:00:51 +0400 Subject: [PATCH 09/15] do not copy "ace/ace" when setting as global --- Makefile.dryice.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 49bf0b28..ee26328d 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -658,9 +658,7 @@ function exportAce(ns, module, requireBase, extModule) { REQUIRE_NS.require(["MODULE"], function(a) { a && a.config.init(); if (!window.NS) - window.NS = {}; - for (var key in a) if (a.hasOwnProperty(key)) - NS[key] = a[key]; + window.NS = a; }); })(); }; From 45311cda459a3ae52405b578dcceb928cbf509d4 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 21 Feb 2014 22:30:47 +0400 Subject: [PATCH 10/15] fix #1808 show different different indicators for LF and CRLF --- lib/ace/document.js | 2 ++ lib/ace/layer/text.js | 21 +++++++++++++++++---- lib/ace/virtual_renderer.js | 16 +++++++++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/lib/ace/document.js b/lib/ace/document.js index 14e04ff9..a2ca7210 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -120,6 +120,7 @@ var Document = function(text) { this.$detectNewLine = function(text) { var match = text.match(/^.*?(\r\n|\r|\n)/m); this.$autoNewLine = match ? match[1] : "\n"; + this._signal("changeNewLineMode"); }; /** @@ -152,6 +153,7 @@ var Document = function(text) { return; this.$newLineMode = newLineMode; + this._signal("changeNewLineMode"); }; /** diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 50b00196..fd81f5ff 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -41,18 +41,31 @@ var Text = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_text-layer"; parentEl.appendChild(this.element); + this.$updateEolChar = this.$updateEolChar.bind(this); }; (function() { oop.implement(this, EventEmitter); - this.EOF_CHAR = "\xB6"; //"¶"; - this.EOL_CHAR = "\xAC"; //"¬"; - this.TAB_CHAR = "\u2192"; //"→" "\u21E5"; - this.SPACE_CHAR = "\xB7"; //"·"; + 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.SPACE_CHAR = "\xB7"; this.$padding = 0; + this.$updateEolChar = function() { + var EOL_CHAR = this.session.doc.getNewLineCharacter() == "\n" + ? this.EOL_CHAR_LF + : this.EOL_CHAR_CRLF; + if (this.EOL_CHAR != EOL_CHAR) { + this.EOL_CHAR = EOL_CHAR; + return true; + } + } + this.setPadding = function(padding) { this.$padding = padding; this.element.style.padding = "0 " + padding + "px"; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index c5eb42a9..28cefde1 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -227,8 +227,13 @@ var VirtualRenderer = function(container, theme) { * Associates the renderer with an [[EditSession `EditSession`]]. **/ this.setSession = function(session) { + if (this.session) + this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); + this.session = session; - + if (!session) + return; + if (this.scrollMargin.top && session.getScrollTop() <= 0) session.setScrollTop(-this.scrollMargin.top); @@ -239,6 +244,10 @@ var VirtualRenderer = function(container, theme) { this.$textLayer.setSession(session); this.$loop.schedule(this.CHANGE_FULL); this.session.$setFontMetrics(this.$fontMetrics); + + this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this); + this.onChangeNewLineMode() + this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode); }; /** @@ -272,6 +281,11 @@ var VirtualRenderer = function(container, theme) { this.$loop.schedule(this.CHANGE_LINES); }; + this.onChangeNewLineMode = function() { + this.$loop.schedule(this.CHANGE_TEXT); + this.$textLayer.$updateEolChar(); + }; + this.onChangeTabSize = function() { this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); this.$textLayer.onChangeTabSize(); From 306e918920fa9f1275ed16a479626d5b70106db6 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 21 Feb 2014 22:38:42 +0400 Subject: [PATCH 11/15] fix #1825 editor created with showGutter=false cannot later show gutters --- lib/ace/virtual_renderer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 28cefde1..6034cc9c 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -1623,6 +1623,7 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { showGutter: { set: function(show){ this.$gutter.style.display = show ? "block" : "none"; + this.$loop.schedule(this.CHANGE_FULL); this.onGutterResize(); }, initialValue: true From 07c7c86944cd622041edf6e909ba31aa0fa7603d Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 23 Feb 2014 12:02:45 +0400 Subject: [PATCH 12/15] fix #1827 setScrollMargin Breaks Multiple Selection When Margin is Greater Than 0 --- lib/ace/layer/cursor.js | 2 +- lib/ace/virtual_renderer.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js index aaf3ffec..4578482a 100644 --- a/lib/ace/layer/cursor.js +++ b/lib/ace/layer/cursor.js @@ -190,7 +190,7 @@ var Cursor = function(parentEl) { for (var i = 0, n = selections.length; i < n; i++) { var pixelPos = this.getPixelPosition(selections[i].cursor, true); if ((pixelPos.top > config.height + config.offset || - pixelPos.top < -config.offset) && i > 1) { + pixelPos.top < 0) && i > 1) { continue; } diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 6034cc9c..6f6ab177 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -720,7 +720,7 @@ var VirtualRenderer = function(container, theme) { sm.v = sm.top + sm.bottom; sm.h = sm.left + sm.right; if (sm.top && this.scrollTop <= 0 && this.session) - this.session.setScrollTop(sm.top); + this.session.setScrollTop(-sm.top); this.updateFull(); }; @@ -1002,7 +1002,7 @@ var VirtualRenderer = function(container, theme) { minHeight : minHeight, maxHeight : maxHeight, offset : offset, - gutterOffset : Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight), + gutterOffset : Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)), height : this.$size.scrollerHeight }; From a9117a4aee9c7dc377aaa2cdc8fcad72906697bf Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 23 Feb 2014 14:02:38 +0400 Subject: [PATCH 13/15] define('ace/ace') needs to be at the end of ace.js fixes https://github.com/ajaxorg/ace-builds/issues/15 --- Makefile.dryice.js | 87 +++++++++++++++++++++++++++++----------------- lib/ace/config.js | 6 ++-- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index ee26328d..add81489 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -293,27 +293,30 @@ function getWriteFilters(options, projectType, main) { if (options.noconflict) filters.push(namespace(options.ns)); - + + if (options.exportModule && projectType == "main" || projectType == "ext") { + filters.push(exportAce(options.ns, options.exportModule, + options.noconflict ? options.ns : "", projectType == "ext" && main)); + } + if (options.compress) filters.push(copy.filter.uglifyjs); - // copy.filter.uglifyjs.options.ascii = true; doesn't work with some uglify.js versions + // copy.filter.uglifyjs.options.ascii_only = true; doesn't work with some uglify.js versions filters.push(function(text) { - var t1 = text.replace(/[\x80-\uffff]/g, function(c) { + var text = text.replace(/[\x00-\x09\x0b\x0c\x0e\x19\x80-\uffff]/g, function(c) { c = c.charCodeAt(0).toString(16); + if (c.length == 1) + return "\\x0" + c; if (c.length == 2) return "\\x" + c; if (c.length == 3) - c = "0" + c; + return "\\u0" + c; return "\\u" + c; }); return text; }); - if (options.exportModule && projectType == "main" || projectType == "ext") { - filters.push(exportAce(options.ns, options.exportModule, - options.noconflict ? options.ns : "", projectType == "ext" && main)); - } return filters; } @@ -550,15 +553,6 @@ var detectTextModules = function(input, source) { detectTextModules.onRead = true; copy.filter.addDefines = detectTextModules; -function generateThemesModule(themes) { - var themelist = [ - 'define(function(require, exports, module) {', - '\n\nmodule.exports.themes = ' + JSON.stringify(themes, null, ' '), - ';\n\n});' - ].join(''); - fs.writeFileSync(__dirname + '/lib/ace/ext/themelist_utils/themes.js', themelist, 'utf8'); -} - function inlineTextModules(text) { var deps = []; return text.replace(/, *['"]ace\/requirejs\/text!(.*?)['"]| require\(['"](?:ace|[.\/]+)\/requirejs\/text!(.*?)['"]\)/g, function(_, dep, call) { @@ -574,14 +568,37 @@ function inlineTextModules(text) { }); call = textModules[dep]; - // if (deps.length > 1) - // console.log(call.length) if (call) return " " + call; } }); } +var CommonJsProject = copy.createCommonJsProject({roots:[]}).constructor; +CommonJsProject.prototype.getCurrentModules = function() { + function isDep(child, parent) { + if (!modules[parent]) + return false; + var deps = modules[parent].deps; + if (deps[child]) return true; + return Object.keys(deps).some(function(x) { + return isDep(child, x) + }); + } + var depMap = {}, modules = this.currentModules; + return Object.keys(this.currentModules).map(function(moduleName) { + module = modules[moduleName] + module.id = moduleName; + return module; + }).sort(function(a, b) { + if (isDep(a.id, b.id)) + return -1; + if (isDep(b.id, a.id)) + return 1; + return Object.keys(a.deps).length - Object.keys(b.deps).length || a.id.localeCompare(b.id) + }); +}; + // TODO: replace with project.clone once it is fixed in dryice function cloneProject(project) { var clone = copy.createCommonJsProject({ @@ -602,16 +619,12 @@ function cloneProject(project) { } function copyFileSync(srcFile, destFile) { - var BUF_LENGTH = 64*1024, - buf = new Buffer(BUF_LENGTH), - bytesRead = BUF_LENGTH, - pos = 0, - fdr = null, - fdw = null; - - - fdr = fs.openSync(srcFile, 'r'); - fdw = fs.openSync(destFile, 'w'); + var BUF_LENGTH = 64*1024; + var buf = new Buffer(BUF_LENGTH); + var bytesRead = BUF_LENGTH; + var pos = 0; + var fdr = fs.openSync(srcFile, 'r'); + var fdw = fs.openSync(destFile, 'w'); while (bytesRead === BUF_LENGTH) { bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos); @@ -652,13 +665,14 @@ function exportAce(ns, module, requireBase, extModule) { requireBase = requireBase || "window"; module = module || "ace/ace"; return function(text) { - var template = function() { (function() { REQUIRE_NS.require(["MODULE"], function(a) { - a && a.config.init(); + a && a.config.init(true); if (!window.NS) window.NS = a; + for (var key in a) if (a.hasOwnProperty(key)) + NS[key] = a[key]; }); })(); }; @@ -672,6 +686,8 @@ function exportAce(ns, module, requireBase, extModule) { }; } + text = text.replace(/function init\(packaged\) {/, "init(true);$&\n"); + return (text + ";" + template .toString() .replace(/MODULE/g, module) @@ -694,6 +710,15 @@ function updateModes() { }) } +function generateThemesModule(themes) { + var themelist = [ + 'define(function(require, exports, module) {', + '\n\nmodule.exports.themes = ' + JSON.stringify(themes, null, ' '), + ';\n\n});' + ].join(''); + fs.writeFileSync(__dirname + '/lib/ace/ext/themelist_utils/themes.js', themelist, 'utf8'); +} + if (!module.parent) main(process.argv); else diff --git a/lib/ace/config.js b/lib/ace/config.js index f8614c1a..1d927e45 100644 --- a/lib/ace/config.js +++ b/lib/ace/config.js @@ -144,8 +144,8 @@ exports.loadModule = function(moduleName, onLoad) { // initialization -exports.init = function() { - options.packaged = require.packaged || module.packaged || (global.define && define.packaged); +function init(packaged) { + options.packaged = packaged || require.packaged || module.packaged || (global.define && define.packaged); if (!global.document) return ""; @@ -190,6 +190,8 @@ exports.init = function() { exports.set(key, scriptOptions[key]); }; +exports.init = init; + function deHyphenate(str) { return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); }); } From c1011ca87520bf6f3638a3025c86460cbdff85a5 Mon Sep 17 00:00:00 2001 From: nightwing Date: Wed, 26 Feb 2014 17:29:32 +0400 Subject: [PATCH 14/15] fix worker build --- Makefile.dryice.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index add81489..f8e1383c 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -304,7 +304,7 @@ function getWriteFilters(options, projectType, main) { // copy.filter.uglifyjs.options.ascii_only = true; doesn't work with some uglify.js versions filters.push(function(text) { - var text = text.replace(/[\x00-\x09\x0b\x0c\x0e\x19\x80-\uffff]/g, function(c) { + var text = text.replace(/[\x00-\x08\x0b\x0c\x0e\x19\x80-\uffff]/g, function(c) { c = c.charCodeAt(0).toString(16); if (c.length == 1) return "\\x0" + c; @@ -587,14 +587,15 @@ CommonJsProject.prototype.getCurrentModules = function() { } var depMap = {}, modules = this.currentModules; return Object.keys(this.currentModules).map(function(moduleName) { - module = modules[moduleName] + module = modules[moduleName]; module.id = moduleName; + module.isSpecial = !/define\(\'[^']*',/.test(module.source); return module; }).sort(function(a, b) { - if (isDep(a.id, b.id)) - return -1; - if (isDep(b.id, a.id)) - return 1; + if (a.isSpecial) return -1; + if (b.isSpecial) return 1; + if (isDep(a.id, b.id)) return -1; + if (isDep(b.id, a.id)) return 1; return Object.keys(a.deps).length - Object.keys(b.deps).length || a.id.localeCompare(b.id) }); }; From 3166b3fb90bec07e1a28c605cb5f341495375f61 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 3 Mar 2014 15:24:39 +0400 Subject: [PATCH 15/15] fix #1836 html worker logs a lot of `unable to load` --- lib/ace/mode/html/saxparser.js | 102 ++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/lib/ace/mode/html/saxparser.js b/lib/ace/mode/html/saxparser.js index 966630d5..079f2e5c 100644 --- a/lib/ace/mode/html/saxparser.js +++ b/lib/ace/mode/html/saxparser.js @@ -1,5 +1,5 @@ -define(["require", "exports", "module"], function(require, exports, module){ -require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s