diff --git a/configs/cli.js b/configs/cli.js
index 8d95eff0..d6f247e1 100644
--- a/configs/cli.js
+++ b/configs/cli.js
@@ -56,7 +56,8 @@ return [
packagePath: "./c9.ide.auth/auth",
accessToken: "token",
ideBaseUrl: "",
- apiUrl: APIURL
+ apiUrl: APIURL,
+ cli: true
// userId: process.env.C9_USER
},
{
@@ -119,7 +120,8 @@ return [
local: true,
home: process.env.HOME,
setStatus: function(){},
- location: ""
+ location: "",
+ platform: process.platform,
},
error_handler: {
log: function(){}
diff --git a/configs/client-default.js b/configs/client-default.js
index 789b64f7..6f6d5192 100644
--- a/configs/client-default.js
+++ b/configs/client-default.js
@@ -98,7 +98,7 @@ module.exports = function(options) {
packagePath: "plugins/c9.ide.plugins/debug"
},
{
- packagePath: "plugins/c9.ide.plugins/market"
+ packagePath: "plugins/c9.ide.plugins/packages"
},
{
packagePath: "plugins/c9.ide.plugins/test",
@@ -456,7 +456,7 @@ module.exports = function(options) {
{
packagePath: "plugins/c9.ide.layout.classic/preload",
themePrefix: options.themePrefix,
- defaultTheme: "dark"
+ defaultTheme: options.defaultTheme || "dark"
},
{
packagePath: "plugins/c9.ide.tree/tree",
@@ -618,7 +618,6 @@ module.exports = function(options) {
},
{
packagePath: "plugins/c9.cli.bridge/bridge",
- port: 17123,
startBridge: options.startBridge
},
{
diff --git a/node_modules/ace/lib/ace/commands/default_commands.js b/node_modules/ace/lib/ace/commands/default_commands.js
index f1e267c1..dddce931 100644
--- a/node_modules/ace/lib/ace/commands/default_commands.js
+++ b/node_modules/ace/lib/ace/commands/default_commands.js
@@ -423,6 +423,12 @@ exports.commands = [{
exec: function() {},
passEvent: true,
readOnly: true
+}, {
+ name: "copy",
+ exec: function(editor) {
+ // placeholder for replay macro
+ },
+ readOnly: true
},
// commands disabled in readOnly mode
@@ -439,6 +445,12 @@ exports.commands = [{
},
scrollIntoView: "cursor",
multiSelectAction: "forEach"
+}, {
+ name: "paste",
+ exec: function(editor, text) {
+ editor.$handlePaste(text);
+ },
+ scrollIntoView: "cursor"
}, {
name: "removeline",
bindKey: bindKey("Ctrl-D", "Command-D"),
diff --git a/node_modules/ace/lib/ace/edit_session.js b/node_modules/ace/lib/ace/edit_session.js
index bd984221..56c0f0b5 100644
--- a/node_modules/ace/lib/ace/edit_session.js
+++ b/node_modules/ace/lib/ace/edit_session.js
@@ -132,7 +132,6 @@ var SearchHighlight = require("./search_highlight").SearchHighlight;
//}
/**
- *
* Sets up a new `EditSession` and associates it with the given `Document` and `TextMode`.
* @param {Document | String} text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam}
* @param {TextMode} mode [The inital language mode to use for the document]{: #modeParam}
@@ -149,9 +148,10 @@ var EditSession = function(text, mode) {
this.$undoSelect = true;
this.$foldData = [];
+ this.id = "session" + EditSession.$uid;
this.$foldData.toString = function() {
return this.join("\n");
- }
+ };
this.on("changeFold", this.onChangeFold.bind(this));
this.$onChange = this.onChange.bind(this);
@@ -167,6 +167,8 @@ var EditSession = function(text, mode) {
};
+EditSession.$uid = 0;
+
(function() {
oop.implement(this, EventEmitter);
@@ -255,15 +257,17 @@ var EditSession = function(text, mode) {
this.$resetRowCache(delta.start.row);
var removedFolds = this.$updateInternalDataOnChange(delta);
- if (!this.$fromUndo && this.$undoManager && !delta.ignore) {
- this.$deltasDoc.push(delta);
- if (removedFolds && removedFolds.length != 0) {
- this.$deltasFold.push({
+ if (!this.$fromUndo && this.$undoManager) {
+ if (removedFolds && removedFolds.length) {
+ this.$undoManager.add({
action: "removeFolds",
folds: removedFolds
- });
+ }, this.mergeUndoDeltas);
+ this.mergeUndoDeltas = true;
}
-
+ this.$undoManager.add(delta, this.mergeUndoDeltas);
+ this.mergeUndoDeltas = true;
+
this.$informUndoManager.schedule();
}
@@ -281,9 +285,6 @@ var EditSession = function(text, mode) {
this.selection.moveTo(0, 0);
this.$resetRowCache(0);
- this.$deltas = [];
- this.$deltasDoc = [];
- this.$deltasFold = [];
this.setUndoManager(this.$undoManager);
this.getUndoManager().reset();
};
@@ -364,53 +365,27 @@ var EditSession = function(text, mode) {
};
/**
- * Sets the undo manager.
- * @param {UndoManager} undoManager The new undo manager
- *
- *
- **/
+ * Sets the undo manager.
+ * @param {UndoManager} undoManager The new undo manager
+ *
+ *
+ **/
this.setUndoManager = function(undoManager) {
this.$undoManager = undoManager;
- this.$deltas = [];
- this.$deltasDoc = [];
- this.$deltasFold = [];
-
+
if (this.$informUndoManager)
this.$informUndoManager.cancel();
-
+
if (undoManager) {
var self = this;
-
+ undoManager.addSession(this);
this.$syncInformUndoManager = function() {
self.$informUndoManager.cancel();
-
- if (self.$deltasFold.length) {
- self.$deltas.push({
- group: "fold",
- deltas: self.$deltasFold
- });
- self.$deltasFold = [];
- }
-
- if (self.$deltasDoc.length) {
- self.$deltas.push({
- group: "doc",
- deltas: self.$deltasDoc
- });
- self.$deltasDoc = [];
- }
-
- if (self.$deltas.length > 0) {
- undoManager.execute({
- action: "aceupdate",
- args: [self.$deltas, self],
- merge: self.mergeUndoDeltas
- });
- }
self.mergeUndoDeltas = false;
- self.$deltas = [];
};
this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager);
+ } else {
+ this.$syncInformUndoManager = function() {};
}
};
@@ -425,7 +400,11 @@ var EditSession = function(text, mode) {
this.$defaultUndoManager = {
undo: function() {},
redo: function() {},
- reset: function() {}
+ reset: function() {},
+ add: function() {},
+ addSelection: function() {},
+ startNewGroup: function() {},
+ addSession: function() {},
};
/**
@@ -1147,14 +1126,14 @@ var EditSession = function(text, mode) {
};
/**
- * Removes a range of full lines. This method also triggers the `'change'` event.
- * @param {Number} firstRow The first row to be removed
- * @param {Number} lastRow The last row to be removed
- * @returns {[String]} Returns all the removed lines.
- *
- * @related Document.removeFullLines
- *
- **/
+ * Removes a range of full lines. This method also triggers the `'change'` event.
+ * @param {Number} firstRow The first row to be removed
+ * @param {Number} lastRow The last row to be removed
+ * @returns {[String]} Returns all the removed lines.
+ *
+ * @related Document.removeFullLines
+ *
+ **/
this.removeFullLines = function(firstRow, lastRow){
return this.doc.removeFullLines(firstRow, lastRow);
};
@@ -1163,34 +1142,30 @@ var EditSession = function(text, mode) {
* Reverts previous changes to your document.
* @param {Array} deltas An array of previous changes
* @param {Boolean} dontSelect [If `true`, doesn't select the range of where the change occured]{: #dontSelect}
- *
*
* @returns {Range}
- **/
+ **/
this.undoChanges = function(deltas, dontSelect) {
if (!deltas.length)
return;
this.$fromUndo = true;
- var lastUndoRange = null;
for (var i = deltas.length - 1; i != -1; i--) {
var delta = deltas[i];
- if (delta.group == "doc") {
- this.doc.revertDeltas(delta.deltas);
- lastUndoRange =
- this.$getUndoSelection(delta.deltas, true, lastUndoRange);
- } else {
- delta.deltas.forEach(function(foldDelta) {
- this.addFolds(foldDelta.folds);
- }, this);
+ if (delta.action == "insert" || delta.action == "remove") {
+ this.doc.revertDelta(delta);
+ } else if (delta.folds) {
+ this.addFolds(delta.folds);
}
}
+ if (!dontSelect) {
+ // console.log(deltas.selectionBefore + "uuu")
+ if (deltas.selectionBefore)
+ this.selection.fromJSON(deltas.selectionBefore);
+ else
+ this.selection.setRange(this.$getUndoSelection(deltas, true));
+ }
this.$fromUndo = false;
- lastUndoRange &&
- this.$undoSelect &&
- !dontSelect &&
- this.selection.setSelectionRange(lastUndoRange);
- return lastUndoRange;
};
/**
@@ -1198,41 +1173,39 @@ var EditSession = function(text, mode) {
* @param {Array} deltas An array of previous changes
* @param {Boolean} dontSelect {:dontSelect}
*
- *
* @returns {Range}
- **/
+ **/
this.redoChanges = function(deltas, dontSelect) {
if (!deltas.length)
return;
this.$fromUndo = true;
- var lastUndoRange = null;
for (var i = 0; i < deltas.length; i++) {
var delta = deltas[i];
- if (delta.group == "doc") {
- this.doc.applyDeltas(delta.deltas);
- lastUndoRange =
- this.$getUndoSelection(delta.deltas, false, lastUndoRange);
+ if (delta.action == "insert" || delta.action == "remove") {
+ this.doc.applyDelta(delta);
}
}
+
+ if (!dontSelect) {
+ if (deltas.selectionAfter)
+ this.selection.fromJSON(deltas.selectionAfter);
+ else
+ this.selection.setRange(this.$getUndoSelection(deltas, false));
+ }
this.$fromUndo = false;
- lastUndoRange &&
- this.$undoSelect &&
- !dontSelect &&
- this.selection.setSelectionRange(lastUndoRange);
- return lastUndoRange;
};
/**
* Enables or disables highlighting of the range where an undo occured.
* @param {Boolean} enable If `true`, selects the range of the reinserted change
- *
- **/
+ *
+ **/
this.setUndoSelect = function(enable) {
this.$undoSelect = enable;
};
- this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) {
+ this.$getUndoSelection = function(deltas, isUndo) {
function isInsert(delta) {
return isUndo ? delta.action !== "insert" : delta.action === "insert";
}
@@ -1268,60 +1241,36 @@ var EditSession = function(text, mode) {
lastDeltaIsInsert = false;
}
}
-
- // 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) {
- lastUndoRange.start.column += range.end.column - range.start.column;
- lastUndoRange.end.column += range.end.column - range.start.column;
- }
-
- var cmp = lastUndoRange.compareRange(range);
- if (cmp == 1) {
- range.setStart(lastUndoRange.start);
- } else if (cmp == -1) {
- range.setEnd(lastUndoRange.end);
- }
- }
-
return range;
};
/**
- * Replaces a range in the document with the new `text`.
- *
- * @param {Range} range A specified Range to replace
- * @param {String} text The new text to use as a replacement
- * @returns {Object} An object containing the final row and column, like this:
- * ```
- * {row: endRow, column: 0}
- * ```
- * If the text and range are empty, this function returns an object containing the current `range.start` value.
- * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
- *
- *
- *
- * @related Document.replace
- *
- *
- **/
+ * Replaces a range in the document with the new `text`.
+ *
+ * @param {Range} range A specified Range to replace
+ * @param {String} text The new text to use as a replacement
+ * @returns {Object} An object containing the final row and column, like this:
+ * ```
+ * {row: endRow, column: 0}
+ * ```
+ * If the text and range are empty, this function returns an object containing the current `range.start` value.
+ * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
+ *
+ * @related Document.replace
+ **/
this.replace = function(range, text) {
return this.doc.replace(range, text);
};
/**
- * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this:
+ * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this:
* ```json
- * { row: newRowLocation, column: newColumnLocation }
+ * { row: newRowLocation, column: newColumnLocation }
* ```
* @param {Range} fromRange The range of text you want moved within the document
* @param {Object} toPosition The location (row and column) where you want to move the text to
* @returns {Range} The new range where the text was moved to.
- *
- *
- *
- **/
+ **/
this.moveText = function(fromRange, toPosition, copy) {
var text = this.getTextRange(fromRange);
var folds = this.getFoldsInRange(fromRange);
@@ -1365,15 +1314,15 @@ var EditSession = function(text, mode) {
};
/**
- * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`.
- *
- * If `indentString` contains the `'\t'` character, it's replaced by whatever is defined by [[EditSession.getTabString `getTabString()`]].
- * @param {Number} startRow Starting row
- * @param {Number} endRow Ending row
- * @param {String} indentString The indent token
- *
- *
- **/
+ * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`.
+ *
+ * If `indentString` contains the `'\t'` character, it's replaced by whatever is defined by [[EditSession.getTabString `getTabString()`]].
+ * @param {Number} startRow Starting row
+ * @param {Number} endRow Ending row
+ * @param {String} indentString The indent token
+ *
+ *
+ **/
this.indentRows = function(startRow, endRow, indentString) {
indentString = indentString.replace(/\t/g, this.getTabString());
for (var row=startRow; row<=endRow; row++)
@@ -1381,11 +1330,10 @@ var EditSession = function(text, mode) {
};
/**
- * Outdents all the rows defined by the `start` and `end` properties of `range`.
- * @param {Range} range A range of rows
- *
- *
- **/
+ * Outdents all the rows defined by the `start` and `end` properties of `range`.
+ * @param {Range} range A range of rows
+ *
+ **/
this.outdentRows = function (range) {
var rowRange = range.collapseRows();
var deleteRange = new Range(0, 0, 0, 0);
@@ -1443,34 +1391,34 @@ var EditSession = function(text, mode) {
return diff;
};
/**
- * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`.
- * @param {Number} firstRow The starting row to move up
- * @param {Number} lastRow The final row to move up
- * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
- *
- **/
+ * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`.
+ * @param {Number} firstRow The starting row to move up
+ * @param {Number} lastRow The final row to move up
+ * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
+ *
+ **/
this.moveLinesUp = function(firstRow, lastRow) {
return this.$moveLines(firstRow, lastRow, -1);
};
/**
- * Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`.
- * @param {Number} firstRow The starting row to move down
- * @param {Number} lastRow The final row to move down
- * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
- **/
+ * Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`.
+ * @param {Number} firstRow The starting row to move down
+ * @param {Number} lastRow The final row to move down
+ * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
+ **/
this.moveLinesDown = function(firstRow, lastRow) {
return this.$moveLines(firstRow, lastRow, 1);
};
/**
- * Duplicates all the text between `firstRow` and `lastRow`.
- * @param {Number} firstRow The starting row to duplicate
- * @param {Number} lastRow The final row to duplicate
- * @returns {Number} Returns the number of new rows added; in other words, `lastRow - firstRow + 1`.
- *
- *
- **/
+ * Duplicates all the text between `firstRow` and `lastRow`.
+ * @param {Number} firstRow The starting row to duplicate
+ * @param {Number} lastRow The final row to duplicate
+ * @returns {Number} Returns the number of new rows added; in other words, `lastRow - firstRow + 1`.
+ *
+ *
+ **/
this.duplicateLines = function(firstRow, lastRow) {
return this.$moveLines(firstRow, lastRow, 0);
};
@@ -1545,8 +1493,7 @@ var EditSession = function(text, mode) {
* Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted.
* @param {Boolean} useWrapMode Enable (or disable) wrap mode
*
- *
- **/
+ **/
this.setUseWrapMode = function(useWrapMode) {
if (useWrapMode != this.$useWrapMode) {
this.$useWrapMode = useWrapMode;
@@ -1565,9 +1512,9 @@ var EditSession = function(text, mode) {
};
/**
- * Returns `true` if wrap mode is being used; `false` otherwise.
- * @returns {Boolean}
- **/
+ * Returns `true` if wrap mode is being used; `false` otherwise.
+ * @returns {Boolean}
+ **/
this.getUseWrapMode = function() {
return this.$useWrapMode;
};
@@ -1581,8 +1528,7 @@ var EditSession = function(text, mode) {
* @param {Number} min The minimum wrap value (the left side wrap)
* @param {Number} max The maximum wrap value (the right side wrap)
*
- *
- **/
+ **/
this.setWrapLimitRange = function(min, max) {
if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) {
this.$wrapLimitRange = { min: min, max: max };
@@ -1594,12 +1540,12 @@ var EditSession = function(text, mode) {
};
/**
- * This should generally only be called by the renderer when a resize is detected.
- * @param {Number} desiredLimit The new wrap limit
- * @returns {Boolean}
- *
- * @private
- **/
+ * This should generally only be called by the renderer when a resize is detected.
+ * @param {Number} desiredLimit The new wrap limit
+ * @returns {Boolean}
+ *
+ * @private
+ **/
this.adjustWrapLimit = function(desiredLimit, $printMargin) {
var limits = this.$wrapLimitRange;
if (limits.max < 0)
diff --git a/node_modules/ace/lib/ace/editor.js b/node_modules/ace/lib/ace/editor.js
index 500cfc45..5cc23e95 100644
--- a/node_modules/ace/lib/ace/editor.js
+++ b/node_modules/ace/lib/ace/editor.js
@@ -111,21 +111,25 @@ var Editor = function(renderer, session) {
oop.implement(this, EventEmitter);
this.$initOperationListeners = function() {
- function last(a) {return a[a.length - 1]}
-
- this.selections = [];
this.commands.on("exec", this.startOperation.bind(this), true);
this.commands.on("afterExec", this.endOperation.bind(this), true);
this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this));
-
+
+ // todo: add before change events?
this.on("change", function() {
- this.curOp || this.startOperation();
+ if (!this.curOp) {
+ this.startOperation();
+ this.curOp.selectionBefore = this.$lastSel;
+ }
this.curOp.docChanged = true;
}.bind(this), true);
-
+
this.on("changeSelection", function() {
- this.curOp || this.startOperation();
+ if (!this.curOp) {
+ this.startOperation();
+ this.curOp.selectionBefore = this.$lastSel;
+ }
this.curOp.selectionChanged = true;
}.bind(this), true);
};
@@ -144,19 +148,18 @@ var Editor = function(renderer, session) {
}
this.$opResetTimer.schedule();
- this.curOp = {
+ this.curOp = this.session.curOp = {
command: commadEvent.command || {},
args: commadEvent.args,
scrollTop: this.renderer.scrollTop
};
-
- // this.selections.push(this.selection.toJSON());
+ this.curOp.selectionBefore = this.selection.toJSON();
};
this.endOperation = function(e) {
if (this.curOp) {
if (e && e.returnValue === false)
- return this.curOp = null;
+ return (this.curOp = null);
this._signal("beforeEndOperation");
var command = this.curOp.command;
var scrollIntoView = command && command.scrollIntoView;
@@ -185,7 +188,12 @@ var Editor = function(renderer, session) {
if (scrollIntoView == "animate")
this.renderer.animateScrolling(this.curOp.scrollTop);
}
+ var sel = this.selection.toJSON();
+ this.curOp.selectionAfter = sel;
+ this.$lastSel = this.selection.toJSON();
+ // console.log(this.$lastSel+" endOP")
+ this.session.getUndoManager().addSelection(sel);
this.prevOp = this.curOp;
this.curOp = null;
}
@@ -903,10 +911,10 @@ var Editor = function(renderer, session) {
*
**/
this.onPaste = function(text) {
- // todo this should change when paste becomes a command
- if (this.$readOnly)
- return;
-
+ this.commands.exec("paste", this, text);
+ };
+
+ this.$handlePaste = function(text) {
var e = {text: text};
this._signal("paste", e);
text = e.text;
@@ -927,7 +935,6 @@ var Editor = function(renderer, session) {
this.session.insert(range.start, lines[i]);
}
}
- this.renderer.scrollCursorIntoView();
};
this.execCommand = function(command, args) {
@@ -2487,7 +2494,7 @@ var Editor = function(renderer, session) {
* @related UndoManager.undo
**/
this.undo = function() {
- this.session.getUndoManager().undo();
+ this.session.getUndoManager().undo(this.session);
this.renderer.scrollCursorIntoView(null, 0.5);
};
@@ -2496,7 +2503,7 @@ var Editor = function(renderer, session) {
* @related UndoManager.redo
**/
this.redo = function() {
- this.session.getUndoManager().redo();
+ this.session.getUndoManager().redo(this.session);
this.renderer.scrollCursorIntoView(null, 0.5);
};
diff --git a/node_modules/ace/lib/ace/split.js b/node_modules/ace/lib/ace/split.js
index 878b0dc3..e960c128 100644
--- a/node_modules/ace/lib/ace/split.js
+++ b/node_modules/ace/lib/ace/split.js
@@ -42,8 +42,6 @@ var EditSession = require("./edit_session").EditSession;
/**
* @class Split
*
- *
- *
**/
@@ -217,14 +215,7 @@ var Split = function(container, theme, splits) {
var s = new EditSession(session.getDocument(), session.getMode());
var undoManager = session.getUndoManager();
- if (undoManager) {
- var undoManagerProxy = new UndoManagerProxy(undoManager, s);
- s.setUndoManager(undoManagerProxy);
- }
-
- // Overwrite the default $informUndoManager function such that new delas
- // aren't added to the undo manager from the new and the old session.
- s.$informUndoManager = lang.delayedCall(function() { s.$deltas = []; });
+ s.setUndoManager(undoManager);
// Copy over 'settings' from the session.
s.setTabSize(session.getTabSize());
@@ -331,43 +322,5 @@ var Split = function(container, theme, splits) {
}).call(Split.prototype);
-
-function UndoManagerProxy(undoManager, session) {
- this.$u = undoManager;
- this.$doc = session;
-}
-
-(function() {
- this.execute = function(options) {
- this.$u.execute(options);
- };
-
- this.undo = function() {
- var selectionRange = this.$u.undo(true);
- if (selectionRange) {
- this.$doc.selection.setSelectionRange(selectionRange);
- }
- };
-
- this.redo = function() {
- var selectionRange = this.$u.redo(true);
- if (selectionRange) {
- this.$doc.selection.setSelectionRange(selectionRange);
- }
- };
-
- this.reset = function() {
- this.$u.reset();
- };
-
- this.hasUndo = function() {
- return this.$u.hasUndo();
- };
-
- this.hasRedo = function() {
- return this.$u.hasRedo();
- };
-}).call(UndoManagerProxy.prototype);
-
exports.Split = Split;
});
diff --git a/node_modules/ace/lib/ace/test/all_browser.js b/node_modules/ace/lib/ace/test/all_browser.js
index 7ac5092e..71e96e2f 100644
--- a/node_modules/ace/lib/ace/test/all_browser.js
+++ b/node_modules/ace/lib/ace/test/all_browser.js
@@ -5,9 +5,9 @@ require("ace/lib/fixoldbrowsers");
var AsyncTest = require("asyncjs").test;
var async = require("asyncjs");
-var passed = 0
-var failed = 0
-var log = document.getElementById("log")
+var passed = 0;
+var failed = 0;
+var log = document.getElementById("log");
var testNames = [
"ace/anchor_test",
@@ -55,6 +55,7 @@ var testNames = [
"ace/snippets_test",
"ace/token_iterator_test",
"ace/tokenizer_test",
+ "ace/undomanager_test",
"ace/virtual_renderer_test"
];
@@ -64,13 +65,30 @@ for (var i in testNames) {
html.push("", href.replace(/^ace\//, "") ,"
");
}
+
+if (location.search.indexOf("show=1") != -1) {
+ var VirtualRenderer = require("ace/virtual_renderer").VirtualRenderer;
+ require("ace/test/mockrenderer").MockRenderer = function() {
+ var el = document.createElement("div");
+ el.style.position = "fixed";
+ el.style.left = "20px";
+ el.style.top = "30px";
+ el.style.width = "500px";
+ el.style.height = "300px";
+ document.body.appendChild(el);
+
+ return new VirtualRenderer(el);
+ };
+}
+
+
var nav = document.createElement("div");
nav.innerHTML = html.join("");
nav.style.cssText = "position:absolute;right:0;top:0";
document.body.appendChild(nav);
if (location.search)
- testNames = location.search.substr(1).split(",")
+ testNames = location.search.substr(1).split(",");
var filter = location.hash.substr(1);
@@ -89,7 +107,7 @@ require(testNames, function() {
test[method] = undefined;
});
}
- return AsyncTest.testcase(test)
+ return AsyncTest.testcase(test);
}, AsyncTest.TestGenerator)
.run()
.each(function(test, next) {
@@ -102,16 +120,16 @@ require(testNames, function() {
var node = document.createElement("div");
node.className = test.passed ? "passed" : "failed";
- var name = test.name
+ var name = test.name;
if (test.suiteName)
- name = test.suiteName + ": " + test.name
+ name = test.suiteName + ": " + test.name;
- var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL")
+ var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL");
if (!test.passed) {
if (test.err.stack)
- var err = test.err.stack
+ var err = test.err.stack;
else
- var err = test.err
+ var err = test.err;
console.error(msg);
console.error(err);
@@ -123,13 +141,13 @@ require(testNames, function() {
node.innerHTML = msg;
log.appendChild(node);
- next()
+ next();
})
.each(function(test) {
if (test.passed)
- passed += 1
+ passed += 1;
else
- failed += 1
+ failed += 1;
})
.end(function() {
log.innerHTML += [
@@ -140,11 +158,11 @@ require(testNames, function() {
"Total number of tests: " + (passed + failed) + "
",
(passed ? "Passed tests: " + passed + "
" : ""),
(failed ? "Failed tests: " + failed + "
" : "")
- ].join("")
+ ].join("");
console.log("Total number of tests: " + (passed + failed));
console.log("Passed tests: " + passed);
console.log("Failed tests: " + failed);
- })
+ });
});
});
diff --git a/node_modules/ace/lib/ace/undomanager.js b/node_modules/ace/lib/ace/undomanager.js
index 6da50a8b..1c76f4f4 100644
--- a/node_modules/ace/lib/ace/undomanager.js
+++ b/node_modules/ace/lib/ace/undomanager.js
@@ -32,25 +32,26 @@ define(function(require, exports, module) {
"use strict";
/**
- *
- *
* This object maintains the undo stack for an [[EditSession `EditSession`]].
* @class UndoManager
**/
/**
- *
- *
* Resets the current undo state and creates a new `UndoManager`.
*
* @constructor
**/
var UndoManager = function() {
+ this.$maxRev = 0;
+ this.$fromUndo = false;
this.reset();
};
(function() {
-
+
+ this.addSession = function(session) {
+ this.$session = session;
+ };
/**
* Provides a means for implementing your own undo manager. `options` has one property, `args`, an [[Array `Array`]], with two elements:
*
@@ -60,156 +61,523 @@ var UndoManager = function() {
* @param {Object} options Contains additional properties
*
**/
- this.execute = function(options) {
- // Normalize deltas for storage.
- // var deltaSets = this.$serializeDeltas(options.args[0]);
- var deltaSets = options.args[0];
- // Add deltas to undo stack.
- this.$doc = options.args[1];
- if (options.merge && this.hasUndo()){
- this.dirtyCounter--;
- deltaSets = this.$undoStack.pop().concat(deltaSets);
+ this.add = function(delta, allowMerge, session) {
+ if (this.$fromUndo) return;
+ if (delta == this.$lastDelta) return;
+ if (allowMerge === false || !this.lastDeltas) {
+ this.lastDeltas = [];
+ this.$undoStack.push(this.lastDeltas);
+ delta.id = this.$rev = ++this.$maxRev;
}
- this.$undoStack.push(deltaSets);
-
- // Reset redo stack.
- this.$redoStack = [];
- if (this.dirtyCounter < 0) {
- // The user has made a change after undoing past the last clean state.
- // We can never get back to a clean state now until markClean() is called.
- this.dirtyCounter = NaN;
- }
- this.dirtyCounter++;
+ if (delta.action == "remove" || delta.action == "insert")
+ this.$lastDelta = delta;
+ this.lastDeltas.push(delta);
};
-
+
+ this.addSelection = function(selection, rev) {
+ this.selections.push({
+ value: selection,
+ rev: rev || this.$rev
+ });
+ };
+
+ this.startNewGroup = function() {
+ this.lastDeltas = null;
+ return this.$rev;
+ };
+
+ this.markIgnored = function(from, to) {
+ if (to == null) to = this.$rev + 1;
+ var stack = this.$undoStack;
+ for (var i = stack.length; i--;) {
+ var delta = stack[i][0];
+ if (delta.id <= from)
+ break;
+ if (delta.id < to)
+ delta.ignore = true;
+ }
+ this.lastDeltas = null;
+ };
+
+ this.getSelection = function(rev, after) {
+ var stack = this.selections;
+ for (var i = stack.length; i--;) {
+ var selection = stack[i];
+ if (selection.rev < rev) {
+ if (after)
+ selection = stack[i + 1];
+ return selection;
+ }
+ }
+ };
+
+ this.getRevision = function() {
+ return this.$rev;
+ };
+
+ this.getDeltas = function(from, to) {
+ if (to == null) to = this.$rev + 1;
+ var stack = this.$undoStack;
+ var end = null, start = 0;
+ for (var i = stack.length; i--;) {
+ var delta = stack[i][0];
+ if (delta.id < to && !end)
+ end = i+1;
+ if (delta.id <= from) {
+ start = i + 1;
+ break;
+ }
+ }
+ return stack.slice(start, end);
+ };
+
+ this.getChangedRanges = function(from, to) {
+ if (to == null) to = this.$rev + 1;
+
+ };
+
+ this.getChangedLines = function(from, to) {
+ if (to == null) to = this.$rev + 1;
+
+ };
+
/**
* [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo}
* @param {Boolean} dontSelect {:dontSelect}
*
- *
* @returns {Range} The range of the undo.
**/
- this.undo = function(dontSelect) {
- var deltaSets = this.$undoStack.pop();
+ this.undo = function(session, dontSelect) {
+ this.lastDeltas = null;
+ var stack = this.$undoStack;
+
+ if (!rearrangeUndoStack(stack, stack.length))
+ return;
+
+ if (this.$redoStackBaseRev !== this.$rev && this.$redoStack.length)
+ this.$redoStack = [];
+
+ this.$fromUndo = true;
+
+ var deltaSet = stack.pop();
var undoSelectionRange = null;
- if (deltaSets) {
- undoSelectionRange = this.$doc.undoChanges(this.$deserializeDeltas(deltaSets), dontSelect);
- this.$redoStack.push(deltaSets);
- this.dirtyCounter--;
+ if (deltaSet && deltaSet.length) {
+ undoSelectionRange = session.undoChanges(deltaSet, dontSelect);
+ this.$redoStack.push(deltaSet);
+ this.$syncRev();
}
+
+ this.$fromUndo = false;
return undoSelectionRange;
};
-
+
/**
* [Perform a redo operation on the document, reimplementing the last change.]{: #UndoManager.redo}
* @param {Boolean} dontSelect {:dontSelect}
*
- *
**/
- this.redo = function(dontSelect) {
- var deltaSets = this.$redoStack.pop();
- var redoSelectionRange = null;
- if (deltaSets) {
- redoSelectionRange =
- this.$doc.redoChanges(this.$deserializeDeltas(deltaSets), dontSelect);
- this.$undoStack.push(deltaSets);
- this.dirtyCounter++;
+ this.redo = function(session, dontSelect) {
+ this.lastDeltas = null;
+
+ this.$fromUndo = true;
+ if (this.$redoStackBaseRev != this.$rev) {
+ var diff = this.getDeltas(this.$redoStackBaseRev, this.$rev + 1);
+ rebaseRedoStack(this.$redoStack, diff);
+ this.$redoStackBaseRev = this.$rev;
+ this.$redoStack.forEach(function(x) {
+ x[0].id = ++this.$maxRev;
+ }, this);
}
+ var deltaSet = this.$redoStack.pop();
+ var redoSelectionRange = null;
+
+ if (deltaSet) {
+ redoSelectionRange = session.redoChanges(deltaSet, dontSelect);
+ this.$undoStack.push(deltaSet);
+ this.$syncRev();
+ }
+ this.$fromUndo = false;
+
return redoSelectionRange;
};
+
+ this.$syncRev = function() {
+ var stack = this.$undoStack;
+ var nextDelta = stack[stack.length - 1];
+ var id = nextDelta && nextDelta[0].id || 0;
+ this.$redoStackBaseRev = id;
+ this.$rev = id;
+ };
/**
- *
* Destroys the stack of undo and redo redo operations.
**/
this.reset = function() {
+ this.lastDeltas = null;
+ this.$lastDelta = null;
this.$undoStack = [];
this.$redoStack = [];
- this.dirtyCounter = 0;
+ this.$rev = 0;
+ this.mark = 0;
+ this.$redoStackBaseRev = this.$rev;
+ this.selections = [];
};
+
/**
- *
* Returns `true` if there are undo operations left to perform.
* @returns {Boolean}
**/
- this.hasUndo = function() {
+ this.canUndo = function() {
return this.$undoStack.length > 0;
};
/**
- *
* Returns `true` if there are redo operations left to perform.
* @returns {Boolean}
**/
- this.hasRedo = function() {
+ this.canRedo = function() {
return this.$redoStack.length > 0;
};
-
+
/**
- *
* Marks the current status clean
**/
- this.markClean = function() {
- this.dirtyCounter = 0;
+ this.bookmark = function(rev) {
+ if (rev == undefined)
+ rev = this.$rev;
+ this.mark = rev;
};
/**
- *
* Returns if the current status is clean
* @returns {Boolean}
**/
- this.isClean = function() {
- return this.dirtyCounter === 0;
+ this.isAtBookmark = function() {
+ return this.$rev === this.mark;
};
- // Serializes deltaSets to reduce memory usage.
- this.$serializeDeltas = function(deltaSets) {
- return cloneDeltaSetsObj(deltaSets, $serializeDelta);
- };
-
- // Deserializes deltaSets to allow application to the document.
- this.$deserializeDeltas = function(deltaSets) {
- return cloneDeltaSetsObj(deltaSets, $deserializeDelta);
- };
-
- function $serializeDelta(delta){
- return {
- action: delta.action,
- start: delta.start,
- end: delta.end,
- lines: delta.lines.length == 1 ? null : delta.lines,
- text: delta.lines.length == 1 ? delta.lines[0] : null,
- };
- }
+ this.toJSON = function() {
- function $deserializeDelta(delta) {
- return {
- action: delta.action,
- start: delta.start,
- end: delta.end,
- lines: delta.lines || [delta.text]
- };
- }
+ };
- function cloneDeltaSetsObj(deltaSets_old, fnGetModifiedDelta) {
- var deltaSets_new = new Array(deltaSets_old.length);
- for (var i = 0; i < deltaSets_old.length; i++) {
- var deltaSet_old = deltaSets_old[i];
- var deltaSet_new = { group: deltaSet_old.group, deltas: new Array(deltaSet_old.length)};
-
- for (var j = 0; j < deltaSet_old.deltas.length; j++) {
- var delta_old = deltaSet_old.deltas[j];
- deltaSet_new.deltas[j] = fnGetModifiedDelta(delta_old);
- }
-
- deltaSets_new[i] = deltaSet_new;
- }
- return deltaSets_new;
- }
+ this.fromJSON = function() {
+
+ };
+
+ this.hasUndo = this.canUndo;
+ this.hasRedo = this.canRedo;
+ this.isClean = this.isAtBookmark;
+ this.markClean = this.bookmark;
}).call(UndoManager.prototype);
+function rearrangeUndoStack(stack, pos) {
+ for (var i = pos; i--; ) {
+ var deltaSet = stack[i];
+ if (deltaSet && !deltaSet[0].ignore) {
+ while(i < pos - 1) {
+ var swapped = swapGroups(stack[i], stack[i + 1]);
+ stack[i] = swapped[0];
+ stack[i + 1] = swapped[1];
+ i++;
+ }
+ return true;
+ }
+ }
+}
+
+var Range = require("./range").Range;
+var cmp = Range.comparePoints;
+var comparePoints = Range.comparePoints;
+
+function $updateMarkers(delta) {
+ var isInsert = delta.action == "insert";
+ var start = delta.start;
+ var end = delta.end;
+ var rowShift = (end.row - start.row) * (isInsert ? 1 : -1);
+ var colShift = (end.column - start.column) * (isInsert ? 1 : -1);
+ if (isInsert) end = start;
+
+ for (var i in this.marks) {
+ var point = this.marks[i];
+ var cmp = comparePoints(point, start);
+ if (cmp < 0) {
+ continue; // delta starts after the range
+ }
+ if (cmp === 0) {
+ if (isInsert) {
+ if (point.bias == 1) {
+ cmp = 1;
+ }
+ else {
+ point.bias == -1;
+ continue;
+ }
+ }
+ }
+ var cmp2 = isInsert ? cmp : comparePoints(point, end);
+ if (cmp2 > 0) {
+ point.row += rowShift;
+ point.column += point.row == end.row ? colShift : 0;
+ continue;
+ }
+ if (!isInsert && cmp2 <= 0) {
+ point.row = start.row;
+ point.column = start.column;
+ if (cmp2 === 0)
+ point.bias = 1;
+ }
+ }
+}
+
+
+
+function clonePos(pos) {
+ return {row: pos.row,column: pos.column};
+}
+function cloneDelta(d) {
+ return {
+ start: clonePos(d.start),
+ end: clonePos(d.end),
+ action: d.action,
+ lines: d.lines.slice()
+ };
+}
+function stringifyDelta(d) {
+ d = d || this;
+ if (Array.isArray(d)) {
+ return d.map(stringifyDelta).join("\n");
+ }
+ var type = "";
+ if (d.action) {
+ type = d.action == "insert" ? "+" : "-";
+ type += "[" + d.lines + "]";
+ } else if (d.value) {
+ if (Array.isArray(d.value)) {
+ type = d.value.map(stringifyRange).join("\n");
+ } else {
+ type = stringifyRange(d.value);
+ }
+ }
+ if (d.start) {
+ type += stringifyRange(d);
+ }
+ if (d.id || d.rev) {
+ type += "\t(" + (d.id || d.rev) + ")";
+ }
+ return type;
+}
+function stringifyRange(r) {
+ return r.start.row + ":" + r.start.column
+ + "=>" + r.end.row + ":" + r.end.column;
+}
+/*
+ * i i d1 d2
+ * |/ |/ d2.s >= d1.e shift(d2, d1, -1)
+ * d2.s <= d1.s shift(d1, d2, +1)
+ * d1.s < d2.s < d1.e // can split
+ *
+ * i r d1 d2
+ * |/ |\ d2.s >= d1.e shift(d2, d1, -1)
+ * d2.e <= d1.s shift(d1, d2, -1)
+ * else // can't swap
+ *
+ * r i d1 d2
+ * |\ |/ d2.s >= d1.s shift(d2, d1, +1)
+ * d2.s <= d1.s shift(d1, d2, +1)
+ * // no else
+ *
+ * r r d1 d2
+ * |\ |\ d2.s >= d1.s shift(d2, d1, +1)
+ * d2.e <= d1.s shift(d1, d2, -1)
+ * d2.s < d1.s < d2.e // can split
+ */
+
+function swap(d1, d2) {
+ var i1 = d1.action == "insert";
+ var i2 = d2.action == "insert";
+
+ if (i1 && i2) {
+ if (cmp(d2.start, d1.end) >= 0) {
+ shift(d2, d1, -1);
+ } else if (cmp(d2.start, d1.start) <= 0) {
+ shift(d1, d2, +1);
+ } else {
+ return null;
+ }
+ } else if (i1 && !i2) {
+ if (cmp(d2.start, d1.end) >= 0) {
+ shift(d2, d1, -1);
+ } else if (cmp(d2.end, d1.start) <= 0) {
+ shift(d1, d2, -1);
+ } else {
+ return null;
+ }
+ } else if (!i1 && i2) {
+ if (cmp(d2.start, d1.start) >= 0) {
+ shift(d2, d1, +1);
+ } else if (cmp(d2.start, d1.start) <= 0) {
+ shift(d1, d2, +1);
+ } else {
+ return null;
+ }
+ } else if (!i1 && !i2) {
+ if (cmp(d2.start, d1.start) >= 0) {
+ shift(d2, d1, +1);
+ } else if (cmp(d2.end, d1.start) <= 0) {
+ shift(d1, d2, -1);
+ } else {
+ return null;
+ }
+ }
+ return [d2, d1];
+}
+function swapGroups(ds1, ds2) {
+ for (var i = ds1.length; i--; ) {
+ for (var j = 0; j < ds2.length; j++) {
+ if (!swap(ds1[i], ds2[j])) {
+ // rollback, we have to undo ds2 first
+ while (i < ds1.length) {
+ while (j--) {
+ swap(ds2[j], ds1[i]);
+ }
+ j = ds2.length;
+ i++;
+ }
+ return [ds1, ds2];
+ }
+ }
+ }
+ ds1.selectionBefore = ds2.selectionBefore =
+ ds1.selectionAfter = ds2.selectionAfter = null;
+ return [ds2, ds1];
+}
+
+/*
+ d2 xform(d1, c1) = [d2, c2]
+ o<---o xform(c1, d1) = [c2, d2]
+ c2 | | d1
+ o<---o
+ c1
+*/
+function xform(d1, c1) {
+ var i1 = d1.action == "insert";
+ var i2 = c1.action == "insert";
+
+ if (i1 && i2) {
+ if (cmp(d1.start, c1.start) < 0) {
+ shift(c1, d1, 1);
+ } else {
+ shift(d1, c1, 1);
+ }
+ } else if (i1 && !i2) {
+ if (cmp(d1.start, c1.end) >= 0) {
+ shift(d1, c1, -1);
+ } else if (cmp(d1.start, c1.start) <= 0) {
+ shift(c1, d1, +1);
+ } else {
+ shift(d1, Range.fromPoints(c1.start, d1.start), -1);
+ shift(c1, d1, +1);
+ }
+ } else if (!i1 && i2) {
+ if (cmp(c1.start, d1.end) >= 0) {
+ shift(c1, d1, -1);
+ } else if (cmp(c1.start, d1.start) <= 0) {
+ shift(d1, c1, +1);
+ } else {
+ shift(c1, Range.fromPoints(d1.start, c1.start), -1);
+ shift(d1, c1, +1);
+ }
+ } else if (!i1 && !i2) {
+ if (cmp(c1.start, d1.end) >= 0) {
+ shift(c1, d1, -1);
+ } else if (cmp(c1.end, d1.start) <= 0) {
+ shift(d1, c1, -1);
+ } else {
+ var before, after;
+ if (cmp(d1.start, c1.start) < 0) {
+ before = d1;
+ d1 = splitDelta(d1, c1.start);
+ }
+ if (cmp(d1.end, c1.end) > 0) {
+ after = splitDelta(d1, c1.end);
+ }
+
+ shiftPos(c1.end, d1.start, d1.end, -1);
+ if (after && !before) {
+ d1.lines = after.lines;
+ d1.start = after.start;
+ d1.end = after.end;
+ after = d1;
+ }
+
+ return [c1, before, after].filter(Boolean);
+ }
+ }
+ return [c1, d1];
+}
+
+function shift(d1, d2, dir) {
+ shiftPos(d1.start, d2.start, d2.end, dir);
+ shiftPos(d1.end, d2.start, d2.end, dir);
+}
+function shiftPos(pos, start, end, dir) {
+ if (pos.row == (dir == 1 ? start : end).row) {
+ pos.column += dir * (end.column - start.column);
+ }
+ pos.row += dir * (end.row - start.row);
+}
+function splitDelta(c, pos) {
+ var lines = c.lines;
+ var end = c.end;
+ c.end = clonePos(pos);
+ var rowsBefore = c.end.row - c.start.row;
+ var otherLines = lines.splice(rowsBefore, lines.length);
+
+ var col = rowsBefore ? pos.column : pos.column - c.start.column;
+ lines.push(otherLines[0].substring(0, col));
+ otherLines[0] = otherLines[0].substr(col) ;
+ var rest = {
+ start: clonePos(pos),
+ end: end,
+ lines: otherLines,
+ action: c.action
+ };
+ return rest;
+}
+
+function moveDeltasByOne(redoStack, d) {
+ d = cloneDelta(d);
+ for (var j = redoStack.length; j--;) {
+ var deltaSet = redoStack[j];
+ for (var i = deltaSet.length; i--> 0;) {
+ var x = deltaSet[i];
+ var xformed = xform(x, d);
+ d = xformed[0];
+ if (xformed.length != 2) {
+ if (xformed[2]) {
+ redoStack.splice(i + 1, 1, xformed[1], xformed[2]);
+ i++;
+ } else if (!xformed[1]) {
+ redoStack.splice(i, 1);
+ i--;
+ }
+ }
+ }
+ }
+ return redoStack;
+}
+function rebaseRedoStack(redoStack, deltaSets) {
+ for (var i = 0; i < deltaSets.length; i++) {
+ var deltas = deltaSets[i];
+ for (var j = 0; j < deltas.length; j++) {
+ moveDeltasByOne(redoStack, deltas[j]);
+ }
+ }
+}
+
exports.UndoManager = UndoManager;
+
});
diff --git a/node_modules/ace/lib/ace/undomanager_test.js b/node_modules/ace/lib/ace/undomanager_test.js
new file mode 100644
index 00000000..4a9c1028
--- /dev/null
+++ b/node_modules/ace/lib/ace/undomanager_test.js
@@ -0,0 +1,111 @@
+/* ***** 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 ***** */
+
+if (typeof process !== "undefined") {
+ require("amd-loader");
+ require("./test/mockdom");
+}
+
+define(function(require, exports, module) {
+"use strict";
+
+require("./multi_select");
+var assert = require("./test/assertions");
+var Range = require("./range").Range;
+var Editor = require("./editor").Editor;
+var EditSession = require("./edit_session").EditSession;
+var MockRenderer = require("./test/mockrenderer").MockRenderer;
+var UndoManager = require("./undomanager").UndoManager;
+
+var editor;
+
+
+module.exports = {
+
+ name: "ACE undoManager.js",
+
+ "test: reabsing": function() {
+ var session = new EditSession("");
+ var editor = new Editor(new MockRenderer(), session);
+ var undoManager = new UndoManager();
+ session.setUndoManager(undoManager);
+
+ session.setValue("012345-012345-012345");
+ session.insert({row: 0, column: 0}, "xx");
+ session.markUndoGroup();
+ session.remove(new Range(0, 10, 0, 15));
+ session.markUndoGroup();
+ session.insert({row: 0, column: 5}, "yy");
+ session.markUndoGroup();
+ editor.undo();
+ editor.undo();
+ var rev = session.getUndoManager().startNewGroup();
+ session.insert({row: 0, column: 5}, "z\nz");
+ session.getUndoManager().markIgnored(rev);
+ // editor.undo()
+ editor.redo();
+ editor.redo();
+ var val1 = editor.getValue();
+ editor.undo();
+ editor.undo();
+ editor.undo();
+
+ editor.redo();
+ editor.redo();
+ editor.redo();
+ var val2 = editor.getValue();
+ assert.equal(val1, val2);
+ },
+ "test: conflicting deletes": function() {
+ var session = new EditSession("");
+ var editor = new Editor(new MockRenderer(), session);
+ var undoManager = new UndoManager();
+ session.setUndoManager(undoManager);
+
+ session.setValue("012345\nabcdefg\nxyz");
+ session.remove(new Range(0, 2, 0, 4));
+ assert.equal(session.getLine(0), "0145");
+ session.markUndoGroup();
+ editor.undo();
+ session.remove(new Range(0, 1, 0, 5));
+ assert.equal(session.getLine(0), "05");
+ session.markUndoGroup();
+ editor.redo();
+ assert.equal(session.getLine(0), "05");
+ editor.undo();
+ assert.equal(session.getLine(0), "012345");
+ }
+};
+
+});
+
+if (typeof module !== "undefined" && module === require.main) {
+ require("asyncjs").test.testcase(module.exports).exec();
+}
diff --git a/node_modules/vfs-child/parent.js b/node_modules/vfs-child/parent.js
index 38474005..733570c6 100644
--- a/node_modules/vfs-child/parent.js
+++ b/node_modules/vfs-child/parent.js
@@ -15,7 +15,7 @@ function Parent(fsOptions) {
options.uid = fsOptions.uid;
delete fsOptions.uid;
}
- options.customFds = [-1, -1, 2];
+ options.stdio = options.customFds = [-1, -1, 2];
var args = [require.resolve('./child.js'), JSON.stringify(fsOptions)];
var executablePath = process.execPath;
var child;
diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js
index d43c1756..6e106dad 100644
--- a/node_modules/vfs-local/localfs.js
+++ b/node_modules/vfs-local/localfs.js
@@ -1828,8 +1828,13 @@ module.exports = function setup(fsOptions) {
if (options.idle)
options.command = "echo '[Idle]'";
- if (options.terminal)
- args.push("export ISOUTPUTPANE=0;" + BASH + " -l");
+ if (options.terminal) {
+ args.push("export ISOUTPUTPANE=0;"
+ + (options.defaultEditor
+ ? " export EDITOR='`which c9` open --wait'; "
+ : "")
+ + BASH + " -l");
+ }
else if (options.command)
args.push((BASH + " -l -c '"
@@ -2334,6 +2339,9 @@ module.exports = function setup(fsOptions) {
err.code = "EEXIST";
return callback(err, { api: apis[name] });
}
+
+ if (options.redefine && apis[name] && apis[name].destroy)
+ apis[name].destroy();
var fn;
@@ -2394,6 +2402,9 @@ module.exports = function setup(fsOptions) {
}
function unextend(name, options, callback) {
+ if (apis[name] && apis[name].destroy)
+ apis[name].destroy();
+
delete apis[name];
callback(null, {});
}
diff --git a/node_modules/vfs-socket/worker.js b/node_modules/vfs-socket/worker.js
index 1d8547d6..9512eb96 100644
--- a/node_modules/vfs-socket/worker.js
+++ b/node_modules/vfs-socket/worker.js
@@ -162,6 +162,9 @@ function Worker(vfs) {
var nextStreamID = 1;
function storeStream(stream) {
+ if (stream.token)
+ return stream.token;
+
nextStreamID = (nextStreamID + 1) % 10000;
while (streams.hasOwnProperty(nextStreamID)) { nextStreamID = (nextStreamID + 1) % 10000; }
var id = nextStreamID;
@@ -188,6 +191,7 @@ function Worker(vfs) {
remote.onClose(id);
});
var token = {id: id};
+ stream.token = token;
if (stream.hasOwnProperty("readable")) token.readable = stream.readable;
if (stream.hasOwnProperty("writable")) token.writable = stream.writable;
return token;
@@ -195,6 +199,9 @@ function Worker(vfs) {
function storeProcess(process, onlyPid) {
var pid = process.pid;
+ if (processes.token)
+ return onlyPid ? process.pid : process.token;
+
processes[pid] = process;
process.on("exit", function (code, signal) {
delete processes[pid];
@@ -215,11 +222,13 @@ function Worker(vfs) {
code: code
}, callback || function() {});
};
+
+ var token = {pid: pid};
+ process.token = token;
if (onlyPid)
return pid;
- var token = {pid: pid};
token.stdin = storeStream(process.stdin);
token.stdout = storeStream(process.stdout);
token.stderr = storeStream(process.stderr);
@@ -230,8 +239,8 @@ function Worker(vfs) {
if (!pty || processes[pty.pid] == pty) // Pty is returned twice
return pty && pty.token;
- var pid = storeProcess(pty, true);
- var token = storeStream(pty);
+ var pid = storeProcess(pty, true); delete pty.token;
+ var token = storeStream(pty); delete pty.token;
token.pid = pid;
pty.token = token;
diff --git a/package.json b/package.json
index 2dc5c639..0a942d39 100644
--- a/package.json
+++ b/package.json
@@ -60,12 +60,12 @@
"c9.ide.language.javascript.tern": "#7aab8b0b6a",
"c9.ide.language.javascript.infer": "#cfec494a3c",
"c9.ide.language.jsonalyzer": "#21b64e5820",
- "c9.ide.collab": "#edef363853",
+ "c9.ide.collab": "#da4d09ae6a",
"c9.ide.local": "#2bfd7ff051",
"c9.ide.find": "#6cc6d3379d",
"c9.ide.find.infiles": "#72582de3cd",
"c9.ide.find.replace": "#e4daf722b8",
- "c9.ide.run.debug": "#638e6b00b3",
+ "c9.ide.run.debug": "#23a188b91a",
"c9.automate": "#47e2c429c9",
"c9.ide.ace.emmet": "#e5f1a92ac3",
"c9.ide.ace.gotoline": "#4d1a93172c",
@@ -81,9 +81,9 @@
"c9.ide.fontawesome": "#781602c5d8",
"c9.ide.format": "#f51451ac57",
"c9.ide.help.support": "#60e88f5680",
- "c9.ide.imgeditor": "#08bbc53578",
+ "c9.ide.imgeditor": "#ed89162aa7",
"c9.ide.immediate": "#6845a93705",
- "c9.ide.installer": "#a1e01c07a3",
+ "c9.ide.installer": "#9bfeb1f703",
"c9.ide.mount": "#32e79866ee",
"c9.ide.navigate": "#64156c7f4a",
"c9.ide.newresource": "#f1f0624768",
@@ -99,7 +99,7 @@
"c9.ide.run": "#71c5562e42",
"c9.ide.run.build": "#ad45874c88",
"c9.ide.run.debug.xdebug": "#b91d23f48b",
- "c9.ide.save": "#b876d87d55",
+ "c9.ide.save": "#3cb206c168",
"c9.ide.terminal.monitor": "#b0b4d03280",
"c9.ide.theme.flat": "#b1d65fa9bb",
"c9.ide.threewaymerge": "#229382aa0b",
diff --git a/plugins/c9.cli.bridge/bridge-client.js b/plugins/c9.cli.bridge/bridge-client.js
index a283cf0c..f27353be 100644
--- a/plugins/c9.cli.bridge/bridge-client.js
+++ b/plugins/c9.cli.bridge/bridge-client.js
@@ -5,7 +5,7 @@
*/
define(function(require, exports, module) {
main.consumes = ["c9", "Plugin", "net"];
- main.provides = ["bridge-client"];
+ main.provides = ["bridge.client"];
return main;
function main(options, imports, register) {
@@ -13,27 +13,61 @@ define(function(require, exports, module) {
var c9 = imports.c9;
var net = imports.net;
+ var JSONStream = require("./json-stream");
+
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
// var emit = plugin.getEmitter();
- var PORT = options.port || 17123;
+ var counter = 0;
+ var SOCKET = c9.platform == "win32"
+ ? "\\\\.\\pipe\\.c9\\bridge.socket"
+ : c9.home + "/.c9/bridge.socket";
/***** Methods *****/
function send(message, callback) {
- net.connect(PORT, {}, function(err, stream) {
+ net.connect(SOCKET, {}, function(err, stream) {
if (err)
return callback(err);
- stream.write(JSON.stringify(message));
- stream.end();
+ var jstream = new JSONStream(stream);
+ var msgId = generateMessageId();
+ var done;
- callback();
+ jstream.write({
+ id: msgId,
+ message: message
+ });
+
+ jstream.on("data", function(payload){
+ if (payload.id == msgId && !done) {
+ done = true;
+ callback(null, payload.message);
+ stream.end();
+ }
+ });
+
+ jstream.on("error", function(err){
+ if (done) return;
+ callback(err);
+ done = true;
+ });
+
+ jstream.on("close", function(){
+ if (done) return;
+ callback(new Error("No Response"));
+ done = true;
+ })
});
}
+ function generateMessageId(){
+ // Use vfs token
+ return Math.random() + "-" + ++counter;
+ }
+
/***** Lifecycle *****/
plugin.on("load", function(){
@@ -55,7 +89,7 @@ define(function(require, exports, module) {
});
register(null, {
- "bridge-client": plugin
+ "bridge.client": plugin
});
}
});
\ No newline at end of file
diff --git a/plugins/c9.cli.bridge/bridge-service.js b/plugins/c9.cli.bridge/bridge-service.js
index fd6543b9..77e900c7 100644
--- a/plugins/c9.cli.bridge/bridge-service.js
+++ b/plugins/c9.cli.bridge/bridge-service.js
@@ -1,37 +1,128 @@
module.exports = function (vfs, options, register) {
+ var stream;
+
+ var net = require("net");
var Stream = require('stream');
- var stream, server;
+
+ var SOCKET = process.platform == "win32"
+ ? "\\\\.\\pipe\\.c9\\bridge.socket"
+ : process.env.HOME + "/.c9/bridge.socket";
+
+ function createListenClient(api){
+ var client = net.connect(SOCKET, function(data){
+ if (data) api.onData(data);
+ });
+ client.setEncoding("utf8");
+ client.unref();
+
+ client.on("data", function(data){
+ if (data) api.onData(data);
+ });
+
+ client.on("error", function(err){
+ if (err.code == "ECONNREFUSED") {
+ require("fs").unlink(SOCKET, function(){
+ createListenServer(api);
+ });
+ }
+ else if (err.code == "ENOENT") {
+ createListenServer(api);
+ }
+ else
+ api.onError(err);
+ });
+
+ client.on("end", function(){
+ createListenServer(api);
+ });
+
+ api.onConnect(client);
+
+ api.disconnect = function(){
+ client.end();
+ };
+
+ return client;
+ }
+
+ function createListenServer(api){
+ // var timeout = setTimeout(function(){
+ // unixServer.close();
+ // }, 500);
+
+ var unixServer = net.createServer(function(client) {
+ client.setEncoding("utf8");
+
+ client.on("data", function(data){
+ if (data) api.onData(data);
+ });
+
+ client.on("error", function(data){
+ // console.error("ERROR", api.id, data);
+ });
+
+ api.onConnect(client);
+ });
+ unixServer.listen(SOCKET);
+
+ unixServer.on("error", function(err){
+ if (err.code == "EADDRINUSE") {
+ createListenClient(api);
+ }
+ else
+ api.onError(err);
+ });
+
+ api.disconnect = function(){
+ unixServer.close();
+ };
+ }
register(null, {
- connect: function (port, callback) {
+ connect: function (callback) {
if (stream) return callback(null, { stream: stream });
- server = require('net').createServer(function(c) {
- var buffer = "";
- c.on("data", function(chunk) {
- buffer += chunk;
- });
- c.on("end", function(){
- stream.emit("data", buffer);
- });
- });
- server.on("error", function(err) {
- callback(err);
- });
- server.listen(port, process.env.OPENSHIFT_DIY_IP || "localhost", function(err) {
- if (err) return callback(err);
- callback(null, { stream: stream });
- });
-
stream = new Stream();
stream.readable = true;
+ stream.writable = true;
+
+ var client;
+ var sent = false;
+ var api = this.api = {
+ id: Math.random(),
+ onConnect: function(c){
+ client = c;
+ if (sent) return;
+
+ callback(null, { stream: stream });
+ sent = true;
+ },
+ onData: function(data){
+ stream && stream.emit("data", data);
+ },
+ onError: function(err){
+ stream && stream.emit("error", err);
+ }
+ };
+
+ // createListenServer
+ createListenClient(api);
+
+ stream.write = function(data){
+ if (client) client.write(data);
+ };
},
disconnect: function(){
- try { server && server.close(); }
+ try { this.api && this.api.disconnect(); }
catch (e) {}
+
stream = null;
- server = null;
+ delete this.api;
+ },
+
+ destroy: function(){
+ this.disconnect();
}
});
};
\ No newline at end of file
diff --git a/plugins/c9.cli.bridge/bridge.js b/plugins/c9.cli.bridge/bridge.js
index bf39c7bc..d1396622 100644
--- a/plugins/c9.cli.bridge/bridge.js
+++ b/plugins/c9.cli.bridge/bridge.js
@@ -1,4 +1,3 @@
-
define(function(require, exports, module) {
main.consumes = ["c9", "Plugin", "ext"];
main.provides = ["bridge"];
@@ -8,6 +7,8 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var c9 = imports.c9;
var ext = imports.ext;
+
+ var JSONStream = require("./json-stream");
/***** Initialization *****/
@@ -15,15 +16,10 @@ define(function(require, exports, module) {
var emit = plugin.getEmitter();
var ENABLED = options.startBridge !== false;
- var PORT = options.port || 17123;
var stream, api;
- var loaded = false;
function load(){
- if (loaded) return;
- loaded = true;
-
if (!ENABLED) return;
ext.loadRemotePlugin("bridge", {
@@ -35,58 +31,62 @@ define(function(require, exports, module) {
api = remote;
- api.connect(PORT, function(err, meta) {
- if (err) {
- loaded = false;
+ api.connect(function(err, meta) {
+ if (err)
+ return console.error(err); // this should never happen
- if (err.code == "EADDRINUSE") {
- console.warn("Another Application is using port "
- + PORT + ". CLI client interface disabled. Restart Cloud9 to retry connecting.");
- }
- else
- console.error(err);
-
- return;
- }
-
- stream = meta.stream;
-
- stream.on("data", function(chunk) {
- try { var message = JSON.parse(chunk); }
- catch (e) {
- setTimeout(function(){
- loaded = false;
- load();
- }, 60000);
- return;
- }
- emit("message", { message: message });
+ stream = new JSONStream(meta.stream);
+
+ stream.on("error", function(err) {
+ console.error(err);
+ });
+
+ stream.on("data", function(payload) {
+ emit("message", {
+ message: payload.message,
+ respond: function(err, message){
+ stream.write({
+ id: payload.id,
+ message: message,
+ error: err
+ });
+ }
+ });
+
});
stream.on("close", function(){
- loaded = false;
+ load();
});
+
+ emit.sticky("ready");
});
});
- window.addEventListener("unload", unload);
+ window.addEventListener("unload", function(){
+ api && api.disconnect();
+ });
}
- function unload() {
- api && api.disconnect();
- api = stream = null;
- loaded = false;
+ function write(json){
+ if (!stream) {
+ plugin.once("ready", function(){ write(json); });
+ return;
+ }
+
+ stream.write(json);
}
-
+
/***** Methods *****/
plugin.on("load", function(){
c9.on("connect", load, plugin);
- c9.on("disconnect", unload, plugin);
});
plugin.on("unload", function(){
api && api.disconnect();
+ stream = null;
+ api = null;
});
/***** Register and define API *****/
@@ -94,7 +94,12 @@ define(function(require, exports, module) {
/**
* Bridge To Communicate from CLI to IDE
**/
- plugin.freezePublicAPI({ });
+ plugin.freezePublicAPI({
+ /**
+ *
+ */
+ write: write
+ });
register(null, {
bridge: plugin
diff --git a/plugins/c9.cli.bridge/bridge_commands.js b/plugins/c9.cli.bridge/bridge_commands.js
index 496af20a..bf64a756 100644
--- a/plugins/c9.cli.bridge/bridge_commands.js
+++ b/plugins/c9.cli.bridge/bridge_commands.js
@@ -1,20 +1,25 @@
define(function(require, exports, module) {
main.consumes = [
- "Plugin", "bridge", "tabManager", "panels",
- "tree.favorites", "tree", "fs"
+ "Plugin", "bridge", "tabManager", "panels", "tree.favorites", "tree",
+ "fs", "preferences", "settings", "c9"
];
- main.provides = ["bridge_commands"];
+ main.provides = ["bridge.commands"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var bridge = imports.bridge;
- var tabs = imports.tabManager;
+ var tabManager = imports.tabManager;
var panels = imports.panels;
var tree = imports.tree;
+ var settings = imports.settings;
var favs = imports["tree.favorites"];
var fs = imports.fs;
+ var c9 = imports.c9;
+ var prefs = imports.preferences;
+
+ var async = require("async");
/***** Initialization *****/
@@ -23,36 +28,62 @@ define(function(require, exports, module) {
var BASEPATH = options.basePath;
- var loaded = false;
function load(){
- if (loaded) return;
- loaded = true;
-
bridge.on("message", function(e) {
var message = e.message;
switch (message.type) {
case "open":
- open(message);
+ open(message, e.respond);
break;
case "ping":
+ e.respond(null, true);
+ break;
+ default:
+ console.error("Unknown Bridge Command: ", message.type);
break;
}
- });
+ }, plugin);
+
+ settings.on("read", function(e) {
+ settings.setDefaults("user/terminal", [
+ ["defaultEditor", "true"]
+ ]);
+ }, plugin);
+
+ prefs.add({
+ "Editors" : {
+ "Terminal" : {
+ "Use Cloud9 as the Default Editor" : {
+ type: "checkbox",
+ path: "user/terminal/@defaultEditor",
+ position: 14000
+ }
+ }
+ }
+ }, plugin);
}
/***** Methods *****/
- function open(message) {
- message.paths.forEach(function(info, i) {
+ function open(message, callback) {
+ var i = -1;
+ var tabs = [];
+ BASEPATH = c9.toInternalPath(BASEPATH);
+
+ async.each(message.paths, function(info, next) {
var path = info.path;
+ i++;
+ path = c9.toInternalPath(path);
// Make sure file is inside workspace
- if (path.substr(0, BASEPATH.length) !== BASEPATH)
- return;
-
- // Remove base path
- path = path.substr(BASEPATH.length);
+ if (path.charAt(0) !== "~") {
+ if (path.substr(0, BASEPATH.length) !== BASEPATH)
+ return; // Dont' call callback. Perhaps another client will pick this up.
+
+ // Remove base path
+ path = path.substr(BASEPATH.length);
+ }
if (info.type == "directory") {
path = path.replace(/\/$/, "");
@@ -61,26 +92,45 @@ define(function(require, exports, module) {
var node = favs.addFavorite(path);
- tree.expand(path, function(err) {
+ tree.expand(path, function() {
tree.select(node); //path || "/");
tree.scrollToSelection();
+ next();
});
tree.focus();
}
else {
- tabs.once("ready", function(){
+ tabManager.once("ready", function(){
fs.exists(path, function(existing) {
- tabs.open({
+ var tab = tabManager.open({
path: path,
active: i === 0,
document:
existing
? undefined
: { meta : { newfile: true } }
- }, function(){});
+ }, function(){
+ next();
+ });
+
+ if (message.wait) {
+ tab.on("close", function(){
+ tabs.splice(tabs.indexOf(tab), 1);
+ if (!tabs.length)
+ callback(null, true);
+ });
+ }
+
+ tabs.push(tab);
});
});
}
+ }, function(err){
+ if (err)
+ return callback(err);
+
+ if (!message.wait || !tabs.length)
+ callback(null, true);
});
}
@@ -102,7 +152,7 @@ define(function(require, exports, module) {
plugin.freezePublicAPI({});
register(null, {
- "bridge_commands": plugin
+ "bridge.commands": plugin
});
}
});
diff --git a/plugins/c9.cli.bridge/bridge_test.js b/plugins/c9.cli.bridge/bridge_test.js
index 253d9cca..ccb93842 100644
--- a/plugins/c9.cli.bridge/bridge_test.js
+++ b/plugins/c9.cli.bridge/bridge_test.js
@@ -2,7 +2,7 @@
"use client";
-require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) {
+require(["lib/architect/architect", "lib/chai/chai", "/vfs-root", "/vfs-home"], function (architect, chai, basePath, homePath) {
var expect = chai.expect;
var Assert = chai.assert;
@@ -14,46 +14,70 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
debug: true,
hosted: true,
local: false,
- davPrefix: "/"
+ davPrefix: "/",
+ home: homePath
},
"plugins/c9.core/ext",
"plugins/c9.core/http-xhr",
"plugins/c9.core/util",
+ "plugins/c9.ide.ui/lib_apf",
"plugins/c9.ide.ui/ui",
"plugins/c9.core/settings",
- //"plugins/c9.ide.collab/collab",
"plugins/c9.vfs.client/vfs_client",
"plugins/c9.vfs.client/endpoint",
"plugins/c9.ide.auth/auth",
"plugins/c9.fs/fs",
+ "plugins/c9.fs/net",
+
+ {
+ packagePath: "plugins/c9.cli.bridge/bridge",
+ startBridge: true
+ },
+ {
+ packagePath: "plugins/c9.cli.bridge/bridge_commands",
+ basePath: basePath
+ },
+ "plugins/c9.cli.bridge/bridge-client",
// Mock plugins
{
- consumes: ["ui"],
+ consumes: [],
provides: [
- "preferences", "dialog.error"
+ "preferences", "ui"
],
setup: expect.html.mocked
},
{
- consumes: ["collab"],
+ consumes: ["bridge", "bridge.client"],
provides: [],
setup: main
}
], architect);
function main(options, imports, register) {
- var collab = imports.collab;
+ var bridge = imports.bridge;
+ var client = imports["bridge.client"];
- describe('collab', function() {
- this.timeout(10000);
+ describe('bridge', function() {
+ // this.timeout(10000);
- describe("connect", function(){
- it('should connect', function(done) {
- collab.connect(null, function(err, stream) {
- if (err) throw err.message;
- });
+ before(function(done){
+ bridge.on("ready", function(){
+ done();
+ });
+ });
+
+ it('send and receive messages', function(done) {
+ bridge.on("message", function(e){
+ if (e.message.hello) {
+ e.respond(null, { "hi": true });
+ }
+ });
+ client.send({ "hello": true }, function(err, message){
+ if (err) throw err.message;
+ expect(message).property("hi").to.be.ok;
+ done();
});
});
});
diff --git a/plugins/c9.cli.bridge/json-stream.js b/plugins/c9.cli.bridge/json-stream.js
new file mode 100644
index 00000000..1f48ed05
--- /dev/null
+++ b/plugins/c9.cli.bridge/json-stream.js
@@ -0,0 +1,47 @@
+define(function(require, exports, module) {
+
+var EventEmitter = require("events").EventEmitter;
+
+module.exports = function(stream) {
+ var emit = this.emit.bind(this);
+
+ var buffer = "";
+ stream.on("data", function(chunk) {
+ buffer += chunk;
+
+ var parts = buffer.split("\n");
+ while (parts.length) {
+ try {
+ var message = JSON.parse(parts[0]);
+ emit("data", message);
+ parts.shift();
+ }
+ catch (e) {
+ if (parts.length !== 1) {
+ emit("error", e);
+ parts.shift();
+ }
+ else {
+ break;
+ }
+ }
+ }
+ buffer = parts.join("\n");
+ });
+
+ stream.on("error", function(err){
+ emit("error", err);
+ });
+
+ stream.on("close", function(data){
+ emit("close", data);
+ });
+
+ this.write = function(data) {
+ stream.write(JSON.stringify(data) + "\n");
+ };
+};
+
+module.exports.prototype = new EventEmitter();
+
+});
\ No newline at end of file
diff --git a/plugins/c9.cli.open/open.js b/plugins/c9.cli.open/open.js
index 0ef32d02..d186f500 100755
--- a/plugins/c9.cli.open/open.js
+++ b/plugins/c9.cli.open/open.js
@@ -1,5 +1,5 @@
define(function(require, exports, module) {
- main.consumes = ["Plugin", "cli_commands", "proc", "bridge-client"];
+ main.consumes = ["Plugin", "cli_commands", "proc", "bridge.client"];
main.provides = ["open"];
return main;
@@ -7,7 +7,7 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var cmd = imports.cli_commands;
var proc = imports.proc;
- var bridge = imports["bridge-client"];
+ var bridge = imports["bridge.client"];
var fs = require("fs");
var PATH = require("path");
@@ -25,11 +25,12 @@ define(function(require, exports, module) {
cmd.addCommand({
name: "open",
info: " Opens a file or directory.",
- usage: "",
+ usage: "[--wait] ",
options: {
- "path" : {
- description: "Specify the path that will be opened",
- default: false
+ "wait": {
+ description: "Wait until the file(s) are closed",
+ "default": false,
+ "boolean": true
}
},
check: function(argv) {
@@ -39,6 +40,7 @@ define(function(require, exports, module) {
exec: function(argv) {
open(
argv._.slice(1), // Remove "open" from the paths
+ argv.wait,
function(){});
}
});
@@ -46,12 +48,16 @@ define(function(require, exports, module) {
/***** Methods *****/
- function open(paths, callback) {
+ function open(paths, wait, callback) {
try {
paths = paths.map(function(path) {
var isDir = fs.existsSync(path) && fs.statSync(path).isDirectory();
+ path = PATH.resolve(path);
+ if (path.substr(0, process.env.HOME.length) == process.env.HOME)
+ path = "~" + path.substr(process.env.HOME.length);
+
return {
- path: "/" + PATH.resolve(path),
+ path: path,
type: isDir ? "directory" : "file"
};
});
@@ -65,6 +71,7 @@ define(function(require, exports, module) {
paths.forEach(function(info) {
var path = info.type == "directory"
? info.path : PATH.dirname(info.path);
+
if (!last) {
last = path;
}
@@ -86,11 +93,12 @@ define(function(require, exports, module) {
var message = {
type: "open",
workspace: "local",
+ wait: wait,
// cwd : cwd,
paths: paths
};
- bridge.send(message, function cb(err) {
+ bridge.send(message, function cb(err, response) {
if (err) {
if (err.code == "ECONNREFUSED") {
// Seems Cloud9 is not running, lets start it up
@@ -111,6 +119,9 @@ define(function(require, exports, module) {
console.log(err.message);
}
+ if (response !== true)
+ console.log("Could not open ", paths);
+
process.exit(); // I don't get why this is needed
});
}
@@ -129,13 +140,16 @@ define(function(require, exports, module) {
var timed = Date.now();
(function retry(){
- bridge.send({ type: "ping" }, function(err) {
+ bridge.send({ type: "ping" }, function(err, message) {
if (!err)
return callback(true);
if (Date.now() - timed > 10000)
return callback(false);
+ if (message !== true)
+ return callback(false);
+
setTimeout(retry, 100);
});
})();
diff --git a/plugins/c9.cli.publish/install.js b/plugins/c9.cli.publish/install.js
index b1643e22..ce82d09c 100644
--- a/plugins/c9.cli.publish/install.js
+++ b/plugins/c9.cli.publish/install.js
@@ -77,10 +77,6 @@ define(function(require, exports, module) {
"default": false,
"boolean": true
},
- "package" : {
- description: "",
- "default": false
- },
"verbose" : {
"description": "Output more information",
"alias": "v",
@@ -131,7 +127,7 @@ define(function(require, exports, module) {
process.exit(1);
}
else {
- console.log("Succesfully installed", name + (argv.debug ? "" : "@" + data.version));
+ console.log("Successfully installed", name + (argv.debug ? "" : "@" + data.version));
process.exit(0);
}
});
@@ -140,6 +136,7 @@ define(function(require, exports, module) {
cmd.addCommand({
name: "remove",
+ alias: "uninstall",
info: " Removes a cloud9 package.",
usage: "[--verbose] [--global] [--local] ", // @TODO --global
options: {
@@ -153,9 +150,6 @@ define(function(require, exports, module) {
"default": false,
"boolean": true
},
- "package" : {
- description: ""
- },
"verbose" : {
"description": "Output more information",
"alias": "v",
@@ -186,7 +180,7 @@ define(function(require, exports, module) {
process.exit(1);
}
else {
- console.log("Succesfully removed", name);
+ console.log("Successfully removed", name);
process.exit(0);
}
});
@@ -387,8 +381,8 @@ define(function(require, exports, module) {
if (verbose)
console.log("Installing debug version of package");
- if (!options.test)
- return callback(new Error("Dry run is not supported for debug installations"));
+ if (options.test)
+ return callback(new Error("Test is not supported for debug installations"));
prepareDirectory(function(err, packagePath){
if (err) return callback(err);
diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js
index 8bb04348..e79214bd 100644
--- a/plugins/c9.cli.publish/publish.js
+++ b/plugins/c9.cli.publish/publish.js
@@ -88,8 +88,7 @@ define(function(require, exports, module) {
}
},
check: function(argv) {
- // if (argv._.length < 2 && !argv["newversion"] && !argv["dry-run"])
- // throw new Error("Missing version");
+
},
exec: function(argv) {
verbose = argv["verbose"];
@@ -438,9 +437,9 @@ define(function(require, exports, module) {
var path = join(cwd, json.installer);
var installerCode = fs.readFileSync(path, "utf8");
- var m = installerCode.match(/\.version\s*=\s*(\d+)/g);
+ var m = installerCode.match(/\.version\s*=\s*(\d+)/);
- var installerVersion = m && m[0];
+ var installerVersion = m && m[1];
if (!installerVersion)
return callback(new Error("ERROR: missing installer version in " + json.installer));
extraCode.push({
@@ -724,7 +723,7 @@ define(function(require, exports, module) {
request.on('response', function(res) {
// TODO better handle version exists error
- if (res.statusCode == 412 && !version)
+ if (res.statusCode == 412)
console.error("ERROR: most likely version " + json.version + " already exisits, try increasing version");
if (res.statusCode != 200)
return callback(new Error("ERROR: Unknown Error:" + res.statusCode));
diff --git a/plugins/c9.cli/auth.bootstrap.js b/plugins/c9.cli/auth.bootstrap.js
index a24fd471..684225f1 100644
--- a/plugins/c9.cli/auth.bootstrap.js
+++ b/plugins/c9.cli/auth.bootstrap.js
@@ -66,7 +66,6 @@ define(function(require, exports, module) {
}, function(err, token) {
if (err) return callback(err);
-
fs.writeFile(AUTHPATH, token, function(err){
if (err) return callback(err);
callback(null, lastToken = token);
diff --git a/plugins/c9.cli/cli.js b/plugins/c9.cli/cli.js
index 4a5923fc..6c0ec08a 100755
--- a/plugins/c9.cli/cli.js
+++ b/plugins/c9.cli/cli.js
@@ -7,6 +7,9 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var cmd = imports.cli_commands;
+ var fs = require("fs");
+ var resolve = require("path").resolve;
+
var optimist;
/***** Initialization *****/
@@ -21,7 +24,7 @@ define(function(require, exports, module) {
var module;
var argv;
- process.argv.slice(2).some(function(n){
+ process.argv.slice(2).some(function(n) {
if (!n.match(/^[-\/]/) && n != "node") {
module = n;
return true;
@@ -29,6 +32,18 @@ define(function(require, exports, module) {
return false;
});
+ if (!commands[module] && process.argv.length > 2) {
+ for (var i = 2; i < process.argv.length; i++) {
+ if (process.argv[i].charAt(0) == "-") continue;
+ var path = resolve(process.argv[i]);
+ if (fs.existsSync(path)) {
+ process.argv.splice(2, 0, "open");
+ module = "open";
+ }
+ break;
+ }
+ }
+
optimist = require('optimist');
if (!module || !commands[module]) {
@@ -62,6 +77,12 @@ define(function(require, exports, module) {
argv = optimist
.usage("The Cloud9 CLI.\nUsage: c9 " + module + " [--help] " + def.usage)
.options(def.options);
+
+ if (argv.argv.help)
+ argv = argv.check(function(){
+ if (argv.help)
+ throw new Error("Help Requested");
+ });
if (def.check)
argv = argv.check(def.check);
argv = argv.argv;
diff --git a/plugins/c9.fs/fs.js b/plugins/c9.fs/fs.js
index a3145076..376f68fb 100644
--- a/plugins/c9.fs/fs.js
+++ b/plugins/c9.fs/fs.js
@@ -55,7 +55,7 @@ define(function(require, exports, module) {
loaded = true;
if (options.cli)
- plugin.on("error", function(e){ console.error(e.error); });
+ plugin.on("error", function(e){ }); // Prevent exception
}
function wrap(name, fn) {
diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js
index 4609d862..a06b159e 100644
--- a/plugins/c9.ide.ace/ace.js
+++ b/plugins/c9.ide.ace/ace.js
@@ -40,13 +40,14 @@ define(function(require, exports, module) {
var lang = require("ace/lib/lang");
var Range = require("ace/range").Range;
var config = require("ace/config");
- var AceEditor = require("ace/editor").Editor;
var Document = require("ace/document").Document;
+ var AceEditor = require("ace/editor").Editor;
var EditSession = require("ace/edit_session").EditSession;
+ var UndoManager = require("ace/undomanager").UndoManager;
+ var whitespaceUtil = require("ace/ext/whitespace");
var defaultCommands = require("ace/commands/default_commands").commands;
var VirtualRenderer = require("ace/virtual_renderer").VirtualRenderer;
var multiSelectCommands = require("ace/multi_select").commands;
- var whitespaceUtil = require("ace/ext/whitespace");
// enable multiselect
require("ace/multi_select");
@@ -281,100 +282,169 @@ define(function(require, exports, module) {
/***** Undo Manager *****/
function AceUndoManager(undoManager, session) {
+ var state = undoManager.getState();
this.$session = session;
this.$undo = undoManager;
- var _self = this;
- var Item = this.Item;
- this.$undo.on("itemFind", function(e) {
- return Item(_self, e.state);
- });
+ this.$aceUndo = new UndoManager();
+ this.$aceUndo.c9UndoProxy = undoManager;
+ undoManager.$aceUndo = this.$aceUndo;
+ undoManager.add = this.add;
+ undoManager.addSelection = this.addSelection;
+ undoManager.undo = this.undo;
+ undoManager.redo = this.redo;
+ undoManager.reset = this.reset;
+ undoManager.canUndo = this.canUndo;
+ undoManager.canRedo = this.canRedo;
+ undoManager.getState = this.getState;
+ undoManager.setState = this.setState;
+ undoManager.bookmark = this.bookmarkPosition;
+ undoManager.isAtBookmark = this.isAtBookmark;
+ undoManager.__defineGetter__("position", this.getPosition);
+ undoManager.__defineGetter__("length", this.getLength);
+ undoManager._emit = this._emit = undoManager.getEmitter();
+
+ this.deleyedEmit = lang.delayedCall(this._emit.bind(null, "change"))
+ .schedule.bind(null, 0);
+ this.setState(state, true);
+ }
+ function updateDeltas(deltas) {
+ if (deltas[0] && deltas[0].deltas) {
+ var oldDeltas = deltas.slice();
+ deltas.length = 0;
+ oldDeltas.forEach(function(x) {
+ deltas.push.apply(deltas, x.deltas);
+ });
+ }
+ return deltas;
}
AceUndoManager.prototype = {
- Item: function(_self, deltas) {
- return {
- undo: function(){
- _self.$session.session.undoChanges(deltas, _self.dontSelect);
- },
- redo: function(){
- _self.$session.session.redoChanges(deltas, _self.dontSelect);
- },
- getState: function(){
- return deltas.filter(function (d) {
- return d.group != "fold";
- });
- }
- };
+ add: function(delta, doc) {
+ this.$aceUndo.add(delta, doc);
+ this._emit("change");
},
-
- execute: function(options) {
- if (options.merge && this.lastDeltas) {
- this.lastDeltas.push.apply(this.lastDeltas, options.args[0]);
- } else {
- this.lastDeltas = options.args[0];
- this.$undo.add(this.Item(this, this.lastDeltas));
- }
+ addSelection: function(range, rev) {
+ this.$aceUndo.addSelection(range, rev);
},
-
undo: function(dontSelect) {
- this.dontSelect = dontSelect;
- this.$undo.undo();
+ this.$aceUndo.undo(dontSelect);
+ this._emit("change");
},
redo: function(dontSelect) {
- this.dontSelect = dontSelect;
- this.$undo.redo();
+ this.$aceUndo.redo(dontSelect);
+ this._emit("change");
},
reset: function(){
- this.$undo.reset();
+ this.$aceUndo.reset();
+ this._emit("change");
},
- hasUndo: function() {
- return this.$undo.length > this.$undo.position + 1;
+ canUndo: function() {
+ return this.$aceUndo.canUndo();
},
- hasRedo: function() {
- return this.$undo.length <= this.$undo.position + 1;
+ canRedo: function() {
+ return this.$aceUndo.canRedo();
},
- get $undoStack() {
- return this.$undo.stack.slice(0, this.$undo.position + 1)
- .map(function(e){ return e.getState ? e.getState() : e });
+ clearUndo: function() {
+ this.$aceUndo.$undoStack = [];
+ this._emit("change");
+ },
+ clearRedo: function() {
+ this.$aceUndo.$redoStack = [];
+ this._emit("change");
+ },
+ startNewGroup: function() {
+ return this.$aceUndo.startNewGroup();
+ },
+ markIgnored: function(from, to) {
+ return this.$aceUndo.markIgnored(from, to);
+ },
+ getState: function() {
+ var aceUndo = this.$aceUndo;
+ var mark = -1;
+ var aceMark = aceUndo.mark;
+ var stack = [];
+ function transform(deltaSet) {
+ var newDelta = deltaSet.filter(function (d) {
+ if (d.id == aceMark) mark = stack.length;
+ return d.action == "insert" || d.action == "remove";
+ });
+ stack.push(newDelta);
+ }
+ aceUndo.$undoStack.forEach(transform);
+ if (aceUndo.$redoStackBaseRev == aceUndo.$rev)
+ aceUndo.$redoStack.forEach(transform);
+ return {
+ stack: stack,
+ mark: mark,
+ position: aceUndo.$undoStack.length - 1
+ };
+ },
+ setState: function(e, silent) {
+ var aceUndo = this.$aceUndo;
+ var stack = e.stack || [];
+ var marked = stack[e.mark] && stack[e.mark][0];
+ var pos = e.position + 1;
+ var undo = stack.slice(0, pos);
+ var redo = stack.slice(pos);
+ aceUndo.$undoStack = undo.filter(function(x) {
+ return x.length;
+ }).map(updateDeltas);
+ aceUndo.$redoStack = redo.filter(function(x) {
+ return x.length;
+ }).map(updateDeltas);
+ stack = aceUndo.$undoStack;
+ var lastDeltaGroup = stack[stack.length - 1];
+ var lastRev = lastDeltaGroup && lastDeltaGroup[0].id || 0;
+ aceUndo.$rev = lastRev;
+ aceUndo.$redoStackBaseRev = aceUndo.$rev;
+ aceUndo.$maxRev = Math.max(aceUndo.$maxRev, lastRev);
+ var markedRev = marked && marked.id;
+ if (markedRev != null)
+ this.$aceUndo.bookmark(markedRev);
+ else if (e.mark == e.position)
+ this.$aceUndo.bookmark();
+ else
+ this.$aceUndo.bookmark(-1);
+ silent || this._emit("change");
+ },
+ isAtBookmark: function() {
+ return this.$aceUndo.isAtBookmark();
+ },
+ bookmark: function(rev) {
+ this.$aceUndo.bookmark(rev);
+ this._emit("change");
+ },
+ bookmarkPosition: function(index) {
+ if (index > -1) {
+ var stack = this.$aceUndo.$undoStack;
+ if (index >= stack.length) {
+ index -= stack.length;
+ stack = this.$aceUndo.$redoStack;
+ index = stack.length - index;
+ }
+ var deltaSet = stack[index];
+ var rev = deltaSet && deltaSet[0] && deltaSet[0].id;
+ if (rev == null) rev = -1;
+ this.$aceUndo.bookmark(rev);
+ } else if (index == -1) {
+ this.$aceUndo.bookmark(0);
+ } else {
+ this.$aceUndo.bookmark(index);
+ }
+ this._emit("change");
+ },
+ addSession: function(session) {
+ this.$aceUndo.addSession(session);
+ },
+ getPosition: function() {
+ var aceUndo = this.$aceUndo;
+ return aceUndo.$undoStack.length - 1;
+ },
+ getLength: function() {
+ var aceUndo = this.$aceUndo;
+ return aceUndo.$undoStack.length + aceUndo.$redoStack.length;
}
};
- function UndoManagerProxy(undoManager, session) {
- this.$u = undoManager;
- this.$doc = session;
- }
-
- (function() {
- this.execute = function(options) {
- this.$u.execute(options);
- };
-
- this.undo = function() {
- var selectionRange = this.$u.undo(true);
- if (selectionRange) {
- this.$doc.selection.setSelectionRange(selectionRange);
- }
- };
-
- this.redo = function() {
- var selectionRange = this.$u.redo(true);
- if (selectionRange) {
- this.$doc.selection.setSelectionRange(selectionRange);
- }
- };
-
- this.reset = function() {
- this.$u.reset();
- };
-
- this.hasUndo = function() {
- return this.$u.hasUndo();
- };
-
- this.hasRedo = function() {
- return this.$u.hasRedo();
- };
- }).call(UndoManagerProxy.prototype);
-
/***** Generic Load *****/
handle.on("load", function(){
@@ -1370,8 +1440,7 @@ define(function(require, exports, module) {
if (!undoManager)
undoManager = session.getUndoManager();
if (undoManager) {
- var undoManagerProxy = new UndoManagerProxy(undoManager, s);
- s.setUndoManager(undoManagerProxy);
+ s.setUndoManager(undoManager);
}
// Overwrite the default $informUndoManager function such that new deltas
@@ -2172,9 +2241,9 @@ define(function(require, exports, module) {
var c9Session = doc.getSession();
// if load starts from another editor type
- // tabmanager will show as instantly
+ // tabmanager will show us instantly
// so we need to show progress bar instantly
- progress.noFadeIn = !currentDocument;
+ progress.noFadeIn = !currentDocument || !currentDocument.tab.active;
// Value Retrieval
doc.on("getValue", function get(e) {
diff --git a/plugins/c9.ide.auth/auth.js b/plugins/c9.ide.auth/auth.js
index 8508ba0f..54fd2633 100644
--- a/plugins/c9.ide.auth/auth.js
+++ b/plugins/c9.ide.auth/auth.js
@@ -80,7 +80,10 @@ define(function(require, exports, module) {
request(apiUrl + "/user", function(err, user) {
if (err || !user) {
- console.warn("LOGIN: API /user err", err);
+ if (options.cli)
+ console.warn("Invalid username or password. Please try again.");
+ else
+ console.warn("LOGIN: API /user err", err);
return setTimeout(login, 1000);
}
diff --git a/plugins/c9.ide.dialog.common/alert_internal.js b/plugins/c9.ide.dialog.common/alert_internal.js
index 2b527375..c76edc94 100644
--- a/plugins/c9.ide.dialog.common/alert_internal.js
+++ b/plugins/c9.ide.dialog.common/alert_internal.js
@@ -1,11 +1,12 @@
define(function(require, module, exports) {
- main.consumes = ["Dialog", "util", "dialog.alert"];
+ main.consumes = ["Dialog", "util", "dialog.alert", "metrics"];
main.provides = ["dialog.alert_internal"];
return main;
function main(options, imports, register) {
var Dialog = imports.Dialog;
var util = imports.util;
+ var metrics = imports.metrics;
var alertWrapper = imports["dialog.alert"];
/***** Initialization *****/
@@ -25,6 +26,8 @@ define(function(require, module, exports) {
/***** Methods *****/
function show(title, header, msg, onhide, options) {
+ metrics.increment("dialog.error");
+
return plugin.queue(function(){
if (header === undefined) {
plugin.title = "Notice";
diff --git a/plugins/c9.ide.dialog.common/error.js b/plugins/c9.ide.dialog.common/error.js
index 7a6cfde5..4b4142e6 100644
--- a/plugins/c9.ide.dialog.common/error.js
+++ b/plugins/c9.ide.dialog.common/error.js
@@ -1,13 +1,14 @@
define(function(require, exports, module) {
"use strict";
- main.consumes = ["Plugin", "ui"];
+ main.consumes = ["Plugin", "ui", "metrics"];
main.provides = ["dialog.error"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var ui = imports.ui;
+ var metrics = imports.metrics;
/***** Initialization *****/
@@ -84,6 +85,8 @@ define(function(require, exports, module) {
}
function show(message, timeout) {
+ metrics.increment("dialog.error");
+
// Error message container
if (!error) {
error = document.body.appendChild(document.createElement("div"));
diff --git a/plugins/c9.ide.editors/document.js b/plugins/c9.ide.editors/document.js
index c305ad8f..6c7174c5 100644
--- a/plugins/c9.ide.editors/document.js
+++ b/plugins/c9.ide.editors/document.js
@@ -43,7 +43,7 @@ define(function(require, module, exports) {
function initUndo(){
undoManager.on("change", function(e) {
var c = !undoManager.isAtBookmark();
- if (changed !== c || undoManager.position == -1) {
+ if (changed !== c) {
changed = c;
emit("changed", { changed: c });
}
@@ -60,26 +60,24 @@ define(function(require, module, exports) {
}
var state = getState();
- undoManager.once("change", function(){
- // Bookmark the undo manager
- undoManager.bookmark();
-
- // Update state
- delete state.changed;
- delete state.value;
- delete state.meta;
- state.undoManager = undoManager.getState();
-
- if (cleansed && editor && state[editor.type])
- state[editor.type].cleansed = true;
-
- // Set new state (preserving original state)
- if (emit("mergeState") !== false)
- setState(state);
- });
-
// Record value (which should add an undo stack item)
plugin.value = value;
+
+ // Bookmark the undo manager
+ undoManager.bookmark();
+
+ // Update state
+ delete state.changed;
+ delete state.value;
+ delete state.meta;
+ state.undoManager = undoManager.getState();
+
+ if (cleansed && editor && state[editor.type])
+ state[editor.type].cleansed = true;
+
+ // Set new state (preserving original state)
+ if (emit("mergeState") !== false)
+ setState(state);
}
function getState(filter) {
diff --git a/plugins/c9.ide.editors/undomanager.js b/plugins/c9.ide.editors/undomanager.js
index 6ab1adc9..db1e90a0 100644
--- a/plugins/c9.ide.editors/undomanager.js
+++ b/plugins/c9.ide.editors/undomanager.js
@@ -10,7 +10,7 @@ define(function(require, module, exports) {
var plugin = new Plugin("Ajax.org", main.consumes);
var emit = plugin.getEmitter();
- var position = -1, mark = null, stack = [];
+ var position = -1, mark = -2, stack = [];
if (options)
setState(options);
@@ -55,7 +55,7 @@ define(function(require, module, exports) {
position = 0;
if (mark < position)
- mark = -1;
+ mark = -2;
emit("change");
}
@@ -64,7 +64,7 @@ define(function(require, module, exports) {
stack = stack.slice(0, position + 1);
if (mark > position)
- mark = -1;
+ mark = -2;
if (!noEvent)
emit("change");
@@ -91,7 +91,7 @@ define(function(require, module, exports) {
position--;
if (mark == idx)
- mark = -1;
+ mark = -2;
else if (mark > idx)
mark--;
@@ -105,8 +105,7 @@ define(function(require, module, exports) {
}
function isAtBookmark(){
- return mark !== null && mark == position
- || mark === null && position == -1;
+ return mark == position;
}
function item(idx) {
@@ -133,7 +132,7 @@ define(function(require, module, exports) {
return; // guard against broken stack
stack = state.stack;
- emit("change"); //If you remove this again, change the test
+ emit("change"); // If you remove this again, change the test
}
function findItem(compressedItem) {
@@ -146,11 +145,13 @@ define(function(require, module, exports) {
position = -1;
stack = [];
- mark = null;
+ mark = -1;
emit("change");
}
+ plugin.freezePublicAPI.baseclass();
+
/**
* The Undo Manager class of Cloud9. Each {@link Document}
* has a single instance of the undo manager that
@@ -213,10 +214,6 @@ define(function(require, module, exports) {
*
**/
plugin.freezePublicAPI({
- /**
- * @ignore
- */
- get stack() { return stack; },
/**
* The number of items on the stack. This number will stay the
* same when using {@link UndoManager#undo} and
diff --git a/plugins/c9.ide.editors/undomanager_test.js b/plugins/c9.ide.editors/undomanager_test.js
index b7624924..a3c57ada 100644
--- a/plugins/c9.ide.editors/undomanager_test.js
+++ b/plugins/c9.ide.editors/undomanager_test.js
@@ -133,7 +133,7 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
expect(undo.position).to.equal(4);
undo.undo(); check++;
- undo.setState({ position : -1, stack : stack, mark : null }); check++;
+ undo.setState({ position : -1, stack : stack, mark : -1 }); check++;
expect(undo.isAtBookmark()).to.equal(true);
expect(data).to.deep.equal(["a", "q"]);
checkCount();
diff --git a/plugins/c9.ide.errorhandler/raygun_error_handler.js b/plugins/c9.ide.errorhandler/raygun_error_handler.js
index 3c3dcca8..82ddc557 100644
--- a/plugins/c9.ide.errorhandler/raygun_error_handler.js
+++ b/plugins/c9.ide.errorhandler/raygun_error_handler.js
@@ -8,7 +8,7 @@ define(function(require, exports, module) {
"use strict";
main.consumes = [
- "Plugin", "info"
+ "Plugin", "info", "metrics"
];
main.provides = ["error_handler"];
return main;
@@ -16,6 +16,7 @@ define(function(require, exports, module) {
function main(options, imports, register) {
var Plugin = imports.Plugin;
var info = imports.info;
+ var metrics = imports.metrics;
/***** Initialization *****/
@@ -57,7 +58,8 @@ define(function(require, exports, module) {
Raygun.setVersion(version + ".0");
}
- function reportError(exception, customData, tags) {
+ function log(exception, customData, tags) {
+ metrics.increment("errorhandler.log");
if (typeof exception === "string")
exception = new Error(exception);
if (!exception)
@@ -78,8 +80,8 @@ define(function(require, exports, module) {
plugin.freezePublicAPI({
/** @deprecated Use log() instead. */
- reportError: reportError,
- log: reportError
+ reportError: log,
+ log: log
});
register(null, { "error_handler" : plugin });
diff --git a/plugins/c9.ide.plugins/installer.js b/plugins/c9.ide.plugins/installer.js
index 2e102bae..152e1824 100644
--- a/plugins/c9.ide.plugins/installer.js
+++ b/plugins/c9.ide.plugins/installer.js
@@ -1,6 +1,6 @@
define(function(require, exports, module) {
main.consumes = [
- "Plugin", "proc", "c9", "pubsub", "auth", "util"
+ "Plugin", "proc", "c9", "pubsub", "auth", "util", "installer"
];
main.provides = ["plugin.installer"];
return main;
@@ -12,6 +12,9 @@ define(function(require, exports, module) {
var proc = imports.proc;
var auth = imports.auth;
var pubsub = imports.pubsub;
+ var installer = imports.installer;
+
+ var async = require("async");
var escapeShell = util.escapeShell;
var updates = options.updates;
@@ -20,11 +23,10 @@ define(function(require, exports, module) {
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
- // var emit = plugin.getEmitter();
+ var emit = plugin.getEmitter();
var HASSDK = c9.location.indexOf("sdk=0") === -1;
- var queue = [];
var installing;
var loaded = false;
@@ -69,87 +71,66 @@ define(function(require, exports, module) {
// return;
// }
- if (!config.length) return;
+ if (!config.length)
+ return callback && callback();
- var found = {};
- config.forEach(function(item){
- if (!found[item.packageName])
- found[item.packageName] = true;
- else return;
-
- queue.push({ name: item.packageName, version: item.version });
-
- if (installing)
- installing.push(item);
- });
-
- if (installing) return;
- installing = config;
-
- var i = 0;
- function next(err){
- if (err) console.log(err);
-
- if (!queue[i]) {
- installing = false; queue = [];
- architect.loadAdditionalPlugins(config, callback);
- return;
- }
-
- installPlugin(queue[i].name, queue[i].version, next);
- i++;
+ // Only run one installer at a time
+ if (installing) {
+ return plugin.once("finished", function(){
+ installPlugins(config, callback);
+ });
}
- next();
+ installing = true;
+
+ var found = {}, packages = [];
+ config.forEach(function(item){
+ if (!found[item.name])
+ found[item.name] = true;
+ else return;
+
+ packages.push({ name: item.name, version: item.version });
+ });
+
+ async.eachSeries(packages, function(pkg, next){
+ installPlugin(pkg.name, pkg.version, next);
+ }, function(err){
+ installing = false;
+ emit("finished");
+
+ if (err) {
+ console.error(err.message);
+ return callback && callback(err);
+ }
+
+ architect.loadAdditionalPlugins(config, callback);
+ });
}
function installPlugin(name, version, callback){
- proc.spawn("bash", {
- args: ["-c", ["c9", "install", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name) + "@" + escapeShell(version)].join(" ")]
- }, function(err, process){
- if (err) return callback(err);
-
- process.stdout.on("data", function(c){
- console.log(c);
- });
- process.stderr.on("data", function(c){
- console.error(c);
+ // Headless installation of the plugin
+ installer.createSession(name, version, function(session, options){
+ session.install({
+ "bash": "c9 install --local --force --accessToken=" + auth.accessToken
+ + " " + escapeShell(name) + "@" + escapeShell(version)
});
- process.on("exit", function(code){
- if (code) {
- var error = new Error(err);
- error.code = code;
- return callback(error);
- }
- callback();
- });
- });
+ // Force to start immediately
+ session.start(callback, true);
+ }, function(){}, 2); // Force to not be administered
}
function uninstallPlugin(name, callback){
- proc.spawn("c9", {
- args: ["remove", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name)]
- }, function(err, process){
- if (err) return callback(err);
-
- var res = null;
- process.stdout.on("data", function(c){
- res = c.toString("utf8");
- });
- process.stderr.on("data", function(c){
- err = c.toString("utf8");
+ // Headless uninstallation of the plugin
+ installer.createSession(name, -1, function(session, options){
+ session.install({
+ "bash": "c9 remove --local --force --accessToken=" + auth.accessToken
+ + " " + escapeShell(name)
});
- process.on("exit", function(code){
- if (code) {
- var error = new Error(err);
- error.code = code;
- return callback(error);
- }
- callback(null, res);
- });
- });
+ // Force to start immediately
+ session.start(callback, true);
+ }, function(){}, 2); // Force to not be administered
}
/***** Lifecycle *****/
@@ -160,7 +141,6 @@ define(function(require, exports, module) {
plugin.on("unload", function() {
loaded = false;
installing = false;
- queue = [];
});
/***** Register and define API *****/
@@ -180,6 +160,11 @@ define(function(require, exports, module) {
*/
installPlugins: installPlugins,
+ /**
+ *
+ */
+ installPlugin: installPlugin,
+
/**
*
*/
diff --git a/plugins/c9.ide.plugins/manager.js b/plugins/c9.ide.plugins/manager.js
index 77294880..63c96f60 100644
--- a/plugins/c9.ide.plugins/manager.js
+++ b/plugins/c9.ide.plugins/manager.js
@@ -85,7 +85,9 @@ define(function(require, exports, module) {
};
var TEMPLATES = {
"plugin.simple": "Empty Plugin",
- "plugin.default": "Full Plugin"
+ "plugin.default": "Full Plugin",
+ "plugin.installer": "Installer Plugin",
+ "plugin.bundle": "Cloud9 Bundle"
};
// @TODO add sorting
@@ -102,7 +104,6 @@ define(function(require, exports, module) {
// var emit = plugin.getEmitter();
var HASSDK = c9.location.indexOf("sdk=0") === -1;
- var ENABLED = c9.location.indexOf("sdk=1") > -1;
var model, datagrid, filterbox;
var btnUninstall, btnReport, btnReadme, btnCloud9, btnReload;
@@ -125,20 +126,18 @@ define(function(require, exports, module) {
// updateCommandsFromSettings();
// }, plugin);
- if (ENABLED) {
- menus.addItemByPath("File/New Plugin", null, 210, plugin);
- Object.keys(TEMPLATES).forEach(function(name){
- menus.addItemByPath("File/New Plugin/" + TEMPLATES[name], new ui.item({
- onclick: function(){
- createNewPlugin(name);
- }
- }), 210, plugin);
- });
-
- ext.on("register", function(){
- setTimeout(reloadModel);
- });
- }
+ menus.addItemByPath("File/New Plugin", null, 210, plugin);
+ Object.keys(TEMPLATES).forEach(function(name){
+ menus.addItemByPath("File/New Plugin/" + TEMPLATES[name], new ui.item({
+ onclick: function(){
+ createNewPlugin(name);
+ }
+ }), 210, plugin);
+ });
+
+ ext.on("register", function(){
+ setTimeout(reloadModel);
+ });
}
var drawn;
diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.html b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.html
new file mode 100644
index 00000000..d8688f81
--- /dev/null
+++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.html
@@ -0,0 +1 @@
+Hello World
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.js
new file mode 100644
index 00000000..3dca2f71
--- /dev/null
+++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin.js
@@ -0,0 +1,155 @@
+define(function(require, exports, module) {
+ main.consumes = [
+ "Plugin", "ui", "commands", "menus", "preferences", "settings"
+ ];
+ main.provides = ["myplugin"];
+ return main;
+
+ function main(options, imports, register) {
+ var Plugin = imports.Plugin;
+ var ui = imports.ui;
+ var menus = imports.menus;
+ var commands = imports.commands;
+ var settings = imports.settings;
+ var prefs = imports.preferences;
+
+ /***** Initialization *****/
+
+ var plugin = new Plugin("Ajax.org", main.consumes);
+ var emit = plugin.getEmitter();
+
+ var showing;
+ function load() {
+ commands.addCommand({
+ name: "mycommand",
+ bindKey: { mac: "Command-I", win: "Ctrl-I" },
+ isAvailable: function(){ return true; },
+ exec: function() {
+ showing ? hide() : show();
+ }
+ }, plugin);
+
+ menus.addItemByPath("Tools/My Menu Item", new ui.item({
+ command: "mycommand"
+ }), 300, plugin);
+
+ settings.on("read", function(e){
+ settings.setDefaults("user/my-plugin", [
+ ["first", "1"],
+ ["second", "all"]
+ ]);
+ });
+
+ prefs.add({
+ "Example" : {
+ position: 450,
+ "My Plugin" : {
+ position: 100,
+ "First Setting": {
+ type: "checkbox",
+ path: "user/my-plugin/@first",
+ position: 100
+ },
+ "Second Setting": {
+ type: "dropdown",
+ path: "user/my-plugin/@second",
+ width: "185",
+ position: 200,
+ items: [
+ { value: "you", caption: "You" },
+ { value: "me", caption: "Me" },
+ { value: "all", caption: "All" }
+ ]
+ }
+ }
+ }
+ }, plugin);
+ }
+
+ var drawn = false;
+ function draw() {
+ if (drawn) return;
+ drawn = true;
+
+ // Insert HTML
+ var markup = require("text!./plugin.html");
+ ui.insertHtml(document.body, markup, plugin);
+
+ // Insert CSS
+ ui.insertCss(require("text!./style.css"), options.staticPrefix, plugin);
+
+ emit("draw");
+ }
+
+ /***** Methods *****/
+
+ function show() {
+ draw();
+
+ var div = document.querySelector(".helloworld");
+ div.style.display = "block";
+ div.innerHTML = settings.get("user/my-plugin/@second");
+
+ emit("show");
+ showing = true;
+ }
+
+ function hide() {
+ if (!drawn) return;
+
+ document.querySelector(".helloworld").style.display = "none";
+
+ emit("hide");
+ showing = false;
+ }
+
+ /***** Lifecycle *****/
+
+ plugin.on("load", function() {
+ load();
+ });
+ plugin.on("unload", function() {
+ drawn = false;
+ showing = false;
+ });
+
+ /***** Register and define API *****/
+
+ /**
+ * This is an example of an implementation of a plugin.
+ * @singleton
+ */
+ plugin.freezePublicAPI({
+ /**
+ * @property showing whether this plugin is being shown
+ */
+ get showing(){ return showing; },
+
+ _events: [
+ /**
+ * @event show The plugin is shown
+ */
+ "show",
+
+ /**
+ * @event hide The plugin is hidden
+ */
+ "hide"
+ ],
+
+ /**
+ * Show the plugin
+ */
+ show: show,
+
+ /**
+ * Hide the plugin
+ */
+ hide: hide,
+ });
+
+ register(null, {
+ "myplugin": plugin
+ });
+ }
+});
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin_test.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin_test.js
new file mode 100644
index 00000000..3ae2262d
--- /dev/null
+++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/plugin_test.js
@@ -0,0 +1,41 @@
+"use client";
+"use mocha";
+
+define(function(require, exports, module) {
+ main.consumes = ["plugin.test", "myplugin"];
+ main.provides = [];
+ return main;
+
+ function main(options, imports, register) {
+ var test = imports["plugin.test"];
+ var myplugin = imports.myplugin;
+
+ var describe = test.describe;
+ var it = test.it;
+ var before = test.before;
+ var after = test.after;
+ var beforeEach = test.beforeEach;
+ var afterEach = test.afterEach;
+ var assert = test.assert;
+ var expect = test.expect;
+
+ /***** Initialization *****/
+
+ describe(myplugin.name, function(){
+ this.timeout(2000);
+
+ it("shows a helloworld div", function() {
+ myplugin.show();
+ expect(document.querySelector(".helloworld")).to.ok;
+ expect(document.querySelector(".helloworld").innerText).to.equal("all");
+ });
+
+ it("hides the div", function() {
+ myplugin.hide();
+ expect(document.querySelector(".helloworld").offsetHeight).to.not.ok;
+ });
+ });
+
+ register(null, {});
+ }
+});
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/market.js b/plugins/c9.ide.plugins/packages.js
similarity index 63%
rename from plugins/c9.ide.plugins/market.js
rename to plugins/c9.ide.plugins/packages.js
index 592f9bc6..4b466aef 100644
--- a/plugins/c9.ide.plugins/market.js
+++ b/plugins/c9.ide.plugins/packages.js
@@ -3,7 +3,7 @@ define(function(require, exports, module) {
"Editor", "editors", "ui", "commands", "menus", "layout",
"tabManager", "util", "settings", "api", "c9"
];
- main.provides = ["plugin.market"];
+ main.provides = ["plugin.packages"];
return main;
function main(options, imports, register) {
@@ -24,17 +24,17 @@ define(function(require, exports, module) {
var extensions = [];
var packages = {};
- var handle = editors.register("plugin.market", "Market Place",
- MarketPlace, extensions);
+ var handle = editors.register("plugin.packages", "Package Browser",
+ PackageBrowser, extensions);
var emit = handle.getEmitter();
emit.setMaxListeners(1000);
- var HASSDK = c9.location.indexOf("sdk=1") > -1;
+ var HASSDK = c9.location.indexOf("sdk=0") === -1;
- function focusOpenMarket(){
+ function focusOpenPackages(){
var pages = tabs.getTabs();
for (var i = 0, tab = pages[i]; tab; tab = pages[i++]) {
- if (tab.editorType == "plugin.market") {
+ if (tab.editorType == "plugin.packages") {
tabs.focusTab(tab);
return true;
}
@@ -49,29 +49,30 @@ define(function(require, exports, module) {
});
commands.addCommand({
- name: "openmarketplace",
- hint: "open the market place",
+ name: "openpackagebrowser",
+ hint: "open the package browser",
group: "General",
// bindKey: { mac: "Command-,", win: "Ctrl-," },
exec: function () {
var tab = tabs.focussedTab;
- if (tab && tab.editor.type == "plugin.market") {
+ if (tab && tab.editor.type == "plugin.packages") {
tab.close();
return;
}
- if (focusOpenMarket())
+ if (focusOpenPackages())
return;
tabs.open({
- editorType: "plugin.market",
+ editorType: "plugin.packages",
active: true
}, function(){});
}
}, handle);
- menus.addItemByPath("Cloud9/Plugin Store", new ui.item({
- command: "openmarketplace"
- }), 301, handle);
+ menus.addItemByPath("Cloud9/~", new ui.divider(), 1000, handle);
+ menus.addItemByPath("Cloud9/Package Browser", new ui.item({
+ command: "openpackagebrowser"
+ }), 1100, handle);
});
/***** Methods *****/
@@ -123,10 +124,10 @@ define(function(require, exports, module) {
/***** Editor *****/
- function MarketPlace(){
+ function PackageBrowser(){
var plugin = new Editor("Ajax.org", main.consumes, extensions);
//var emit = plugin.getEmitter();
- var tab;
+ var tab, iframe;
plugin.on("resize", function(e) {
emit("resize", e);
@@ -136,33 +137,15 @@ define(function(require, exports, module) {
tab = e.tab;
var htmlNode = e.htmlNode;
- api.packages.get("", function(err, list){
- if (c9.standalone) {
- err = null;
- list = [{ name: "example", apikey:"0000000000000000000000000000=", packagePath: "plugins/c9.example/example" }];
- }
-
- if (err) return;
-
- var sHtml = "";
- list.forEach(function(plugin){ // @todo use react instead in an iframe
- packages[plugin.name] = plugin;
-
- sHtml += "";
- });
-
- htmlNode.innerHTML = sHtml;
- htmlNode.addEventListener("click", function(e){
- if (e.target.tagName == "A") {
- installPlugin(e.target.getAttribute("plugin-name"),
- e.target.getAttribute("target"), function(){});
- }
- });
- });
+ htmlNode.style.paddingTop = 0;
+
+ iframe = htmlNode.appendChild(document.createElement("iframe"));
+ iframe.style.width = "100%";
+ iframe.style.height = "100%";
+ iframe.style.border = 0;
+ iframe.style.backgroundColor = "#fbfbfb";
+
+ iframe.src = location.origin.replace("ide.", "") + "/profile/packages?nobar=1&pid=" + c9.projectId;
});
plugin.on("getState", function(e) {
@@ -174,12 +157,11 @@ define(function(require, exports, module) {
plugin.on("documentLoad", function(e) {
var doc = e.doc;
- doc.title = "Plugin Store";
+ doc.title = "Package Browser";
function setTheme(){
- // var bg = ui.getStyleRule(".bar-preferences .container .header", "backgroundColor") || "#F0F0F0";
- var bg = "#FFF";
- doc.tab.backgroundColor = bg; //"#2d2d2d";
+ var bg = "#fbfbfb";
+ doc.tab.backgroundColor = bg;
if (util.shadeColor(bg, 1).isLight)
doc.tab.classList.remove("dark");
@@ -192,14 +174,7 @@ define(function(require, exports, module) {
});
plugin.on("documentActivate", function(e) {
- e.doc.tab.on("unload", function(){
- if (parent.parentNode == tab)
- tab.removeChild(parent);
- });
- tab.appendChild(parent);
-
- emit("show");
});
/***** Register and define API *****/
@@ -212,13 +187,13 @@ define(function(require, exports, module) {
});
- plugin.load(null, "plugin.market");
+ plugin.load(null, "plugin.packages");
return plugin;
}
register(null, {
- "plugin.market": handle
+ "plugin.packages": handle
});
}
});
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.bundle/README.md b/plugins/c9.ide.plugins/templates/plugin.bundle/README.md
new file mode 100644
index 00000000..143f51ff
--- /dev/null
+++ b/plugins/c9.ide.plugins/templates/plugin.bundle/README.md
@@ -0,0 +1 @@
+This is the Cloud9 bundle example
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.bundle/package.json b/plugins/c9.ide.plugins/templates/plugin.bundle/package.json
new file mode 100644
index 00000000..dd39f32a
--- /dev/null
+++ b/plugins/c9.ide.plugins/templates/plugin.bundle/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "",
+ "description": "",
+ "version": "0.0.1",
+ "author": "",
+ "contributors": [
+ {
+ "name": "",
+ "email": ""
+ }
+ ],
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "plugins": {},
+ "categories": [
+ "misc"
+ ],
+ "licenses": []
+}
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.default/README.md b/plugins/c9.ide.plugins/templates/plugin.default/README.md
index 6d7f5b94..600c4e28 100644
--- a/plugins/c9.ide.plugins/templates/plugin.default/README.md
+++ b/plugins/c9.ide.plugins/templates/plugin.default/README.md
@@ -1,3 +1 @@
-# c9.ide.example
-
This is the Cloud9 default plugin example
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.default/package.json b/plugins/c9.ide.plugins/templates/plugin.default/package.json
index 174c0262..3364c37a 100644
--- a/plugins/c9.ide.plugins/templates/plugin.default/package.json
+++ b/plugins/c9.ide.plugins/templates/plugin.default/package.json
@@ -1,5 +1,5 @@
{
- "name": "c9.ide.default",
+ "name": "",
"description": "",
"version": "0.0.1",
"author": "",
diff --git a/plugins/c9.ide.plugins/templates/plugin.installer/README.md b/plugins/c9.ide.plugins/templates/plugin.installer/README.md
new file mode 100644
index 00000000..9de9f3a9
--- /dev/null
+++ b/plugins/c9.ide.plugins/templates/plugin.installer/README.md
@@ -0,0 +1 @@
+This is the Cloud9 installer plugin example
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.installer/install.js b/plugins/c9.ide.plugins/templates/plugin.installer/install.js
new file mode 100644
index 00000000..f87bdec5
--- /dev/null
+++ b/plugins/c9.ide.plugins/templates/plugin.installer/install.js
@@ -0,0 +1,57 @@
+define(function(require, exports, module) {
+
+module.exports = function(session, options){
+ // Dependencies for the collaboration features of Cloud9
+
+ session.install({
+ "name": "SQLite",
+ "description": "SQLite Database and NPM module",
+ "cwd": "~/.c9",
+ "optional": true
+ }, [
+ {
+ "npm": ["sqlite3@3.0.5"]
+ },
+ {
+ "tar.gz": {
+ "url": "https://raw.githubusercontent.com/c9/install/master/packages/sqlite3/linux/sqlite3.tar.gz",
+ "target": "~/.c9/lib/sqlite3",
+ "dir": "sqlite3"
+ }
+ },
+ {
+ "symlink": {
+ "source": "~/.c9/lib/sqlite3/sqlite3",
+ "target": "~/.c9/bin/sqlite3"
+ }
+ }
+ ]);
+
+ session.install({
+ "name": "Sequalize",
+ "description": "Sequalize NPM module",
+ "cwd": "~/.c9",
+ "optional": true
+ }, {
+ "npm": ["sequelize@2.0.0-beta.0"]
+ });
+
+ session.install({
+ "name": "Collab Server",
+ "description": "A small Node.js collaboration server",
+ "cwd": "~/.c9",
+ "optional": true
+ }, {
+ "tar.gz": {
+ "url": "https://raw.githubusercontent.com/c9/install/master/packages/extend/c9-vfs-extend.tar.gz",
+ "target": "~/.c9"
+ }
+ });
+
+ // Show the installation screen
+ session.start();
+};
+
+module.exports.version = 1;
+
+});
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.installer/package.json b/plugins/c9.ide.plugins/templates/plugin.installer/package.json
new file mode 100644
index 00000000..9013bf77
--- /dev/null
+++ b/plugins/c9.ide.plugins/templates/plugin.installer/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "",
+ "description": "",
+ "version": "0.0.1",
+ "author": "",
+ "contributors": [
+ {
+ "name": "",
+ "email": ""
+ }
+ ],
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "plugins": {},
+ "installer": "install.js",
+ "categories": [
+ "misc"
+ ],
+ "licenses": []
+}
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.simple/README.md b/plugins/c9.ide.plugins/templates/plugin.simple/README.md
index 566c1196..8ac7218b 100644
--- a/plugins/c9.ide.plugins/templates/plugin.simple/README.md
+++ b/plugins/c9.ide.plugins/templates/plugin.simple/README.md
@@ -1,3 +1 @@
-# c9.ide.simple
-
This is the Cloud9 simple plugin example
\ No newline at end of file
diff --git a/plugins/c9.ide.plugins/templates/plugin.simple/package.json b/plugins/c9.ide.plugins/templates/plugin.simple/package.json
index f782d88e..3364c37a 100644
--- a/plugins/c9.ide.plugins/templates/plugin.simple/package.json
+++ b/plugins/c9.ide.plugins/templates/plugin.simple/package.json
@@ -1,5 +1,5 @@
{
- "name": "c9.ide.simple",
+ "name": "",
"description": "",
"version": "0.0.1",
"author": "",
diff --git a/plugins/c9.ide.terminal/terminal.js b/plugins/c9.ide.terminal/terminal.js
index dcc8e9a0..05954eb6 100644
--- a/plugins/c9.ide.terminal/terminal.js
+++ b/plugins/c9.ide.terminal/terminal.js
@@ -750,6 +750,9 @@ define(function(require, exports, module) {
session.__defineGetter__("tab", function(){ return doc.tab });
session.__defineGetter__("doc", function(){ return doc });
+ session.__defineGetter__("defaultEditor", function(){
+ return settings.getBool("user/terminal/@defaultEditor");
+ });
session.attach = function(){
if (session.aceSession && aceterm) {
diff --git a/plugins/c9.ide.terminal/tmux_connection.js b/plugins/c9.ide.terminal/tmux_connection.js
index fafcfadb..1576ee80 100644
--- a/plugins/c9.ide.terminal/tmux_connection.js
+++ b/plugins/c9.ide.terminal/tmux_connection.js
@@ -157,6 +157,7 @@ module.exports = function(c9, proc, installPath, shell) {
options.output = false;
options.terminal = true;
options.detachOthers = !session.hasConnected;
+ options.defaultEditor = session.defaultEditor;
}
// Connect to backend and start tmux session
diff --git a/plugins/c9.ide.watcher/gui.js b/plugins/c9.ide.watcher/gui.js
index a4489de9..6bf4147a 100644
--- a/plugins/c9.ide.watcher/gui.js
+++ b/plugins/c9.ide.watcher/gui.js
@@ -309,11 +309,8 @@ define(function(require, exports, module) {
doc.meta.$mergeRoot = data;
// If the value on disk is the same as in the document, set the bookmark
- if (mergedValue == data) {
- doc.undoManager.once("change", function(){
- doc.undoManager.bookmark();
- });
- }
+ if (mergedValue == data)
+ doc.undoManager.bookmark();
return true;
}
diff --git a/plugins/c9.nodeapi/events.js b/plugins/c9.nodeapi/events.js
index 5bf4e755..027cace5 100644
--- a/plugins/c9.nodeapi/events.js
+++ b/plugins/c9.nodeapi/events.js
@@ -146,7 +146,7 @@ EventEmitter.prototype.addListener = function(type, listener, plugin) {
if (m && m > 0 && eventList.length > m) {
eventList.warned = true;
- console.error('(node) warning: possible EventEmitter memory '
+ console.error('warning: possible EventEmitter memory '
+ 'leak detected. " + eventList.length + " listeners of type "' + type + '" added. '
+ 'Use emitter.setMaxListeners() to increase limit.'
);
diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js
index 137f8680..5779888e 100644
--- a/plugins/c9.vfs.standalone/standalone.js
+++ b/plugins/c9.vfs.standalone/standalone.js
@@ -156,6 +156,14 @@ function plugin(options, imports, register) {
res.end("define(function(require, exports, module) { return '"
+ options.workspaceDir + "'; });");
});
+ api.get("/vfs-home", function(req, res, next) {
+ if (!options.options.testing)
+ return next();
+
+ res.writeHead(200, {"Content-Type": "application/javascript"});
+ res.end("define(function(require, exports, module) { return '"
+ + process.env.HOME + "'; });");
+ });
api.get("/update", function(req, res, next) {
res.writeHead(200, {
diff --git a/plugins/c9.vfs.standalone/www/test.js b/plugins/c9.vfs.standalone/www/test.js
index cce8b53b..2b3ea410 100644
--- a/plugins/c9.vfs.standalone/www/test.js
+++ b/plugins/c9.vfs.standalone/www/test.js
@@ -195,6 +195,7 @@ require([
})(),
log: {},
http: {},
+ ui: {},
api: {
stats: {
post: function(type, message, cb) {
@@ -414,8 +415,13 @@ require([
"metrics": {
getLastPing: function() { throw Error("Not implemented"); },
getLastest: function() { throw Error("Not implemented"); },
+ log: function() {},
+ increment: function() {}
+ },
+ error_handler: {
+ log: function() {},
+ reportError: function(){}
},
- error_handler: {reportError: function(){}},
proc: {
execFile: function() {},
spawn: function() {}
diff --git a/settings/standalone.js b/settings/standalone.js
index c65482db..4fd9ac74 100644
--- a/settings/standalone.js
+++ b/settings/standalone.js
@@ -28,6 +28,7 @@ module.exports = function(manifest, installPath) {
var config = {
standalone: true,
+ startBridge: true,
manifest: manifest,
workspaceDir: workspaceDir,
projectName: path.basename(workspaceDir),