This commit is contained in:
Resolver Developers 2011-02-14 10:23:33 +00:00
commit ad4987ca0f
46 changed files with 1980 additions and 230 deletions

View file

@ -1,3 +1,26 @@
2011.02.14, Version 0.1.6
* Extensive support for Cocoa style keybindings on the Mac <https://github.com/ajaxorg/ace/issues/closed#issue/116/comment/767803>
* New commands:
- center selection in viewport
- remove to end/start of line
- split line
- transpose letters
* Refator markers
- Custom code can be used to render markers
- Markers can be in front or behind the text
- Markers are now stored in the session (was in the renderer)
* Lots of IE8 fixes including copy, cut and selections
* Unit tests can also be run in the browser <https://github.com/ajaxorg/ace/blob/master/lib/ace/test/tests.html>
* Soft wrap can adapt to the width of the editor (Mike Ratcliffe, Joe Cheng)
* Add minimal node server server.js to run the Ace demo in Chrome
* The top level editor.html demo has been renamed to index.html
* Bug fixes
- Fixed gotoLine to consider wrapped lines when calculating where to scroll to (James Allen)
- Fixed isues when the editor was scrolled in the web page (Eric Allam)
- Highlighting of Python string literals
- Syntax rule for PHP comments
2011.02.08, Version 0.1.5
* Add Coffeescript Mode (Satoshi Murakami)

View file

@ -1,3 +1,26 @@
2011.02.14, Version 0.1.6
* Extensive support for Cocoa style keybindings on the Mac <https://github.com/ajaxorg/ace/issues/closed#issue/116/comment/767803>
* New commands:
- center selection in viewport
- remove to end/start of line
- split line
- transpose letters
* Refator markers
- Custom code can be used to render markers
- Markers can be in front or behind the text
- Markers are now stored in the session (was in the renderer)
* Lots of IE8 fixes including copy, cut and selections
* Unit tests can also be run in the browser <https://github.com/ajaxorg/ace/blob/master/lib/ace/test/tests.html>
* Soft wrap can adapt to the width of the editor (Mike Ratcliffe, Joe Cheng)
* Add minimal node server server.js to run the Ace demo in Chrome
* The top level editor.html demo has been renamed to index.html
* Bug fixes
- Fixed gotoLine to consider wrapped lines when calculating where to scroll to (James Allen)
- Fixed isues when the editor was scrolled in the web page (Eric Allam)
- Highlighting of Python string literals
- Syntax rule for PHP comments
2011.02.08, Version 0.1.5
* Add Coffeescript Mode (Satoshi Murakami)

View file

@ -598,23 +598,21 @@ if (!Object.isFrozen) Object.isFrozen = no;
// ES5 15.2.3.13
if (!Object.isExtensible) Object.isExtensible = yes;
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+/, "").replace(/\s+$/, "");
return this.trimLeft().trimRight();
}
}
if (!String.prototype.trimRight) {
String.prototype.trimRight = function() {
return this.replace(/\s+$/, "");
return this.replace(/[\t\v\f\s\u00a0\ufeff]+$/, "");
}
}
if (!String.prototype.trimLeft) {
String.prototype.trimRight = function() {
return this.replace(/^\s+/, "");
String.prototype.trimLeft = function() {
return this.replace(/^[\t\v\f\s\u00a0\ufeff]+/, "");
}
}
@ -4101,10 +4099,7 @@ var Editor =function(renderer, session) {
this.$mouseHandler = new MouseHandler(this);
}
this.$selectionMarker = null;
this.$highlightLineMarker = null;
this.$blockScrolling = 0;
this.$search = new Search().set({
wrap: true
});
@ -4158,6 +4153,8 @@ var Editor =function(renderer, session) {
this.session.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.session.removeEventListener("changeWrapLimit", this.$onDocumentChangeWrapLimit);
this.session.removeEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.session.removeEventListener("changeFrontMarker", this.$onChangeFrontMarker);
this.session.removeEventListener("changeBackMarker", this.$onChangeBackMarker);
this.session.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.session.removeEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
@ -4186,6 +4183,12 @@ var Editor =function(renderer, session) {
this.$onDocumentChangeWrapMode = this.onDocumentChangeWrapMode.bind(this);
session.addEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
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.$onDocumentChangeBreakpoint = this.onDocumentChangeBreakpoint.bind(this);
this.session.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
@ -4206,6 +4209,8 @@ var Editor =function(renderer, session) {
this.onCursorChange();
this.onSelectionChange();
this.onChangeFrontMarker();
this.onChangeBackMarker();
this.onDocumentChangeBreakpoint();
this.onDocumentChangeAnnotation();
this.renderer.scrollToRow(session.getScrollTopRow());
@ -4243,7 +4248,7 @@ var Editor =function(renderer, session) {
this.$highlightBrackets = function() {
if (this.$bracketHighlight) {
this.renderer.removeMarker(this.$bracketHighlight);
this.session.removeMarker(this.$bracketHighlight);
this.$bracketHighlight = null;
}
@ -4260,7 +4265,7 @@ var Editor =function(renderer, session) {
var pos = self.session.findMatchingBracket(self.getCursorPosition());
if (pos) {
var range = new Range(pos.row, pos.column, pos.row, pos.column+1);
self.$bracketHighlight = self.renderer.addMarker(range, "ace_bracket");
self.$bracketHighlight = self.session.addMarker(range, "ace_bracket");
}
}, 10);
};
@ -4328,33 +4333,45 @@ var Editor =function(renderer, session) {
};
this.$updateHighlightActiveLine = function() {
if (this.$highlightLineMarker) {
this.renderer.removeMarker(this.$highlightLineMarker);
var session = this.getSession();
if (session.$highlightLineMarker) {
session.removeMarker(session.$highlightLineMarker);
}
this.$highlightLineMarker = null;
session.$highlightLineMarker = null;
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
var cursor = this.getCursorPosition();
var range = new Range(cursor.row, 0, cursor.row+1, 0);
this.$highlightLineMarker = this.renderer.addMarker(range, "ace_active_line", "line");
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "line");
}
};
this.onSelectionChange = function(e) {
if (this.$selectionMarker) {
this.renderer.removeMarker(this.$selectionMarker);
var session = this.getSession();
if (session.$selectionMarker) {
session.removeMarker(session.$selectionMarker);
}
this.$selectionMarker = null;
session.$selectionMarker = null;
if (!this.selection.isEmpty()) {
var range = this.selection.getRange();
var style = this.getSelectionStyle();
this.$selectionMarker = this.renderer.addMarker(range, "ace_selection", style);
session.$selectionMarker = session.addMarker(range, "ace_selection", style);
}
this.onCursorChange(e);
};
this.onChangeFrontMarker = function() {
this.renderer.updateFrontMarkers();
};
this.onChangeBackMarker = function() {
this.renderer.updateBackMarkers();
};
this.onDocumentChangeBreakpoint = function() {
this.renderer.setBreakpoints(this.session.getBreakpoints());
};
@ -4435,6 +4452,8 @@ var Editor =function(renderer, session) {
var lineIndent = this.mode.getNextLineIndent(lineState, line.slice(0, cursor.column), this.session.getTabString());
var end = this.session.insert(cursor, text);
this.moveCursorToPosition(end);
var lineState = this.bgTokenizer.getState(cursor.row);
// multi line insert
if (cursor.row !== end.row) {
@ -4465,14 +4484,14 @@ var Editor =function(renderer, session) {
outdent -= size;
else if (line.charAt(i) == ' ')
outdent -= 1;
this.session.replace(new Range(row, 0, row, line.length), line.substr(i));
this.session.remove(new Range(row, 0, row, i));
}
this.session.indentRows(cursor.row + 1, end.row, lineIndent);
} else {
if (shouldOutdent) {
this.mode.autoOutdent(lineState, this.session, cursor.row);
}
}
};
}
this.onTextInput = function(text) {
@ -4594,7 +4613,90 @@ var Editor =function(renderer, session) {
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeWordRight = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordRight();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeWordLeft = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordLeft();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineStart = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLineStart();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineEnd = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLineEnd();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.splitLine = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
this.session.remove(this.getSelectionRange());
this.clearSelection();
}
var cursor = this.getCursorPosition();
this.insert("\n");
this.moveCursorToPosition(cursor);
};
this.transposeLetters = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
return;
}
var cursor = this.getCursorPosition();
var column = cursor.column;
if (column == 0)
return;
var line = this.session.getLine(cursor.row);
if (column < line.length) {
var swap = line.charAt(column) + line.charAt(column-1);
var range = new Range(cursor.row, column-1, cursor.row, column+1)
}
else {
var swap = line.charAt(column-1) + line.charAt(column-2);
var range = new Range(cursor.row, column-2, cursor.row, column)
}
this.session.replace(range, swap);
};
this.indent = function() {
if (this.$readOnly)
return;
@ -4799,6 +4901,15 @@ var Editor =function(renderer, session) {
this.renderer.scrollToRow(row);
};
this.scrollToLine = function(line, center) {
this.renderer.scrollToLine(line, center);
};
this.centerSelection = function() {
var range = this.getSelectionRange();
var line = Math.floor(range.start.row + (range.end.row - range.start.row) / 2);
this.renderer.scrollToLine(line, true);
};
this.getCursorPosition = function() {
return this.selection.getCursor();
@ -4836,7 +4947,7 @@ var Editor =function(renderer, session) {
this.$blockScrolling -= 1;
if (!this.isRowVisible(this.getCursorPosition().row)) {
this.scrollToRow(lineNumber - 1 - Math.floor(this.getVisibleRowCount() / 2));
this.scrollToLine(lineNumber, true);
}
},
@ -4934,13 +5045,16 @@ var Editor =function(renderer, session) {
if (!ranges.length)
return;
var selection = this.getSelectionRange();
this.clearSelection();
this.selection.moveCursorTo(0, 0);
this.$blockScrolling += 1;
for (var i = ranges.length - 1; i >= 0; --i)
this.$tryReplace(ranges[i], replacement);
if (ranges[0] !== null)
this.selection.setSelectionRange(ranges[0]);
this.selection.setSelectionRange(selection);
this.$blockScrolling -= 1;
},
this.$tryReplace = function(range, replacement) {
@ -5554,11 +5668,11 @@ if (window.pageYOffset !== undefined) {
}
else {
exports.getPageScrollTop = function() {
return ocument.body.scrollTop;
return document.body.scrollTop;
};
exports.getPageScrollLeft = function() {
return ocument.body.scrollLeft;
return document.body.scrollLeft;
};
}
@ -5783,7 +5897,6 @@ var TextInput = function(parentNode, host) {
setTimeout(function () {
sendText();
}, 0);
};
var onCut = function(e) {
@ -5798,7 +5911,6 @@ var TextInput = function(parentNode, host) {
setTimeout(function () {
sendText();
}, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
@ -5832,8 +5944,29 @@ var TextInput = function(parentNode, host) {
event.addListener(text, "propertychange", onTextInput);
};
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
if (useragent.isIE) {
event.addListener(text, "beforecopy", function(e) {
var copyText = host.getCopyText();
if(copyText)
clipboardData.setData("Text", copyText);
else
e.preventDefault();
});
event.addListener(parentNode, "keydown", function(e) {
if (e.ctrlKey && e.keyCode == 88) {
var copyText = host.getCopyText();
if (copyText) {
clipboardData.setData("Text", copyText);
host.onCut();
}
event.preventDefault(e)
}
});
}
else {
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
}
event.addListener(text, "compositionstart", onCompositionStart);
if (useragent.isGecko) {
@ -6339,37 +6472,44 @@ exports.bindings = {
"selecttostart": "Command-Shift-Up",
"gotostart": "Command-Home|Command-Up",
"selectup": "Shift-Up",
"golineup": "Up",
"golineup": "Up|Ctrl-P",
"copylinesdown": "Command-Option-Down",
"movelinesdown": "Option-Down",
"selecttoend": "Command-Shift-Down",
"gotoend": "Command-End|Command-Down",
"selectdown": "Shift-Down",
"golinedown": "Down",
"golinedown": "Down|Ctrl-N",
"selectwordleft": "Option-Shift-Left",
"gotowordleft": "Option-Left",
"selecttolinestart": "Command-Shift-Left",
"gotolinestart": "Command-Left|Home",
"gotolinestart": "Command-Left|Home|Ctrl-A",
"selectleft": "Shift-Left",
"gotoleft": "Left",
"gotoleft": "Left|Ctrl-B",
"selectwordright": "Option-Shift-Right",
"gotowordright": "Option-Right",
"selecttolineend": "Command-Shift-Right",
"gotolineend": "Command-Right|End",
"gotolineend": "Command-Right|End|Ctrl-E",
"selectright": "Shift-Right",
"gotoright": "Right",
"gotoright": "Right|Ctrl-F",
"selectpagedown": "Shift-PageDown",
"pagedown": "PageDown",
"gotopagedown": "Option-PageDown",
"gotopagedown": "Option-PageDown|Ctrl-V",
"selectpageup": "Shift-PageUp",
"pageup": "PageUp",
"gotopageup": "Option-PageUp",
"selectlinestart": "Shift-Home",
"selectlineend": "Shift-End",
"del": "Delete",
"backspace": "Ctrl-Backspace|Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
"del": "Delete|Ctrl-D",
"backspace": "Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H",
"removetolineend": "Ctrl-K",
"removetolinestart": "Option-Backspace",
"removewordleft": "Alt-Backspace|Ctrl-Alt-Backspace",
"removewordright": "Alt-Delete",
"outdent": "Shift-Tab",
"indent": "Tab"
"indent": "Tab",
"transposeletters": "Ctrl-T",
"splitline": "Ctrl-O",
"centerselection": "Ctrl-L"
};
});/* ***** BEGIN LICENSE BLOCK *****
@ -6704,6 +6844,22 @@ canon.addCommand({
name: "backspace",
exec: function(env, args, request) { env.editor.removeLeft(); }
});
canon.addCommand({
name: "removetolinestart",
exec: function(env, args, request) { env.editor.removeToLineStart(); }
});
canon.addCommand({
name: "removetolineend",
exec: function(env, args, request) { env.editor.removeToLineEnd(); }
});
canon.addCommand({
name: "removewordleft",
exec: function(env, args, request) { env.editor.removeWordLeft(); }
});
canon.addCommand({
name: "removewordright",
exec: function(env, args, request) { env.editor.removeWordRight(); }
});
canon.addCommand({
name: "outdent",
exec: function(env, args, request) { env.editor.blockOutdent(); }
@ -6715,10 +6871,22 @@ canon.addCommand({
canon.addCommand({
name: "inserttext",
exec: function(env, args, request) {
env.editor.insert(lang.stringRepeat(args.text || "",
args.times || 1));
env.editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
}
});
canon.addCommand({
name: "centerselection",
exec: function(env, args, request) { env.editor.centerSelection(); }
});
canon.addCommand({
name: "splitline",
exec: function(env, args, request) { env.editor.splitLine(); }
});
canon.addCommand({
name: "transposeletters",
exec: function(env, args, request) { env.editor.transposeLetters(); }
});
});
/* ***** BEGIN LICENSE BLOCK *****
@ -6773,6 +6941,9 @@ var NO_CHANGE_DELTAS = {};
var EditSession = function(text, mode) {
this.$modified = true;
this.$breakpoints = [];
this.$frontMarkers = {};
this.$backMarkers = {};
this.$markerId = 1;
this.$wrapData = [];
this.listeners = [];
@ -6927,6 +7098,44 @@ var EditSession = function(text, mode) {
return this.$breakpoints;
};
this.addMarker = function(range, clazz, type, inFront) {
var id = this.$markerId++;
var marker = {
range : range,
type : type || "line",
renderer: typeof type == "function" ? type : null,
clazz : clazz,
inFront: !!inFront
}
if (inFront) {
this.$frontMarkers[id] = marker;
this._dispatchEvent("changeFrontMarker")
} else {
this.$backMarkers[id] = marker;
this._dispatchEvent("changeBackMarker")
}
return id;
};
this.removeMarker = function(markerId) {
var marker = this.$frontMarkers[markerId] || this.$backMarkers[markerId];
if (!marker)
return;
var markers = marker.inFront ? this.$frontMarkers : this.$backMarkers;
if (marker) {
delete (markers[markerId]);
this._dispatchEvent(marker.inFront ? "changeFrontMarker" : "changeBackMarker");
}
};
this.getMarkers = function(inFront) {
return inFront ? this.$frontMarkers : this.$backMarkers;
};
/**
* Error:
* {
@ -7833,6 +8042,10 @@ var EditSession = function(text, mode) {
column: column
};
}
var rowData = this.$documentToScreenRow(row, column);
var screenRow = rowData[0];
if (row >= this.getLength()) {
return {
row: screenRow,
@ -7842,11 +8055,8 @@ var EditSession = function(text, mode) {
var split;
var wrapRowData = this.$wrapData[row];
var screenRow, screenRowOffset;
var screenColumn;
var rowData = this.$documentToScreenRow(row, column);
screenRow = rowData[0];
screenRowOffset = rowData[1];
var screenRowOffset = rowData[1];
str = this.getLine(row).substring(
wrapRowData[screenRowOffset - 1] || 0, column);
@ -7873,8 +8083,7 @@ var EditSession = function(text, mode) {
}).call(EditSession.prototype);
exports.EditSession = EditSession;
});
/* ***** BEGIN LICENSE BLOCK *****
});/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
@ -7929,10 +8138,12 @@ var Selection = function(session) {
this.selectionAnchor = new Anchor(this.doc, 0, 0);
var _self = this;
this.selectionLead.on("change", function() {
this.selectionLead.on("change", function(e) {
_self._dispatchEvent("changeCursor");
if (!_self.$isEmpty)
_self._dispatchEvent("changeSelection");
if (e.old.row == e.value.row)
_self.$updateDesiredColumn();
});
this.selectionAnchor.on("change", function() {
@ -8052,9 +8263,7 @@ var Selection = function(session) {
this.$updateDesiredColumn = function() {
var cursor = this.getCursor();
if (cursor) {
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
}
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
};
this.$moveSelection = function(mover) {
@ -8595,9 +8804,17 @@ var Anchor = exports.Anchor = function(doc, row, column) {
if (this.row == pos.row && this.column == pos.column)
return;
var old = {
row: this.row,
column: this.column
};
this.row = pos.row;
this.column = pos.column;
this._dispatchEvent("change");
this._dispatchEvent("change", {
old: old,
value: pos
});
};
this.detach = function() {
@ -8789,7 +9006,7 @@ var Tokenizer = function(rules) {
var value = match[0];
for ( var i = 0; i < state.length; i++) {
if (match[i + 1] !== undefined) {
if (match[i + 1]) {
if (typeof state[i].token == "function") {
type = state[i].token(match[0]);
}
@ -8823,10 +9040,10 @@ var Tokenizer = function(rules) {
}
if (lastIndex == line.length) {
break;
}
break;
}
lastIndex = re.lastIndex;
lastIndex = re.lastIndex;
};
if (token.type) {
@ -10095,19 +10312,19 @@ var VirtualRenderer = function(container, theme) {
this.scroller.appendChild(this.content);
this.$gutterLayer = new GutterLayer(this.$gutter);
this.$markerLayer = new MarkerLayer(this.content);
this.$markerBack = new MarkerLayer(this.content);
var textLayer = this.$textLayer = new TextLayer(this.content);
this.canvas = textLayer.element;
this.$markerFront = new MarkerLayer(this.content);
this.characterWidth = textLayer.getCharacterWidth();
this.lineHeight = textLayer.getLineHeight();
this.$cursorLayer = new CursorLayer(this.content);
this.$cursorPadding = 8;
this.layers = [ this.$markerLayer, textLayer, this.$cursorLayer ];
this.scrollBar = new ScrollBar(container);
this.scrollBar.addEventListener("scroll", this.onScroll.bind(this));
@ -10153,14 +10370,17 @@ var VirtualRenderer = function(container, theme) {
this.CHANGE_LINES = 16;
this.CHANGE_TEXT = 32;
this.CHANGE_SIZE = 64;
this.CHANGE_FULL = 128;
this.CHANGE_MARKER_BACK = 128;
this.CHANGE_MARKER_FRONT = 256;
this.CHANGE_FULL = 512;
oop.implement(this, EventEmitter);
this.setSession = function(session) {
this.session = session;
this.$cursorLayer.setSession(session);
this.$markerLayer.setSession(session);
this.$markerBack.setSession(session);
this.$markerFront.setSession(session);
this.$gutterLayer.setSession(session);
this.$textLayer.setSession(session);
this.$loop.schedule(this.CHANGE_FULL);
@ -10232,7 +10452,8 @@ var VirtualRenderer = function(container, theme) {
this.scroller.style.width = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()) + "px";
if (this.session.getUseWrapMode()) {
var limit = Math.floor(this.scroller.clientWidth / this.characterWidth);
var availableWidth = this.scroller.clientWidth - this.$padding * 2;
var limit = Math.floor(availableWidth / this.characterWidth) - 1;
if (this.session.adjustWrapLimit(limit) || force) {
changes = changes | this.CHANGE_FULL;
}
@ -10403,7 +10624,8 @@ var VirtualRenderer = function(container, theme) {
if (changes & this.CHANGE_FULL) {
this.$textLayer.update(this.layerConfig);
this.showGutter && this.$gutterLayer.update(this.layerConfig);
this.$markerLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$updateScrollBar();
this.scrollCursorIntoView();
@ -10417,7 +10639,8 @@ var VirtualRenderer = function(container, theme) {
else
this.$textLayer.scrollLines(this.layerConfig);
this.showGutter && this.$gutterLayer.update(this.layerConfig);
this.$markerLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$updateScrollBar();
return;
@ -10438,8 +10661,12 @@ var VirtualRenderer = function(container, theme) {
if (changes & this.CHANGE_CURSOR)
this.$cursorLayer.update(this.layerConfig);
if (changes & this.CHANGE_MARKER) {
this.$markerLayer.update(this.layerConfig);
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
this.$markerFront.update(this.layerConfig);
}
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) {
this.$markerBack.update(this.layerConfig);
}
if (changes & this.CHANGE_SIZE)
@ -10524,15 +10751,14 @@ var VirtualRenderer = function(container, theme) {
return Math.max(this.$size.scrollerWidth - this.$padding * 2, Math.round(charCount * this.characterWidth));
};
this.addMarker = function(range, clazz, type) {
var id = this.$markerLayer.addMarker(range, clazz, type);
this.$loop.schedule(this.CHANGE_MARKER);
return id;
this.updateFrontMarkers = function() {
this.$markerFront.setMarkers(this.session.getMarkers(true));
this.$loop.schedule(this.CHANGE_MARKER_FRONT);
};
this.removeMarker = function(markerId) {
this.$markerLayer.removeMarker(markerId);
this.$loop.schedule(this.CHANGE_MARKER);
this.updateBackMarkers = function() {
this.$markerBack.setMarkers(this.session.getMarkers());
this.$loop.schedule(this.CHANGE_MARKER_BACK);
};
this.addGutterDecoration = function(row, className){
@ -10612,6 +10838,19 @@ var VirtualRenderer = function(container, theme) {
this.scrollToY(row * this.lineHeight);
};
this.scrollToLine = function(line, center) {
var lineHeight = { lineHeight: this.lineHeight };
var offset = 0;
for (var l = 1; l < line; l++) {
offset += this.session.getRowHeight(lineHeight, l-1);
}
if (center) {
offset -= this.$size.scrollerHeight / 2;
}
this.scrollToY(offset);
};
this.scrollToY = function(scrollTop) {
var maxHeight = this.session.getScreenLength() * this.lineHeight - this.$size.scrollerHeight;
var scrollTop = Math.max(0, Math.min(maxHeight, scrollTop));
@ -10914,9 +11153,6 @@ var Marker = function(parentEl) {
this.element = document.createElement("div");
this.element.className = "ace_layer ace_marker-layer";
parentEl.appendChild(this.element);
this.markers = {};
this.$markerId = 1;
};
(function() {
@ -10924,23 +11160,9 @@ var Marker = function(parentEl) {
this.setSession = function(session) {
this.session = session;
};
this.addMarker = function(range, clazz, type) {
var id = this.$markerId++;
this.markers[id] = {
range : range,
type : type || "line",
clazz : clazz
};
return id;
};
this.removeMarker = function(markerId) {
var marker = this.markers[markerId];
if (marker) {
delete (this.markers[markerId]);
}
this.setMarkers = function(markers) {
this.markers = markers;
};
this.update = function(config) {
@ -10950,7 +11172,7 @@ var Marker = function(parentEl) {
this.config = config;
var html = [];
var html = [];
for ( var key in this.markers) {
var marker = this.markers[key];
@ -10959,7 +11181,12 @@ var Marker = function(parentEl) {
range = range.toScreenRange(this.session);
if (range.isMultiLine()) {
if (marker.renderer) {
var top = this.$getTop(range.start.row, config);
var left = Math.round(range.start.column * config.characterWidth);
marker.renderer(html, range, left, top, config);
}
else if (range.isMultiLine()) {
if (marker.type == "text") {
this.drawTextMarker(html, range, marker.clazz, config);
} else {
@ -12387,6 +12614,22 @@ define("text!styles.css", "html {" +
" background: white;" +
"}" +
"" +
".cool {" +
" position: absolute;" +
" background: orange;" +
" opacity: 0.8;" +
"}" +
"" +
".cool_header {" +
" position: absolute;" +
" background: orange;" +
" color: black;" +
" font-size: 8px;" +
" padding: 1px;" +
" margin-top: -8px;" +
" opacity: 0.8;" +
"}" +
"" +
"#controls {" +
" width: 100%;" +
"}" +

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -138,9 +138,17 @@ var Anchor = exports.Anchor = function(doc, row, column) {
if (this.row == pos.row && this.column == pos.column)
return;
var old = {
row: this.row,
column: this.column
};
this.row = pos.row;
this.column = pos.column;
this._dispatchEvent("change");
this._dispatchEvent("change", {
old: old,
value: pos
});
};
this.detach = function() {

View file

@ -242,6 +242,22 @@ canon.addCommand({
name: "backspace",
exec: function(env, args, request) { env.editor.removeLeft(); }
});
canon.addCommand({
name: "removetolinestart",
exec: function(env, args, request) { env.editor.removeToLineStart(); }
});
canon.addCommand({
name: "removetolineend",
exec: function(env, args, request) { env.editor.removeToLineEnd(); }
});
canon.addCommand({
name: "removewordleft",
exec: function(env, args, request) { env.editor.removeWordLeft(); }
});
canon.addCommand({
name: "removewordright",
exec: function(env, args, request) { env.editor.removeWordRight(); }
});
canon.addCommand({
name: "outdent",
exec: function(env, args, request) { env.editor.blockOutdent(); }
@ -256,5 +272,18 @@ canon.addCommand({
env.editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
}
});
canon.addCommand({
name: "centerselection",
exec: function(env, args, request) { env.editor.centerSelection(); }
});
canon.addCommand({
name: "splitline",
exec: function(env, args, request) { env.editor.splitLine(); }
});
canon.addCommand({
name: "transposeletters",
exec: function(env, args, request) { env.editor.transposeLetters(); }
});
});

View file

@ -50,6 +50,9 @@ var NO_CHANGE_DELTAS = {};
var EditSession = function(text, mode) {
this.$modified = true;
this.$breakpoints = [];
this.$frontMarkers = {};
this.$backMarkers = {};
this.$markerId = 1;
this.$wrapData = [];
this.listeners = [];
@ -204,6 +207,44 @@ var EditSession = function(text, mode) {
return this.$breakpoints;
};
this.addMarker = function(range, clazz, type, inFront) {
var id = this.$markerId++;
var marker = {
range : range,
type : type || "line",
renderer: typeof type == "function" ? type : null,
clazz : clazz,
inFront: !!inFront
}
if (inFront) {
this.$frontMarkers[id] = marker;
this._dispatchEvent("changeFrontMarker")
} else {
this.$backMarkers[id] = marker;
this._dispatchEvent("changeBackMarker")
}
return id;
};
this.removeMarker = function(markerId) {
var marker = this.$frontMarkers[markerId] || this.$backMarkers[markerId];
if (!marker)
return;
var markers = marker.inFront ? this.$frontMarkers : this.$backMarkers;
if (marker) {
delete (markers[markerId]);
this._dispatchEvent(marker.inFront ? "changeFrontMarker" : "changeBackMarker");
}
};
this.getMarkers = function(inFront) {
return inFront ? this.$frontMarkers : this.$backMarkers;
};
/**
* Error:
* {
@ -1110,6 +1151,10 @@ var EditSession = function(text, mode) {
column: column
};
}
var rowData = this.$documentToScreenRow(row, column);
var screenRow = rowData[0];
if (row >= this.getLength()) {
return {
row: screenRow,
@ -1119,11 +1164,8 @@ var EditSession = function(text, mode) {
var split;
var wrapRowData = this.$wrapData[row];
var screenRow, screenRowOffset;
var screenColumn;
var rowData = this.$documentToScreenRow(row, column);
screenRow = rowData[0];
screenRowOffset = rowData[1];
var screenRowOffset = rowData[1];
str = this.getLine(row).substring(
wrapRowData[screenRowOffset - 1] || 0, column);
@ -1150,4 +1192,4 @@ var EditSession = function(text, mode) {
}).call(EditSession.prototype);
exports.EditSession = EditSession;
});
});

View file

@ -71,10 +71,7 @@ var Editor =function(renderer, session) {
this.$mouseHandler = new MouseHandler(this);
}
this.$selectionMarker = null;
this.$highlightLineMarker = null;
this.$blockScrolling = 0;
this.$search = new Search().set({
wrap: true
});
@ -128,6 +125,8 @@ var Editor =function(renderer, session) {
this.session.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.session.removeEventListener("changeWrapLimit", this.$onDocumentChangeWrapLimit);
this.session.removeEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.session.removeEventListener("changeFrontMarker", this.$onChangeFrontMarker);
this.session.removeEventListener("changeBackMarker", this.$onChangeBackMarker);
this.session.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.session.removeEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
@ -156,6 +155,12 @@ var Editor =function(renderer, session) {
this.$onDocumentChangeWrapMode = this.onDocumentChangeWrapMode.bind(this);
session.addEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
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.$onDocumentChangeBreakpoint = this.onDocumentChangeBreakpoint.bind(this);
this.session.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
@ -176,6 +181,8 @@ var Editor =function(renderer, session) {
this.onCursorChange();
this.onSelectionChange();
this.onChangeFrontMarker();
this.onChangeBackMarker();
this.onDocumentChangeBreakpoint();
this.onDocumentChangeAnnotation();
this.renderer.scrollToRow(session.getScrollTopRow());
@ -213,7 +220,7 @@ var Editor =function(renderer, session) {
this.$highlightBrackets = function() {
if (this.$bracketHighlight) {
this.renderer.removeMarker(this.$bracketHighlight);
this.session.removeMarker(this.$bracketHighlight);
this.$bracketHighlight = null;
}
@ -230,7 +237,7 @@ var Editor =function(renderer, session) {
var pos = self.session.findMatchingBracket(self.getCursorPosition());
if (pos) {
var range = new Range(pos.row, pos.column, pos.row, pos.column+1);
self.$bracketHighlight = self.renderer.addMarker(range, "ace_bracket");
self.$bracketHighlight = self.session.addMarker(range, "ace_bracket");
}
}, 10);
};
@ -298,33 +305,45 @@ var Editor =function(renderer, session) {
};
this.$updateHighlightActiveLine = function() {
if (this.$highlightLineMarker) {
this.renderer.removeMarker(this.$highlightLineMarker);
var session = this.getSession();
if (session.$highlightLineMarker) {
session.removeMarker(session.$highlightLineMarker);
}
this.$highlightLineMarker = null;
session.$highlightLineMarker = null;
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
var cursor = this.getCursorPosition();
var range = new Range(cursor.row, 0, cursor.row+1, 0);
this.$highlightLineMarker = this.renderer.addMarker(range, "ace_active_line", "line");
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "line");
}
};
this.onSelectionChange = function(e) {
if (this.$selectionMarker) {
this.renderer.removeMarker(this.$selectionMarker);
var session = this.getSession();
if (session.$selectionMarker) {
session.removeMarker(session.$selectionMarker);
}
this.$selectionMarker = null;
session.$selectionMarker = null;
if (!this.selection.isEmpty()) {
var range = this.selection.getRange();
var style = this.getSelectionStyle();
this.$selectionMarker = this.renderer.addMarker(range, "ace_selection", style);
session.$selectionMarker = session.addMarker(range, "ace_selection", style);
}
this.onCursorChange(e);
};
this.onChangeFrontMarker = function() {
this.renderer.updateFrontMarkers();
};
this.onChangeBackMarker = function() {
this.renderer.updateBackMarkers();
};
this.onDocumentChangeBreakpoint = function() {
this.renderer.setBreakpoints(this.session.getBreakpoints());
};
@ -405,6 +424,8 @@ var Editor =function(renderer, session) {
var lineIndent = this.mode.getNextLineIndent(lineState, line.slice(0, cursor.column), this.session.getTabString());
var end = this.session.insert(cursor, text);
this.moveCursorToPosition(end);
var lineState = this.bgTokenizer.getState(cursor.row);
// multi line insert
if (cursor.row !== end.row) {
@ -435,14 +456,14 @@ var Editor =function(renderer, session) {
outdent -= size;
else if (line.charAt(i) == ' ')
outdent -= 1;
this.session.replace(new Range(row, 0, row, line.length), line.substr(i));
this.session.remove(new Range(row, 0, row, i));
}
this.session.indentRows(cursor.row + 1, end.row, lineIndent);
} else {
if (shouldOutdent) {
this.mode.autoOutdent(lineState, this.session, cursor.row);
}
}
};
}
this.onTextInput = function(text) {
@ -564,7 +585,90 @@ var Editor =function(renderer, session) {
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeWordRight = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordRight();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeWordLeft = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectWordLeft();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineStart = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLineStart();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.removeToLineEnd = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLineEnd();
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.splitLine = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
this.session.remove(this.getSelectionRange());
this.clearSelection();
}
var cursor = this.getCursorPosition();
this.insert("\n");
this.moveCursorToPosition(cursor);
};
this.transposeLetters = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
return;
}
var cursor = this.getCursorPosition();
var column = cursor.column;
if (column == 0)
return;
var line = this.session.getLine(cursor.row);
if (column < line.length) {
var swap = line.charAt(column) + line.charAt(column-1);
var range = new Range(cursor.row, column-1, cursor.row, column+1)
}
else {
var swap = line.charAt(column-1) + line.charAt(column-2);
var range = new Range(cursor.row, column-2, cursor.row, column)
}
this.session.replace(range, swap);
};
this.indent = function() {
if (this.$readOnly)
return;
@ -772,6 +876,12 @@ var Editor =function(renderer, session) {
this.scrollToLine = function(line, center) {
this.renderer.scrollToLine(line, center);
};
this.centerSelection = function() {
var range = this.getSelectionRange();
var line = Math.floor(range.start.row + (range.end.row - range.start.row) / 2);
this.renderer.scrollToLine(line, true);
};
this.getCursorPosition = function() {
return this.selection.getCursor();
@ -907,13 +1017,16 @@ var Editor =function(renderer, session) {
if (!ranges.length)
return;
var selection = this.getSelectionRange();
this.clearSelection();
this.selection.moveCursorTo(0, 0);
this.$blockScrolling += 1;
for (var i = ranges.length - 1; i >= 0; --i)
this.$tryReplace(ranges[i], replacement);
if (ranges[0] !== null)
this.selection.setSelectionRange(ranges[0]);
this.selection.setSelectionRange(selection);
this.$blockScrolling -= 1;
},
this.$tryReplace = function(range, replacement) {

View file

@ -54,37 +54,44 @@ exports.bindings = {
"selecttostart": "Command-Shift-Up",
"gotostart": "Command-Home|Command-Up",
"selectup": "Shift-Up",
"golineup": "Up",
"golineup": "Up|Ctrl-P",
"copylinesdown": "Command-Option-Down",
"movelinesdown": "Option-Down",
"selecttoend": "Command-Shift-Down",
"gotoend": "Command-End|Command-Down",
"selectdown": "Shift-Down",
"golinedown": "Down",
"golinedown": "Down|Ctrl-N",
"selectwordleft": "Option-Shift-Left",
"gotowordleft": "Option-Left",
"selecttolinestart": "Command-Shift-Left",
"gotolinestart": "Command-Left|Home",
"gotolinestart": "Command-Left|Home|Ctrl-A",
"selectleft": "Shift-Left",
"gotoleft": "Left",
"gotoleft": "Left|Ctrl-B",
"selectwordright": "Option-Shift-Right",
"gotowordright": "Option-Right",
"selecttolineend": "Command-Shift-Right",
"gotolineend": "Command-Right|End",
"gotolineend": "Command-Right|End|Ctrl-E",
"selectright": "Shift-Right",
"gotoright": "Right",
"gotoright": "Right|Ctrl-F",
"selectpagedown": "Shift-PageDown",
"pagedown": "PageDown",
"gotopagedown": "Option-PageDown",
"gotopagedown": "Option-PageDown|Ctrl-V",
"selectpageup": "Shift-PageUp",
"pageup": "PageUp",
"gotopageup": "Option-PageUp",
"selectlinestart": "Shift-Home",
"selectlineend": "Shift-End",
"del": "Delete",
"backspace": "Ctrl-Backspace|Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
"del": "Delete|Ctrl-D",
"backspace": "Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H",
"removetolineend": "Ctrl-K",
"removetolinestart": "Option-Backspace",
"removewordleft": "Alt-Backspace|Ctrl-Alt-Backspace",
"removewordright": "Alt-Delete",
"outdent": "Shift-Tab",
"indent": "Tab"
"indent": "Tab",
"transposeletters": "Ctrl-T",
"splitline": "Ctrl-O",
"centerselection": "Ctrl-L"
};
});

View file

@ -114,7 +114,6 @@ var TextInput = function(parentNode, host) {
setTimeout(function () {
sendText();
}, 0);
};
var onCut = function(e) {
@ -129,7 +128,6 @@ var TextInput = function(parentNode, host) {
setTimeout(function () {
sendText();
}, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
@ -163,8 +161,29 @@ var TextInput = function(parentNode, host) {
event.addListener(text, "propertychange", onTextInput);
};
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
if (useragent.isIE) {
event.addListener(text, "beforecopy", function(e) {
var copyText = host.getCopyText();
if(copyText)
clipboardData.setData("Text", copyText);
else
e.preventDefault();
});
event.addListener(parentNode, "keydown", function(e) {
if (e.ctrlKey && e.keyCode == 88) {
var copyText = host.getCopyText();
if (copyText) {
clipboardData.setData("Text", copyText);
host.onCut();
}
event.preventDefault(e)
}
});
}
else {
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
}
event.addListener(text, "compositionstart", onCompositionStart);
if (useragent.isGecko) {

View file

@ -45,9 +45,6 @@ var Marker = function(parentEl) {
this.element = document.createElement("div");
this.element.className = "ace_layer ace_marker-layer";
parentEl.appendChild(this.element);
this.markers = {};
this.$markerId = 1;
};
(function() {
@ -55,23 +52,9 @@ var Marker = function(parentEl) {
this.setSession = function(session) {
this.session = session;
};
this.addMarker = function(range, clazz, type) {
var id = this.$markerId++;
this.markers[id] = {
range : range,
type : type || "line",
clazz : clazz
};
return id;
};
this.removeMarker = function(markerId) {
var marker = this.markers[markerId];
if (marker) {
delete (this.markers[markerId]);
}
this.setMarkers = function(markers) {
this.markers = markers;
};
this.update = function(config) {
@ -81,7 +64,7 @@ var Marker = function(parentEl) {
this.config = config;
var html = [];
var html = [];
for ( var key in this.markers) {
var marker = this.markers[key];
@ -90,7 +73,12 @@ var Marker = function(parentEl) {
range = range.toScreenRange(this.session);
if (range.isMultiLine()) {
if (marker.renderer) {
var top = this.$getTop(range.start.row, config);
var left = Math.round(range.start.column * config.characterWidth);
marker.renderer(html, range, left, top, config);
}
else if (range.isMultiLine()) {
if (marker.type == "text") {
this.drawTextMarker(html, range, marker.clazz, config);
} else {

View file

@ -53,10 +53,12 @@ var Selection = function(session) {
this.selectionAnchor = new Anchor(this.doc, 0, 0);
var _self = this;
this.selectionLead.on("change", function() {
this.selectionLead.on("change", function(e) {
_self._dispatchEvent("changeCursor");
if (!_self.$isEmpty)
_self._dispatchEvent("changeSelection");
if (e.old.row == e.value.row)
_self.$updateDesiredColumn();
});
this.selectionAnchor.on("change", function() {
@ -176,9 +178,7 @@ var Selection = function(session) {
this.$updateDesiredColumn = function() {
var cursor = this.getCursor();
if (cursor) {
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
}
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
};
this.$moveSelection = function(mover) {

View file

@ -37,6 +37,7 @@
require("../../../support/paths");
require("./mockdom");
var async = require("asyncjs");
async.concat(

View file

@ -0,0 +1,75 @@
define(function(require, exports, module) {
require("pilot/fixoldbrowsers");
var async = require("asyncjs");
var dom = require("pilot/dom");
var passed = 0
var failed = 0
var log = document.getElementById("log")
async.concat(
require("./anchor_test"),
require("./change_document_test"),
require("./document_test"),
require("./edit_session_test"),
require("./event_emitter_test"),
require("./navigation_test"),
require("./range_test"),
require("./search_test"),
require("./selection_test"),
require("./text_edit_test"),
require("./virtual_renderer_test"),
require("./mode/css_test"),
require("./mode/css_tokenizer_test"),
require("./mode/html_test"),
require("./mode/html_tokenizer_test"),
require("./mode/javascript_test"),
require("./mode/javascript_tokenizer_test"),
require("./mode/text_test"),
require("./mode/xml_test"),
require("./mode/xml_tokenizer_test")
)
.run()
.each(function(test, next) {
var node = document.createElement("div");
node.className = test.passed ? "passed" : "failed";
var name = test.name
if (test.suiteName)
name = test.suiteName + ": " + test.name
var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL")
if (!test.passed) {
if (test.err.stack)
var err = test.err.stack
else
var err = test.err
msg += "<pre class='error'>" + err + "</pre>";
}
node.innerHTML = msg;
log.appendChild(node);
next()
})
.each(function(test) {
if (test.passed)
passed += 1
else
failed += 1
})
.end(function() {
log.innerHTML += [
"<div class='summary'>",
"<br>",
"Summary: <br>",
"<br>",
"Total number of tests: " + (passed + failed) + "<br>",
(passed ? "Passed tests: " + passed + "<br>" : ""),
(failed ? "Failed tests: " + failed + "<br>" : "")
].join("")
})
});

View file

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Document = require("ace/document").Document;
var Anchor = require("ace/anchor").Anchor;
var Range = require("ace/range").Range;
@ -173,7 +175,9 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
if (module === require.main) {
});
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -0,0 +1,306 @@
define(function(require, exports, module) {
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// UTILITY
var oop = require('pilot/oop');
var pSlice = Array.prototype.slice;
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = exports;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected })
assert.AssertionError = function AssertionError(options) {
this.name = 'AssertionError';
this.message = options.message;
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
}
};
oop.inherits(assert.AssertionError, Error);
assert.AssertionError.prototype.toString = function() {
if (this.message) {
return [this.name + ':', this.message].join(' ');
} else {
return [this.name + ':',
JSON.stringify(this.expected),
this.operator,
JSON.stringify(this.actual)].join(' ');
}
};
// assert.AssertionError instanceof Error
assert.AssertionError.__proto__ = Error.prototype;
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
assert.ok = function ok(value, message) {
if (!!!value) fail(value, true, message, '==', assert.ok);
};
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected)) {
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
}
};
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
if (actual.length != expected.length) return false;
for (var i = 0; i < actual.length; i++) {
if (actual[i] !== expected[i]) return false;
}
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
// 7.3. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull(value) {
return value === null || value === undefined;
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv(a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical 'prototype' property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
try {
var ka = Object.keys(a),
kb = Object.keys(b),
key, i;
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key])) return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected)) {
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
}
};
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, '!==', assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (expected instanceof RegExp) {
return expected.test(actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof expected === 'string') {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail('Missing expected exception' + message);
}
if (!shouldThrow && expectedException(actual, expected)) {
fail('Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [true].concat(pSlice.call(arguments)));
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [false].concat(pSlice.call(arguments)));
};
assert.ifError = function(err) { if (err) {throw err;}};
});

View file

@ -0,0 +1,489 @@
/*!
* async.js
* Copyright(c) 2010 Fabian Jakobs <fabian.jakobs@web.de>
* MIT Licensed
*/
define(function(require, exports, module) {
var STOP = exports.STOP = {}
exports.Generator = function(source) {
if (typeof source == "function")
this.source = {
next: source
}
else
this.source = source
}
;(function() {
this.next = function(callback) {
this.source.next(callback)
}
this.map = function(mapper) {
if (!mapper)
return this
mapper = makeAsync(1, mapper)
var source = this.source
this.next = function(callback) {
source.next(function(err, value) {
if (err)
callback(err)
else {
mapper(value, function(err, value) {
if (err)
callback(err)
else
callback(null, value)
})
}
})
}
return new this.constructor(this)
}
this.filter = function(filter) {
if (!filter)
return this
filter = makeAsync(1, filter)
var source = this.source
this.next = function(callback) {
source.next(function handler(err, value) {
if (err)
callback(err)
else {
filter(value, function(err, takeIt) {
if (err)
callback(err)
else if (takeIt)
callback(null, value)
else
source.next(handler)
})
}
})
}
return new this.constructor(this)
}
this.slice = function(begin, end) {
var count = -1
if (!end || end < 0)
var end = Infinity
var source = this.source
this.next = function(callback) {
source.next(function handler(err, value) {
count++
if (err)
callback(err)
else if (count >= begin && count < end)
callback(null, value)
else if (count >= end)
callback(STOP)
else
source.next(handler)
})
}
return new this.constructor(this)
}
this.reduce = function(reduce, initialValue) {
reduce = makeAsync(3, reduce)
var index = 0
var done = false
var previousValue = initialValue
var source = this.source
this.next = function(callback) {
if (done)
return callback(STOP)
if (initialValue === undefined) {
source.next(function(err, currentValue) {
if (err)
return callback(err, previousValue)
previousValue = currentValue
reduceAll()
})
}
else
reduceAll()
function reduceAll() {
source.next(function handler(err, currentValue) {
if (err) {
done = true
if (err == STOP)
return callback(null, previousValue)
else
return(err)
}
reduce(previousValue, currentValue, index++, function(err, value) {
previousValue = value
source.next(handler)
})
})
}
}
return new this.constructor(this)
}
this.forEach =
this.each = function(fn) {
fn = makeAsync(1, fn)
var source = this.source
this.next = function(callback) {
source.next(function handler(err, value) {
if (err)
callback(err)
else {
fn(value, function(err) {
callback(err, value)
})
}
})
}
return new this.constructor(this)
}
this.some = function(condition) {
condition = makeAsync(1, condition)
var source = this.source
var done = false
this.next = function(callback) {
if (done)
return callback(STOP)
source.next(function handler(err, value) {
if (err)
return callback(err)
condition(value, function(err, result) {
if (err) {
done = true
if (err == STOP)
callback(null, false)
else
callback(err)
}
else if (result) {
done = true
callback(null, true)
}
else
source.next(handler)
})
})
}
return new this.constructor(this)
}
this.every = function(condition) {
condition = makeAsync(1, condition)
var source = this.source
var done = false
this.next = function(callback) {
if (done)
return callback(STOP)
source.next(function handler(err, value) {
if (err)
return callback(err)
condition(value, function(err, result) {
if (err) {
done = true
if (err == STOP)
callback(null, true)
else
callback(err)
}
else if (!result) {
done = true
callback(null, false)
}
else
source.next(handler)
})
})
}
return new this.constructor(this)
}
this.call = function(context) {
var source = this.source
return this.map(function(fn, next) {
fn = makeAsync(0, fn, context)
fn.call(context, function(err, value) {
next(err, value)
})
})
}
this.concat = function(generator) {
var generators = [this]
generators.push.apply(generators, arguments)
var index = 0
var source = generators[index++]
return new this.constructor(function(callback) {
source.next(function handler(err, value) {
if (err) {
if (err == STOP) {
source = generators[index++]
if (!source)
return callback(STOP)
else
return source.next(handler)
}
else
return callback(err)
}
else
return callback(null, value)
})
})
}
this.zip = function(generator) {
var generators = [this]
generators.push.apply(generators, arguments)
return new this.constructor(function(callback) {
exports.list(generators)
.map(function(gen, next) {
gen.next(next)
})
.toArray(callback)
})
}
this.sort = function(compare) {
var self = this
var arrGen
this.next = function(callback) {
if (arrGen)
return arrGen.next(callback)
self.toArray(function(err, arr) {
if (err)
callback(err)
else {
arrGen = exports.list(arr.sort(compare))
arrGen.next(callback)
}
})
}
return new this.constructor(this)
}
this.join = function(separator) {
return this.$arrayOp(Array.prototype.join, separator !== undefined ? [separator] : null)
}
this.reverse = function() {
return this.$arrayOp(Array.prototype.reverse)
}
this.$arrayOp = function(arrayMethod, args) {
var self = this
var i = 0
this.next = function(callback) {
if (i++ > 0)
return callback(STOP)
self.toArray(function(err, arr) {
if (err)
callback(err, "")
else {
if (args)
callback(null, arrayMethod.apply(arr, args))
else
callback(null, arrayMethod.call(arr))
}
})
}
return new this.constructor(this)
}
this.end = function(breakOnError, callback) {
if (!callback) {
callback = arguments[0]
breakOnError = true
}
var source = this.source
var last
var lastError
source.next(function handler(err, value) {
if (err) {
if (err == STOP)
callback && callback(lastError, last)
else if (!breakOnError) {
lastError = err
source.next(handler)
}
else
callback && callback(err, value)
}
else {
last = value
source.next(handler)
}
})
}
this.toArray = function(breakOnError, callback) {
if (!callback) {
callback = arguments[0]
breakOnError = true
}
var values = []
var errors = []
var source = this.source
source.next(function handler(err, value) {
if (err) {
if (err == STOP) {
if (breakOnError)
return callback(null, values)
else {
errors.length = values.length
return callback(errors, values)
}
}
else {
if (breakOnError)
return callback(err)
else
errors[values.length] = err
}
}
values.push(value)
source.next(handler)
})
}
}).call(exports.Generator.prototype)
var makeAsync = exports.makeAsync = function(args, fn, context) {
if (fn.length > args)
return fn
else {
return function() {
var value
var next = arguments[args]
try {
value = fn.apply(context || this, arguments)
} catch(e) {
return next(e)
}
next(null, value)
}
}
}
exports.list = function(arr, construct) {
var construct = construct || exports.Generator
var i = 0
var len = arr.length
return new construct(function(callback) {
if (i < len)
callback(null, arr[i++])
else
callback(STOP)
})
}
exports.values = function(map, construct) {
var values = []
for (var key in map)
values.push(map[key])
return exports.list(values, construct)
}
exports.keys = function(map, construct) {
var keys = []
for (var key in map)
keys.push(key)
return exports.list(keys, construct)
}
/**
* range([start,] stop[, step]) -> generator of integers
*
* Return a generator containing an arithmetic progression of integers.
* range(i, j) returns [i, i+1, i+2, ..., j-1] start (!) defaults to 0.
* When step is given, it specifies the increment (or decrement).
*/
exports.range = function(start, stop, step, construct) {
var construct = construct || exports.Generator
start = start || 0
step = step || 1
if (stop === undefined || stop === null)
stop = step > 0 ? Infinity : -Infinity
var value = start
return new construct(function(callback) {
if (step > 0 && value >= stop || step < 0 && value <= stop)
callback(STOP)
else {
var current = value
value += step
callback(null, current)
}
})
}
exports.concat = function(first, varargs) {
if (arguments.length > 1)
return first.concat.apply(first, Array.prototype.slice.call(arguments, 1))
else
return first
}
exports.zip = function(first, varargs) {
if (arguments.length > 1)
return first.zip.apply(first, Array.prototype.slice.call(arguments, 1))
else
return first.map(function(item, next) {
next(null, [item])
})
}
exports.plugin = function(members, constructors) {
if (members) {
for (var key in members) {
exports.Generator.prototype[key] = members[key]
}
}
if (constructors) {
for (var key in constructors) {
exports[key] = constructors[key]
}
}
}
})

View file

@ -0,0 +1,12 @@
/*!
* async.js
* Copyright(c) 2010 Fabian Jakobs <fabian.jakobs@web.de>
* MIT Licensed
*/
define(function(require, exports, module) {
module.exports = require("./async")
require("./utils")
})

View file

@ -0,0 +1,195 @@
/*!
* async.js
* Copyright(c) 2010 Fabian Jakobs <fabian.jakobs@web.de>
* MIT Licensed
*/
define(function(require, exports, module) {
var oop = require("pilot/oop")
var async = require("asyncjs/async")
require("asyncjs/utils")
exports.TestGenerator = function(source) {
async.Generator.call(this, source)
}
oop.inherits(exports.TestGenerator, async.Generator)
;(function() {
this.exec = function() {
this.run().report().summary(function(err, passed) {
console.log("DONE")
})
}
this.run = function() {
return this.setupTest()
.each(function(test, next) {
if (test.setUpSuite)
test.setUpSuite(next)
else
next()
})
.each(function(test, next) {
test.test(function(err, passed) {
test.err = err
test.passed = passed
next()
})
})
.each(function(test, next) {
if (test.tearDownSuite)
test.tearDownSuite(next)
else
next()
})
}
this.report = function() {
return this.each(function(test, next) {
var color = test.passed ? "\x1b[32m" : "\x1b[31m"
var name = test.name
if (test.suiteName)
name = test.suiteName + ": " + test.name
console.log(color + "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL") + "\x1b[0m")
if (!test.passed)
if (test.err.stack)
console.log(test.err.stack)
else
console.log(test.err)
next()
})
}
this.summary = function(callback) {
var passed = 0
var failed = 0
this.each(function(test) {
if (test.passed)
passed += 1
else
failed += 1
}).end(function() {
console.log("")
console.log("Summary:")
console.log("")
console.log( "Total number of tests: " + (passed + failed))
passed && console.log("\x1b[32mPassed tests: " + passed + "\x1b[0m")
failed && console.log("\x1b[31mFailed tests: " + failed + "\x1b[0m")
console.log("")
callback(null, failed == 0)
})
}
this.setupTest = function() {
return this.each(function(test, next) {
var empty = function(next) { next() }
var context = test.context || this
if (test.setUp)
var setUp = async.makeAsync(0, test.setUp, context)
else
setUp = empty
tearDownCalled = false
if (test.tearDown)
var tearDownInner = async.makeAsync(0, test.tearDown, context)
else
tearDownInner = empty
function tearDown(next) {
tearDownCalled = true
tearDownInner.call(test.context, next)
}
var testFn = async.makeAsync(0, test.fn, context)
test.test = function(callback) {
var called
function errorListener(e) {
if (called)
return
called = true
//process.removeListener('uncaughtException', errorListener)
if (!tearDownCalled) {
async.list([tearDown])
.call()
.timeout(test.timeout)
.end(function() {
callback(e, false)
}) }
else
callback(e, false)
}
//process.addListener('uncaughtException', errorListener)
async.list([setUp, testFn, tearDown])
.delay(0)
.call(context)
.timeout(test.timeout)
.toArray(false, function(errors, values) {
if (called)
return
called = true
var err = errors[1]
//process.removeListener('uncaughtException', errorListener)
callback(err, !err)
})
}
next()
})
}
}).call(exports.TestGenerator.prototype)
exports.testcase = function(testcase, suiteName, timeout) {
var methods = []
for (var method in testcase)
methods.push(method)
var setUp = testcase.setUp || null
var tearDown = testcase.tearDown || null
var single
methods.forEach(function(name) {
if (name.charAt(0) == '>')
single = name
})
if (single)
methods = [single]
var testNames = methods.filter(function(method) {
return method.match(/^>?test/) && typeof(testcase[method]) == "function"
})
var count = testNames.length
var i=1
tests = testNames.map(function(name) {
return {
suiteName: suiteName || testcase.name || "",
name: name,
setUp: setUp,
tearDown: tearDown,
context: testcase,
timeout: timeout === undefined ? 3000 : timeout,
fn: testcase[name],
count: count,
index: i++
}
})
if (testcase.setUpSuite) {
tests[0].setUpSuite = async.makeAsync(0, testcase.setUpSuite, testcase)
}
if (testcase.tearDownSuite) {
tests[tests.length-1].tearDownSuite = async.makeAsync(0, testcase.tearDownSuite, testcase)
}
return async.list(tests, exports.TestGenerator)
}
})

View file

@ -0,0 +1,63 @@
/*!
* async.js
* Copyright(c) 2010 Fabian Jakobs <fabian.jakobs@web.de>
* MIT Licensed
*/
define(function(require, exports, module) {
var async = require("asyncjs/async")
async.plugin({
delay: function(delay) {
return this.each(function(item, next) {
setTimeout(next, delay)
})
},
timeout: function(timeout) {
timeout = timeout || 0
var source = this.source
this.next = function(callback) {
var called
var id = setTimeout(function() {
called = true
callback("Source did not respond after " + timeout + "ms!")
}, timeout)
source.next(function(err, value) {
if (called)
return
called = true
clearTimeout(id)
callback(err, value)
})
}
return new this.constructor(this)
},
get: function(key) {
return this.map(function(value, next) {
next(null, value[key])
})
},
inspect: function() {
return this.each(function(item, next) {
console.log(JSON.stringify(item))
next()
})
},
print: function() {
return this.each(function(item, next) {
console.log(item)
next()
})
}
})
})

View file

@ -37,8 +37,6 @@
define(function(require, exports, module) {
require("./mockdom");
var EditSession = require("../edit_session").EditSession,
Editor = require("../editor").Editor,
Text = require("../mode/text").Mode,
@ -158,7 +156,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var Document = require("../document").Document,
Range = require("../range").Range,
assert = require("./assertions"),
@ -302,7 +304,9 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
if (module === require.main) {
});
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -37,8 +37,6 @@
define(function(require, exports, module) {
require("./mockdom");
var EditSession = require("ace/edit_session").EditSession,
Editor = require("../editor").Editor,
UndoManager = require("ace/undomanager").UndoManager,
@ -236,7 +234,7 @@ var Test = {
wrapLimit = wrapLimit || 12;
tabSize = tabSize || 4;
splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize);
console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]);
@ -333,7 +331,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -35,10 +35,10 @@
*
* ***** END LICENSE BLOCK ***** */
require("../../../support/paths");
define(function(require, exports, module) {
var oop = require("pilot/oop");
EventEmitter = require("pilot/event_emitter").EventEmitter,
EventEmitter = require("pilot/event_emitter").EventEmitter,
assert = require("./assertions");
var Emitter = function() {};
@ -61,6 +61,4 @@ var Test = {
};
module.exports = require("asyncjs/test").testcase(Test)
if (module === require.main)
module.exports.exec()
});

View file

@ -123,7 +123,10 @@ MockRenderer.prototype.draw = function() {
MockRenderer.prototype.updateLines = function(startRow, endRow) {
};
MockRenderer.prototype.addMarker = function() {
MockRenderer.prototype.updateBackMarkers = function() {
};
MockRenderer.prototype.updateFrontMarkers = function() {
};
MockRenderer.prototype.setBreakpoints = function() {

View file

@ -73,7 +73,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -88,7 +88,7 @@ module.exports = require("asyncjs/test").testcase(Test, "css tokenizer");
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

View file

@ -65,7 +65,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -68,7 +68,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -147,7 +147,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -104,7 +104,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -62,7 +62,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -73,7 +73,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -63,7 +63,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -37,8 +37,6 @@
define(function(require, exports, module) {
require("./mockdom");
var EditSession = require("ace/edit_session").EditSession,
Editor = require("../editor").Editor,
MockRenderer = require("./mockrenderer"),
@ -153,7 +151,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test)
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -164,7 +164,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -347,7 +347,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test)
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -293,7 +293,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
}

54
lib/ace/test/tests.html Normal file
View file

@ -0,0 +1,54 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Ace Unit Tests</title>
<style type="text/css" media="screen">
#log .passed {
color: green;
}
#log .failed {
color: red;
}
#log pre.error {
color: black;
}
</style>
</head>
<body>
<div id="log"></div>
<script src="../../../demo/require.js" type="text/javascript" charset="utf-8"></script>
<script>
require({
paths: {
ace: "../lib/ace",
cockpit: "../support/cockpit/lib/cockpit",
pilot: "../support/pilot/lib/pilot"
},
packages : [{
name: "asyncjs",
location: "../lib/ace/test",
lib: "asyncjs",
main: "index"
}, {
name: "assert",
location: "../lib/ace/test",
lib: "asyncjs",
main: "assert"
}]
});
require(["ace/test/all_browser"], function(tests) {
});
</script>
</body>
</html>

View file

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
require("./mockdom");
var EditSession = require("ace/edit_session").EditSession,
Editor = require("../editor").Editor,
@ -435,13 +434,63 @@ var Test = {
editor.moveCursorTo(1, 8);
editor.removeLeft();
assert.equal(session.toString(), "123\n 456");
},
"test: transpose at line start should be a noop": function() {
var session = new EditSession(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 0);
editor.transposeLetters();
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
},
"test: transpose in line should swap the charaters before and after the cursor": function() {
var session = new EditSession(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 2);
editor.transposeLetters();
assert.equal(session.getValue(), ["123", "4657", "89"].join("\n"));
},
"test: transpose at line end should swap the last two characters": function() {
var session = new EditSession(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 4);
editor.transposeLetters();
assert.equal(session.getValue(), ["123", "4576", "89"].join("\n"));
},
"test: transpose with non empty selection should be a noop": function() {
var session = new EditSession(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 1);
editor.getSelection().selectRight();
editor.transposeLetters();
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
},
"test: transpose should move the cursor behind the last swapped character": function() {
var session = new EditSession(["123", "4567", "89"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 2);
editor.transposeLetters();
assert.position(editor.getCursorPosition(), 1, 3);
}
};
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
require("./mockdom");
var EditSession = require("ace/edit_session").EditSession,
VirtualRenderer = require("../virtual_renderer").VirtualRenderer,
@ -75,7 +74,7 @@ var Test = {
module.exports = require("asyncjs/test").testcase(Test);
});
if (module === require.main) {
if (typeof module !== "undefined" && module === require.main) {
require("../../../support/paths");
exports.exec()
exports.exec();
}

View file

@ -75,7 +75,7 @@ var Tokenizer = function(rules) {
var value = match[0];
for ( var i = 0; i < state.length; i++) {
if (match[i + 1] !== undefined) {
if (match[i + 1]) {
if (typeof state[i].token == "function") {
type = state[i].token(match[0]);
}
@ -109,10 +109,10 @@ var Tokenizer = function(rules) {
}
if (lastIndex == line.length) {
break;
}
break;
}
lastIndex = re.lastIndex;
lastIndex = re.lastIndex;
};
if (token.type) {

View file

@ -75,19 +75,19 @@ var VirtualRenderer = function(container, theme) {
this.scroller.appendChild(this.content);
this.$gutterLayer = new GutterLayer(this.$gutter);
this.$markerLayer = new MarkerLayer(this.content);
this.$markerBack = new MarkerLayer(this.content);
var textLayer = this.$textLayer = new TextLayer(this.content);
this.canvas = textLayer.element;
this.$markerFront = new MarkerLayer(this.content);
this.characterWidth = textLayer.getCharacterWidth();
this.lineHeight = textLayer.getLineHeight();
this.$cursorLayer = new CursorLayer(this.content);
this.$cursorPadding = 8;
this.layers = [ this.$markerLayer, textLayer, this.$cursorLayer ];
this.scrollBar = new ScrollBar(container);
this.scrollBar.addEventListener("scroll", this.onScroll.bind(this));
@ -133,14 +133,17 @@ var VirtualRenderer = function(container, theme) {
this.CHANGE_LINES = 16;
this.CHANGE_TEXT = 32;
this.CHANGE_SIZE = 64;
this.CHANGE_FULL = 128;
this.CHANGE_MARKER_BACK = 128;
this.CHANGE_MARKER_FRONT = 256;
this.CHANGE_FULL = 512;
oop.implement(this, EventEmitter);
this.setSession = function(session) {
this.session = session;
this.$cursorLayer.setSession(session);
this.$markerLayer.setSession(session);
this.$markerBack.setSession(session);
this.$markerFront.setSession(session);
this.$gutterLayer.setSession(session);
this.$textLayer.setSession(session);
this.$loop.schedule(this.CHANGE_FULL);
@ -212,7 +215,8 @@ var VirtualRenderer = function(container, theme) {
this.scroller.style.width = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()) + "px";
if (this.session.getUseWrapMode()) {
var limit = Math.floor(this.scroller.clientWidth / this.characterWidth);
var availableWidth = this.scroller.clientWidth - this.$padding * 2;
var limit = Math.floor(availableWidth / this.characterWidth) - 1;
if (this.session.adjustWrapLimit(limit) || force) {
changes = changes | this.CHANGE_FULL;
}
@ -383,7 +387,8 @@ var VirtualRenderer = function(container, theme) {
if (changes & this.CHANGE_FULL) {
this.$textLayer.update(this.layerConfig);
this.showGutter && this.$gutterLayer.update(this.layerConfig);
this.$markerLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$updateScrollBar();
this.scrollCursorIntoView();
@ -397,7 +402,8 @@ var VirtualRenderer = function(container, theme) {
else
this.$textLayer.scrollLines(this.layerConfig);
this.showGutter && this.$gutterLayer.update(this.layerConfig);
this.$markerLayer.update(this.layerConfig);
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$updateScrollBar();
return;
@ -418,8 +424,12 @@ var VirtualRenderer = function(container, theme) {
if (changes & this.CHANGE_CURSOR)
this.$cursorLayer.update(this.layerConfig);
if (changes & this.CHANGE_MARKER) {
this.$markerLayer.update(this.layerConfig);
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
this.$markerFront.update(this.layerConfig);
}
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) {
this.$markerBack.update(this.layerConfig);
}
if (changes & this.CHANGE_SIZE)
@ -504,15 +514,14 @@ var VirtualRenderer = function(container, theme) {
return Math.max(this.$size.scrollerWidth - this.$padding * 2, Math.round(charCount * this.characterWidth));
};
this.addMarker = function(range, clazz, type) {
var id = this.$markerLayer.addMarker(range, clazz, type);
this.$loop.schedule(this.CHANGE_MARKER);
return id;
this.updateFrontMarkers = function() {
this.$markerFront.setMarkers(this.session.getMarkers(true));
this.$loop.schedule(this.CHANGE_MARKER_FRONT);
};
this.removeMarker = function(markerId) {
this.$markerLayer.removeMarker(markerId);
this.$loop.schedule(this.CHANGE_MARKER);
this.updateBackMarkers = function() {
this.$markerBack.setMarkers(this.session.getMarkers());
this.$loop.schedule(this.CHANGE_MARKER_BACK);
};
this.addGutterDecoration = function(row, className){

View file

@ -1,7 +1,7 @@
{
"name": "ace",
"description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE",
"version": "0.1.5",
"version": "0.1.6",
"homepage" : "http://github.com/ajaxorg/ace",
"engines": {"node": ">= 0.2.0"},
"author": "Fabian Jakobs <fabian@ajax.org>",

@ -1 +1 @@
Subproject commit cbfac498d30d43fdb7687d198c5b752736222c2f
Subproject commit 5d642573259ba8a77456d3fa066beb2f1b2be23a