diff --git a/configs/cli.js b/configs/cli.js index 8d95eff0..2a4be963 100644 --- a/configs/cli.js +++ b/configs/cli.js @@ -119,7 +119,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 5aa0cf6b..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", @@ -618,7 +618,6 @@ module.exports = function(options) { }, { packagePath: "plugins/c9.cli.bridge/bridge", - port: 17123, startBridge: options.startBridge }, { 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 8e54ffa6..5d1c846d 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "c9.ide.help.support": "#60e88f5680", "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#6845a93705", - "c9.ide.installer": "#a1e01c07a3", + "c9.ide.installer": "#6f8f44c9e1", "c9.ide.mount": "#32e79866ee", "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#f1f0624768", 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..1ea7e584 100644 --- a/plugins/c9.cli.publish/install.js +++ b/plugins/c9.cli.publish/install.js @@ -140,6 +140,7 @@ define(function(require, exports, module) { cmd.addCommand({ name: "remove", + alias: "uninstall", info: " Removes a cloud9 package.", usage: "[--verbose] [--global] [--local] ", // @TODO --global options: { @@ -387,8 +388,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..be5acac7 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({ 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.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 += "
" - + "" + plugin.name + " | " - + "Install In Workspace | " - + "Install To User" - + "
"; - }); - - 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.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 9ef583e1..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) { 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),