diff --git a/configs/client-default.js b/configs/client-default.js index bc382dff..ad581a8a 100644 --- a/configs/client-default.js +++ b/configs/client-default.js @@ -240,6 +240,7 @@ module.exports = function(options) { }, "plugins/c9.ide.ui/widgets.tree", "plugins/c9.ide.ui/widgets.datagrid", + "plugins/c9.ide.ui/widgets.terminal", "plugins/c9.ide.ui/focus", "plugins/c9.ide.ui/lib_apf", diff --git a/package.json b/package.json index 9ca614d0..71822a2e 100644 --- a/package.json +++ b/package.json @@ -59,14 +59,14 @@ "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#cfec494a3c", - "c9.ide.language.jsonalyzer": "#a1057f20db", - "c9.ide.collab": "#7b09419b5c", + "c9.ide.language.jsonalyzer": "#21b64e5820", + "c9.ide.collab": "#504750d8f0", "c9.ide.local": "#cf624506cc", - "c9.ide.find": "#bd9f11c08f", + "c9.ide.find": "#6cc6d3379d", "c9.ide.find.infiles": "#72582de3cd", "c9.ide.find.replace": "#e4daf722b8", "c9.ide.run.debug": "#638e6b00b3", - "c9.automate": "#86bf1ee1ca", + "c9.automate": "#b1b0cca13a", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#43445d6306", @@ -77,13 +77,13 @@ "c9.ide.behaviors": "#6aad7006a0", "c9.ide.closeconfirmation": "#a28bfd8272", "c9.ide.configuration": "#f309bb47d2", - "c9.ide.dialog.wizard": "#c6401bdd13", + "c9.ide.dialog.wizard": "#ea640aa5a1", "c9.ide.fontawesome": "#781602c5d8", "c9.ide.format": "#f51451ac57", "c9.ide.help.support": "#60e88f5680", "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#6845a93705", - "c9.ide.installer": "#38f5840924", + "c9.ide.installer": "#75413dd79a", "c9.ide.mount": "#cb45b621f1", "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#f1f0624768", diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js index b812bc4e..75fdbef2 100644 --- a/plugins/c9.cli.publish/publish.js +++ b/plugins/c9.cli.publish/publish.js @@ -631,7 +631,7 @@ define(function(require, exports, module) { additional.push({ id: path, source: 'define("' + path + '", [],' + - JSON.stringify(packedConfig, null, 4) + ')', + JSON.stringify(packedConfig, null, 4) + ');', literal : true, order: -1 }); diff --git a/plugins/c9.ide.dialog/dialog.js b/plugins/c9.ide.dialog/dialog.js index c2b5da11..7cfbb603 100644 --- a/plugins/c9.ide.dialog/dialog.js +++ b/plugins/c9.ide.dialog/dialog.js @@ -130,6 +130,9 @@ define(function(require, module, exports) { if (allowClose && e.keyCode == 27) dialog.hide(); }); + dialog.on("resize", function(){ + emit("resize"); + }); commands.addCommand({ name: plugin.name, @@ -254,7 +257,7 @@ define(function(require, module, exports) { // @todo this looks very similar to forms.js. Perhaps able to merge? function createItem(heading, name, options) { - var position = options.position || count++; + var position = options.position || (count += 100); var node; switch(options.type) { @@ -511,6 +514,13 @@ define(function(require, module, exports) { */ "hide" ], + + /** + * + */ + createElement: function(options){ + createItem(null, null, options); + }, /** * Updates form elements with new values. This method currently diff --git a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less index d35f07fc..6c792f2a 100644 --- a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less +++ b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less @@ -1606,8 +1606,8 @@ @installer-text-shadow: none; @installer-font-family: Arial; -@installer-log-color: #fff; -@installer-log-gradient: linear-gradient(top,rgba(0, 0, 0, 0.29) 0%, rgba(0, 0, 0, 0.11) 8px, rgba(0, 0, 0, 0.01) 13px, transparent 15px); +@installer-log-color: #333; +@installer-log-gradient: linear-gradient(top, #DFEFF9 0%, #DFEFF9 100%); @installer-log-border: 1px solid white; @installer-log-border-color: rgba(255,255,255,0.06) rgba(0,0,0,0.3) rgba(0,0,0,0.3) rgba(255,255,255,0.06); @installer-log-border-radius: 0; diff --git a/plugins/c9.ide.layout.classic/themes/default-dark.less b/plugins/c9.ide.layout.classic/themes/default-dark.less index 3ef3edf0..796ae607 100644 --- a/plugins/c9.ide.layout.classic/themes/default-dark.less +++ b/plugins/c9.ide.layout.classic/themes/default-dark.less @@ -1606,8 +1606,8 @@ @installer-text-shadow: none; @installer-font-family: Arial; -@installer-log-color: #fff; -@installer-log-gradient: linear-gradient(top,rgba(0, 0, 0, 0.29) 0%, rgba(0, 0, 0, 0.11) 8px, rgba(0, 0, 0, 0.01) 13px, transparent 15px); +@installer-log-color: #333; +@installer-log-gradient: linear-gradient(top, #DFEFF9 0%, #DFEFF9 100%); @installer-log-border: 1px solid white; @installer-log-border-color: rgba(255,255,255,0.06) rgba(0,0,0,0.3) rgba(0,0,0,0.3) rgba(255,255,255,0.06); @installer-log-border-radius: 0; diff --git a/plugins/c9.ide.plugins/loader.js b/plugins/c9.ide.plugins/loader.js index cb5abe47..93ad2aea 100644 --- a/plugins/c9.ide.plugins/loader.js +++ b/plugins/c9.ide.plugins/loader.js @@ -55,7 +55,14 @@ define(function(require, exports, module) { var install = []; if (loadFromDisk) { - fs.readdir("~/.c9/plugins", function(error, files){ + fs.readdir("~/.c9/plugins", function handle(err, files){ + if (err) { + if (err.code == "EDISCONNECT") + fs.readdir("~/.c9/plugins", handle); + console.error(err); + return; + } + files.forEach(function(f) { if (!/^[_.]/.test(f.name)) { fs.exists("~/.c9/plugins/" + f.name + "/__installed__.js", function(exists) { diff --git a/plugins/c9.ide.ui/lib_apf.js b/plugins/c9.ide.ui/lib_apf.js index 4d12f382..617b89bb 100644 --- a/plugins/c9.ide.ui/lib_apf.js +++ b/plugins/c9.ide.ui/lib_apf.js @@ -20275,6 +20275,9 @@ apf.Interactive = function(){ doResize(e); + if (_self.dispatchEvent) + _self.dispatchEvent("resize"); + //overThreshold = true; } diff --git a/plugins/c9.ide.ui/widgets.list.js b/plugins/c9.ide.ui/widgets.list.js index 8c62a39c..e321d142 100644 --- a/plugins/c9.ide.ui/widgets.list.js +++ b/plugins/c9.ide.ui/widgets.list.js @@ -509,6 +509,12 @@ define(function(require, exports, module) { focus: function(){ return acetree.focus(); }, + /** + * + */ + blur: function(){ + return acetree.blur(); + }, /** * */ diff --git a/plugins/c9.ide.ui/widgets.terminal.js b/plugins/c9.ide.ui/widgets.terminal.js new file mode 100644 index 00000000..71c50ab2 --- /dev/null +++ b/plugins/c9.ide.ui/widgets.terminal.js @@ -0,0 +1,402 @@ +define(function(require, exports, module) { + main.consumes = ["Plugin", "ui", "util", "commands"]; + main.provides = ["Terminal"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var commands = imports.commands; + + var Aceterm = require("../c9.ide.terminal/aceterm/aceterm"); + + /***** Constructors *****/ + + /* + plugin.on("copy", function(e) { + if (e.native) return; // Ace handles this herself + + var data = aceterm.getCopyText(); + e.clipboardData.setData("text/plain", data); + }); + plugin.on("paste", function(e) { + if (e.native) return; // Ace handles this herself + + var data = e.clipboardData.getData("text/plain"); + if (data !== false) + aceterm.onPaste(data); + }); + */ + + function Terminal(options, forPlugin, baseclass) { + if (!options) throw new Error("options are required"); + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + if (baseclass) plugin.baseclass(); + + var rows = options.rows || 0; + var cols = options.cols || 0; + + var aceterm, terminal; + var redirectEvents; + var meta = {}; + + var excludedEvents = { + "draw": 1, "load":1, "unload":1, "resize":1, + "addListener":1, "removeListener":1, "input":1 + }; + var renameEvents = { + "select": "changeSelection", + "scroll": "changeScrollTop" + }; + + /***** Methods *****/ + + function send(data) { + emit("input", { data: data }); + } + + function _resize(force){ + var ace = terminal.aceSession.ace; + + var size = ace.renderer.$size; + var config = ace.renderer.layerConfig; + + var h = size.scrollerHeight; + var w = size.scrollerWidth - 2 * config.padding; + + if (!h || config.lineHeight <= 1) + return false; + + // top 1px is for cursor outline + var _rows = Math.floor((h - 1) / config.lineHeight); + if (_rows <= 2 && !ace.renderer.scrollBarV.isVisible) + w -= ace.renderer.scrollBarV.width; + var _cols = Math.floor(w / config.characterWidth); + + if (!_cols || !_rows) + return; + + // Don't do anything if the size remains the same + if (!force && _cols == terminal.cols && _rows == terminal.rows) + return; + + if (_cols > 1000 || _rows > 1000) { + console.error("invalid terminal size"); + return; + } + + // do not resize terminal to very small heights during initialization + rows = Math.max(_rows, 2); + cols = Math.max(_cols, 2); + + terminal.resize(_cols, _rows); + + emit("resize", { cols: cols, rows: rows }); + } + + /***** Life Cycle *****/ + + var drawn = false; + function draw(htmlNode) { + if (drawn) return; + drawn = true; + + aceterm = Aceterm.createEditor(htmlNode, "ace/theme/idle_fingers"); + + terminal = new Aceterm(cols, rows, send); + aceterm.setSession(terminal.aceSession); + + aceterm.renderer.on("resize", function(){ + _resize(); + }); + + var cm = commands; + // TODO find better way for terminal and ace commands to coexist + aceterm.commands.addCommands(cm.getExceptionList()); + cm.on("update", function() { + aceterm.commands.addCommands(cm.getExceptionList()); + }, plugin); + + aceterm.commands.exec = function(command) { + return cm.exec(command); + }; + + // Set Default Theme + // if (!options.theme) + // options.theme = "custom-tree ace-tree-" + (options.baseName || "list"); + + // Set properties + for (var prop in options) { + if (prop == "container") continue; + if (plugin.hasOwnProperty(prop)) + plugin[prop] = options[prop]; + } + + // Configure redirected events + redirectEvents = { + afterRender: aceterm.renderer, + title: terminal, + afterWrite: terminal + }; + + emit.sticky("draw"); + } + + plugin.on("load", function(){ + if (options.container) + plugin.attachTo(options.container); + + forPlugin.once("unload", function(){ + plugin.unload(); + }); + }); + plugin.on("unload", function(){ + if (aceterm) { + var container = aceterm.container; + aceterm.destroy(); + + container.innerHTML = ""; + container.parentNode.removeChild(container); + } + + aceterm = null; + container = null; + meta = {}; + }); + plugin.on("newListener", function(type, fn){ + if (excludedEvents[type]) return; + + if (renameEvents[type]) + type = renameEvents[type]; + + if (redirectEvents[type]) + redirectEvents[type].on(type, fn); + else + aceterm.on(type, fn); + }); + plugin.on("removeListener", function(type, fn){ + if (excludedEvents[type]) return; + + if (renameEvents[type]) + type = renameEvents[type]; + + if (redirectEvents[type]) + redirectEvents[type].removeListener(type, fn); + else + aceterm.removeListener(type, fn); + }); + + /** + * @constructor + * Creates a new List instance. + * @param {Object} options + * @param {Plugin} plugin The plugin responsible for creating this list. + */ + plugin.freezePublicAPI({ + // Getter Properties + /** + * @ignore + * @readonly + */ + get aceterm(){ return aceterm; }, + /** + * A meta data object that allows you to store whatever you want + * in relation to this menu. + * @property {Object} meta + * @readonly + */ + get meta(){ return meta; }, + // /** + // * + // */ + // get scrollTop(){ return model.getScrollTop(); }, + // set scrollTop(value){ return model.setScrollTop(value); }, + /** + * + */ + get focussed(){ return aceterm.isFocussed(); }, + /** + * + */ + get container(){ return aceterm.container; }, + /** + * + */ + get renderer(){ return aceterm.renderer; }, + /** + * + */ + get selection(){ return aceterm.selection; }, + /** + * + */ + get commands(){ return aceterm.commands; }, + /** + * + */ + get cols(){ return cols; }, + /** + * + */ + get rows(){ return rows; }, + + // Getters and Setters for Properties + /** + * + */ + get textInput(){ return aceterm.textInput; }, + set textInput(value){ return aceterm.textInput = value; }, + /** + * + */ + get scrollMargin(){ return aceterm.renderer.scrollMargin; }, + set scrollMargin(value){ + aceterm.renderer.setScrollMargin(value[0], value[1]); + }, + /** + * + */ + get theme(){ return aceterm.renderer.theme.cssClass; }, + set theme(value){ aceterm.renderer.setTheme({cssClass: value}); }, + /** + * + */ + get convertEol(){ return terminal.convertEol || false; }, + set convertEol(value){ terminal.convertEol = value; }, + + // Events + _events: [ + /** + * @event draw Fires + */ + "draw", + /** + * @event click Fires + */ + "click", + /** + * @event userSelect Fires + */ + "userSelect", + /** + * @event focus Fires + */ + "focus", + /** + * @event blur Fires + */ + "blur", + /** + * @event select Fires + */ + "select", + /** + * @event scroll Fires + */ + "scroll", + /** + * @event scrollbarVisibilityChanged Fires + */ + "scrollbarVisibilityChanged", + /** + * @event resize Fires + */ + "resize", + /** + * @event afterRender Fires + */ + "afterRender", + /** + * @event title Fires + */ + "title", + /** + * @event afterWrite Fires + */ + "afterWrite" + ], + + /** + * + */ + resize: function(){ + return aceterm.resize(true); + }, + /** + * + */ + focus: function(){ + return aceterm.focus(); + }, + /** + * + */ + blur: function(){ + return aceterm.blur(); + }, + /** + * + */ + execCommand: function(cmd){ + return aceterm.execCommand(cmd); + }, + /** + * + */ + scrollIntoView: function(anchor, lead, offset){ + return aceterm.renderer.scrollCaretIntoView(anchor, lead, offset); + }, + /** + * + */ + enable: function(){ + return aceterm.enable(); + }, + /** + * + */ + disable: function(){ + return aceterm.enable(); + }, + /** + * + */ + write: function(data){ + return terminal.write(data); + }, + /** + * + */ + clear: function(data){ + terminal.clear(); + }, + /** + * + */ + attachTo: function(htmlNode, beforeNode){ + var container; + if (drawn) + container = aceterm.container; + else { + container = document.createElement("div"); + container.style.height = "100%"; + } + + htmlNode.insertBefore(container, beforeNode); + + if (!drawn) + draw(container); + } + }); + + plugin.load(null, options.baseName || "list"); + + return plugin; + } + + register(null, { + Terminal: Terminal + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/filelist.js b/plugins/c9.vfs.server/filelist.js index c652f0a9..263fea82 100644 --- a/plugins/c9.vfs.server/filelist.js +++ b/plugins/c9.vfs.server/filelist.js @@ -94,8 +94,7 @@ define(function(require, exports, module) { if (code == 127) { err = new error.PreconditionFailed( "Your instance seems to be missing the 'nak' utility\n" + - "If you are using an SSH workspace, please do:\n" + - " 'curl https://raw.github.com/c9/install/master/install.sh | bash'"); + "Please re-install nak."); } else if (code) { err = new error.InternalServerError( "'nak' utility failed with exit code " + code + diff --git a/plugins/c9.vfs.standalone/www/test.js b/plugins/c9.vfs.standalone/www/test.js index 276a6ce0..ae30803d 100644 --- a/plugins/c9.vfs.standalone/www/test.js +++ b/plugins/c9.vfs.standalone/www/test.js @@ -400,7 +400,7 @@ require([ console.warn(msg); } }, - "installer": { createSession : function(){}, reinstall: function(){} }, + "installer": { createSession : function(){}, reinstall: function(){}, isInstalled: function(){ return true; } }, "run.gui": { getElement : function(){} }, "debugger": {debug: function() {}, stop: function(){}}, "focusManager": {