diff --git a/node_modules/ace/lib/ace/ext/whitespace.js b/node_modules/ace/lib/ace/ext/whitespace.js index 7f39b092..aa20c60a 100644 --- a/node_modules/ace/lib/ace/ext/whitespace.js +++ b/node_modules/ace/lib/ace/ext/whitespace.js @@ -127,10 +127,20 @@ exports.trimTrailingSpace = function(session, options) { var lines = doc.getAllLines(); var min = options && options.trimEmpty ? -1 : 0; - var cursors = session.selection.rangeCount - ? session.selection.ranges.map(function(x) { return x.cursor; }) - : [session.selection.getCursor()]; - var ci = options && options.keepCursorPosition ? 0 : -1; + var cursors = [], ci = -1; + if (options && options.keepCursorPosition) { + if (session.selection.rangeCount) { + session.selection.rangeList.ranges.forEach(function(x, i, ranges) { + var next = ranges[i + 1] + if (next && next.cursor.row == x.cursor.row) + return; + cursors.push(x.cursor); + }); + } else { + cursors.push(session.selection.getCursor()); + } + ci = 0; + } var cursorRow = cursors[ci] && cursors[ci].row; for (var i = 0, l=lines.length; i < l; i++) { @@ -139,7 +149,7 @@ exports.trimTrailingSpace = function(session, options) { if (i == cursorRow) { if (index < cursors[ci].column) - index = min; + index = cursors[ci].column; ci++; cursorRow = cursors[ci] ? cursors[ci].row : -1; } diff --git a/node_modules/ace/lib/ace/ext/whitespace_test.js b/node_modules/ace/lib/ace/ext/whitespace_test.js index 419ae74f..cddc52ea 100644 --- a/node_modules/ace/lib/ace/ext/whitespace_test.js +++ b/node_modules/ace/lib/ace/ext/whitespace_test.js @@ -1,13 +1,14 @@ if (typeof process !== "undefined") { require("amd-loader"); - require("../test/mockdom"); } define(function(require, exports, module) { "use strict"; +require("../multi_select"); var assert = require("assert"); var EditSession = require("../edit_session").EditSession; +var UndoManager = require("../undomanager").UndoManager; var whitespace = require("./whitespace"); // Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite @@ -111,8 +112,79 @@ module.exports = { assert.equal(indent.length, 1); next(); - } + }, + "test trimTrailingSpace": function(next) { + var session = new EditSession([ + "a", + "\t b \t", + " ", + "\t", + "\t\tx\t\t", + " ", + " " + ]); + session.setUndoManager(new UndoManager()); + + function testOne(value, options) { + console.log(JSON.stringify(session.getValue())) + + whitespace.trimTrailingSpace(session, options); + assert.equal(value, session.getValue()); + session.markUndoGroup(); + session.getUndoManager().undo(); + } + + testOne("a\n\t b\n \n\t\n\t\tx\n \n ") + + testOne("a\n\t b\n\n\n\t\tx\n\n", { + trimEmpty: true + }); + + session.selection.fromJSON([{ + start: {row:2,column:3}, + end: {row:4,column:4} + }]); + testOne("a\n\t b\n\n\n\t\tx\t\n\n", { + keepCursorPosition: true, + trimEmpty: true + }); + + session.selection.fromJSON([{ + start: {row:2,column:3}, + end: {row:4,column:4}, + isBackwards: true + }]); + testOne("a\n\t b\n \n\n\t\tx\n\n", { + keepCursorPosition: true, + trimEmpty: true + }); + + session.selection.$initRangeList(); + session.selection.fromJSON([{ + start: {row:2, column:3}, + end: {row:2,column:3} + }, { + start: {row:1, column:1}, + end: {row:1, column:1} + }, { + start: {row:2,column:2}, + end: {row:2,column:2} + }, { + start: {row:0,column:5}, + end: {row:0,column:5}, + isBackwards:false + }, { + start: {row:6,column:1}, + end: {row:6,column:1}, + isBackwards:false + }]); + testOne("a\n\t b\n \n\n\t\tx\n\n ", { + trimEmpty: true, + keepCursorPosition: true + }); + next(); + }, }; }); diff --git a/node_modules/ace_tree/lib/ace_tree/data_provider.js b/node_modules/ace_tree/lib/ace_tree/data_provider.js index ea343c72..9bc095e0 100644 --- a/node_modules/ace_tree/lib/ace_tree/data_provider.js +++ b/node_modules/ace_tree/lib/ace_tree/data_provider.js @@ -49,7 +49,7 @@ var DataProvider = function(root) { }; this.open = - this.expand = function(node, deep, silent, justLoaded) { + this.expand = function(node, deep, silent) { if (typeof deep != "number") deep = deep ? 100 : 0; if (!node) @@ -69,7 +69,7 @@ var DataProvider = function(root) { this.collapse(node, null, true); node.status = "loaded"; if (!err) - this.expand(node, null, false, true); + this.expand(node, null, false); }.bind(this)); this.setOpen(node, true); return; @@ -95,9 +95,6 @@ var DataProvider = function(root) { } } - if (justLoaded) - node.justLoaded = true; - this.rows = items.length; silent || this._signal("expand", node); }; diff --git a/node_modules/ace_tree/lib/ace_tree/edit.js b/node_modules/ace_tree/lib/ace_tree/edit.js index 4dcc71e4..09bb8dfb 100644 --- a/node_modules/ace_tree/lib/ace_tree/edit.js +++ b/node_modules/ace_tree/lib/ace_tree/edit.js @@ -157,11 +157,12 @@ var EditableTree = function(tree) { this.ace.commands.bindKeys({ "Esc": function(ace) { ace.treeEditor.endRename(true); - ace.treeEditor.tree.focus(); }, "Enter": function(ace) { ace.treeEditor.endRename(); - ace.treeEditor.tree.focus(); + }, + "ctrl-s|cmd-s": function(ace) { + ace.treeEditor.endRename(); }, "Tab": function(ace) { ace.treeEditor.editNext(1); @@ -249,17 +250,24 @@ var EditableTree = function(tree) { this._destroyEditor = function() { if (this.lastDomNode) { this.lastDomNode.style.color = ""; - this.lastDomNode + this.lastDomNode; } this.ace.off("blur", this._onBlur); this.tree.renderer.off("afterRender", this._onAfterRender); - this.ace.blur(); - this.ace.destroy(); - if (this.ace.wrapper.parentNode) - this.ace.wrapper.parentNode.removeChild(this.ace.wrapper); + var ace = this.ace; this.ace = null; + ace.renderer.freeze(); + setTimeout(function() { + // doing this after timeout to allow rename event focus something else + var wasFocused = ace.isFocused(); + ace.destroy(); + if (ace.wrapper.parentNode) + ace.wrapper.parentNode.removeChild(ace.wrapper); + if (wasFocused) + this.tree.focus(); + }.bind(this)); }; this.findNextEditPoint = function(dir, node, col, keepColumn) { @@ -378,16 +386,18 @@ var EditableTree = function(tree) { var val = this.ace.getValue(); - this._destroyEditor(); if (!cancel && this.origVal !== val) { this.tree._emit("rename", { node: node, value: val, + oldValue: this.origVal, column: this.column }); this.tree.provider._signal("change"); } + + this._destroyEditor(); }; }).call(EditableTree.prototype); diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js index 16ba5c0d..2d04ceec 100644 --- a/node_modules/vfs-local/localfs.js +++ b/node_modules/vfs-local/localfs.js @@ -1032,7 +1032,16 @@ module.exports = function setup(fsOptions) { if (!exists || options.overwrite || isSamePath) { // Rename the file fs.rename(frompath, topath, function (err) { - if (err) return callback(err); + if (err) { + if (err.code == 'ENOENT' && options.mkdirP != false) { + options.mkdirP = false; + return mkdirP(dir, {}, function(err) { + if (err) return callback(err); + rename(path, options, callback); + }); + } + return callback(err); + } // Rename metadata if (options.metadata !== false) { diff --git a/package.json b/package.json index eeb712fe..c98720d8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "c9" ], "c9plugins": { - "c9.ide.language": "#6d5a10ac4f", + "c9.ide.language": "#ebc064ef16", "c9.ide.language.css": "#be07d72209", "c9.ide.language.generic": "#92210f5a48", "c9.ide.language.html": "#22fdc74869", @@ -116,7 +116,7 @@ "c9.ide.theme.flat": "#81dadeee55", "c9.ide.threewaymerge": "#229382aa0b", "c9.ide.undo": "#b028bcb4d5", - "c9.ide.upload": "#0bd010d3dc", + "c9.ide.upload": "#a3da59803d", "c9.ide.welcome": "#5b86c44e92", "c9.ide.guide": "#8ab966f344" } diff --git a/plugins/c9.fs/fs.cache.xml.js b/plugins/c9.fs/fs.cache.xml.js index 34b693b2..7922f9a0 100644 --- a/plugins/c9.fs/fs.cache.xml.js +++ b/plugins/c9.fs/fs.cache.xml.js @@ -82,6 +82,9 @@ define(function(require, exports, module) { node.status = "pending"; return; } + var parentPath = e.path; + if (!parentPath.endsWith("/")) + parentPath += "/"; // update cache if (!node) { if (!showHidden && isFileHidden(e.path)) @@ -92,97 +95,116 @@ define(function(require, exports, module) { orphans[e.path] = node; orphan = true; } + node.$lastReadT = Date.now(); // Indicate this directory has been fully read model.setAttribute(node, "status", "loaded"); - var wasOpen = startUpdate(node); - node.children = null; - var existing = node.map || {}; - node.map = {}; - - // Fill Parent - var ondisk = {}, toAppend = []; + var ondisk = Object.create(null); + var toRemove = []; + var toCreate = []; + var orphanAppand = []; + var existing = node.map || (node.map = Object.create(null)); e.result[1].forEach(function(stat) { if (!stat.name || !showHidden && isFileHidden(stat.name)) return; - var name = stat.name; - var path = (e.path + "/" + name).replace("//", "/"); + var path = parentPath + name; ondisk[name] = 1; - // if (existing[name]) return; + if (orphans[path]) { - toAppend.push(path); + if (existing[name]) + delete orphans[path]; + orphanAppand.push(path); } - createNode(path, stat, existing[name], true); + + if (existing[name]) + updateNodeStat(path, stat, existing[name]); + else + toCreate.push(stat); }); - for (var name in existing) { - if (!ondisk[name]) { - // onreaddir can be called before copied nodes are written to disk - // in this case we don't want to lose "predicted" state - if (existing[name] && existing[name].status === "predicted") - node.map[name] = existing[name]; - else { - delete existing[name]; - - emit("remove", { - path: e.path + "/" + name, - node: existing[name], - parent: node - }); - } - } - } + Object.keys(existing).forEach(function(name) { + // onreaddir can be called before copied nodes are written to disk + // in this case we don't want to lose "predicted" state + if (existing[name] && existing[name].status === "predicted") + ondisk[name] = 1; + if (!ondisk[name]) + toRemove.push(name); + }); + + if (!toCreate.length && !toRemove.length && !orphanAppand.length) + return; + + var wasOpen = startUpdate(node); + node.children = null; + + // Fill Parent + toCreate.forEach(function(stat) { + createNode(parentPath + stat.name, stat, null, true); + }); + + toRemove.forEach(function(name) { + var currentNode = existing[name]; + delete existing[name]; + emit("remove", { + path: parentPath + name, + node: currentNode, + parent: node + }); + }); emit("readdir", { path : e.path, parent : node, orphan: orphan }); endUpdate(node, wasOpen); - toAppend.forEach(function(path) { + orphanAppand.forEach(function(path) { emit("orphan-append", {path: path}); }); } fs.on("afterReaddir", onreaddir, plugin); function onstat(e) { - var stat; + if (e.error) return; - if (!e.error) { - // update cache - var there = true; - var node = findNode(e.path); - var parent = findNode(dirname(e.path)); - - if (!showHidden && isFileHidden(e.path)) - return; + // update cache + var stat = e.result[1]; + + var there = true; + var node = findNode(e.path); + var parent = findNode(dirname(e.path)); + + if (!showHidden && isFileHidden(e.path)) + return; - if (!node) { - if (!parent) - return; - there = false; + if (!node) { + if (!parent) + return; + there = false; + } + + if (there != !!stat) { + if (there) { + if (!node.link) + deleteNode(node); } - - if (there != !!e.result[1]) { - if (there) { - if (!node.link) - deleteNode(node); - } - else { - stat = e.result[1]; - if (typeof stat != "object") - stat = null; - createNode(e.path, stat); - } - } - else if (there) { - stat = e.result[1]; + else { if (typeof stat != "object") stat = null; - createNode(e.path, stat, node); + createNode(e.path, stat); } } + else if (there) { + if (typeof stat != "object") + stat = null; + if (!stat && node) + return; + if (stat && node) + updateNodeStat(e.path, stat, node); + else + createNode(e.path, stat, node); + } } fs.on("afterStat", onstat, plugin); fs.on("afterReadFile", function(e) { @@ -295,14 +317,15 @@ define(function(require, exports, module) { // Validation var toNode = findNode(newPath); - deleteNode(node, true); - if (toNode) - deleteNode(toNode, true); - - createNode(newPath, null, node); // Move node - recurPathUpdate(node, oldPath, newPath); + if (!toNode) { + deleteNode(node, true); + createNode(newPath, null, node); // Move node + recurPathUpdate(node, oldPath, newPath); + } e.undo = function(){ + if (toNode) + return; if (!parent) { var tmpParent = node; while (node.parent && tmpParent.parent.status == "pending") @@ -318,6 +341,12 @@ define(function(require, exports, module) { recurPathUpdate(node, newPath, oldPath); }; e.confirm = function() { + if (toNode) { + deleteNode(toNode, true); + createNode(newPath, null, node); // Move node + recurPathUpdate(node, oldPath, newPath); + } + if (node.status === "predicted") node.status = "loaded"; }; @@ -511,14 +540,8 @@ define(function(require, exports, module) { updateNode = orphans[path]; delete orphans[path]; } - var original_stat; - if (stat && stat.link) { - original_stat = stat; - stat = stat.linkStat; - } var parts = path.split("/"); - var name = parts[parts.length - 1]; var node = model.root.map[parts[0] == "~" ? "~" : ""]; if (!node) { node = orphans[parts[0]]; @@ -537,7 +560,7 @@ define(function(require, exports, module) { var map = node.map; if (!map) { - map = node.map = {}; + map = node.map = Object.create(null); } parent = node; node = map[p]; @@ -545,6 +568,11 @@ define(function(require, exports, module) { modified.push(parent); if (i !== parts.length - 1) { node = {label: p, path: subPath, status: "pending", isFolder: true}; + // TODO filter hidden files in getChildren instead. + if (!showHidden && isFileHidden(p)) { + orphans[node.path] = path; + return; + } } else if (updateNode) { deleteNode(updateNode, true); node = updateNode; @@ -564,8 +592,32 @@ define(function(require, exports, module) { node = {label: parts[parts.length - 1], path: path}; orphans[path] = node; } + + updateNodeStat(path, stat, node); + + node.children = null; + + if (!updating) { + if (!modified.length) + modified.push(parent); + var wasOpen = startUpdate(modified[0]); + modified.forEach(function(n) { + if (n != model.root) + n.children = null; + }); + endUpdate(modified[0], wasOpen); + } + model._signal("createNode", node); + return node; + } + + function updateNodeStat(path, stat, node) { node.path = path; - + var original_stat; + if (stat && stat.link) { + original_stat = stat; + stat = stat.linkStat; + } if (stat) { var isFolder = stat && /(directory|folder)$/.test(stat.mime); if (isFolder) { @@ -589,25 +641,13 @@ define(function(require, exports, module) { delete node.isFolder; } - if (node.isFolder && !node.map) - node.map = {}; - else if (!node.isFolder && node.map) + if (node.isFolder && !node.map) { + node.map = Object.create(null); + node.children = null; + } else if (!node.isFolder && node.map) { delete node.map; - - node.children = null; - - if (!updating) { - if (!modified.length) - modified.push(parent); - var wasOpen = startUpdate(modified[0]); - modified.forEach(function(n) { - if (n != model.root) - n.children = null; - }); - endUpdate(modified[0], wasOpen); + node.children = null; } - model._signal("createNode", node); - return node; } function deleteNode(node, silent) { @@ -670,7 +710,7 @@ define(function(require, exports, module) { map: {} }; var root = {}; - root.map = {}; + root.map = Object.create(null); root.map[""] = model.projectDir; model.setRoot(root); // fs.readdir("/", function(){}); @@ -894,7 +934,12 @@ define(function(require, exports, module) { * @param {Function} progress * @param {Function} done */ - loadNodes: loadNodes + loadNodes: loadNodes, + + /** + * @ignore + */ + isFileHidden: isFileHidden }); register(null, { diff --git a/plugins/c9.ide.dialog.common/question.js b/plugins/c9.ide.dialog.common/question.js index 7e3be92e..23d08df1 100644 --- a/plugins/c9.ide.dialog.common/question.js +++ b/plugins/c9.ide.dialog.common/question.js @@ -54,7 +54,7 @@ define(function(require, module, exports) { var gotYesNo = false; plugin.once("hide", function(){ - !gotYesNo && cancel && onNo(false, true, metadata); + !gotYesNo && cancel && onNo && onNo(false, true, metadata); }); plugin.update([ @@ -63,22 +63,22 @@ define(function(require, module, exports) { { id: "yestoall", visible: all, onclick: function(){ gotYesNo = true; plugin.hide(); - onYes(true, metadata); + onYes && onYes(true, metadata); }}, { id: "notoall", visible: all, onclick: function(){ gotYesNo = true; plugin.hide(); - onNo(true, false, metadata); + onNo && onNo(true, false, metadata); }}, { id: "yes", onclick: function(){ gotYesNo = true; plugin.hide(); - onYes(false, metadata); + onYes && onYes(false, metadata); }}, { id: "no", onclick: function(){ gotYesNo = true; plugin.hide(); - onNo(false, false, metadata); + onNo && onNo(false, false, metadata); }} ]); }, options.queue === false); diff --git a/plugins/c9.ide.tree/tree.js b/plugins/c9.ide.tree/tree.js index f130e2b4..5a5e23ed 100644 --- a/plugins/c9.ide.tree/tree.js +++ b/plugins/c9.ide.tree/tree.js @@ -3,7 +3,7 @@ define(function(require, exports, module) { "Panel", "c9", "util", "fs", "settings", "ui", "menus", "panels", "commands", "tabManager", "fs.cache", "watcher", "preferences", "clipboard", "dialog.alert", "dialog.fileremove", - "dialog.fileoverwrite", "dialog.error", "layout" + "dialog.fileoverwrite", "dialog.error", "layout", "dialog.question" ]; main.provides = ["tree"]; return main; @@ -24,6 +24,7 @@ define(function(require, exports, module) { var watcher = imports.watcher; var prefs = imports.preferences; var alert = imports["dialog.alert"].show; + var question = imports["dialog.question"].show; var fsCache = imports["fs.cache"]; var confirmRemove = imports["dialog.fileremove"].show; var confirmRename = imports["dialog.fileoverwrite"].show; @@ -34,7 +35,7 @@ define(function(require, exports, module) { var TreeEditor = require("ace_tree/edit"); var markup = require("text!./tree.xml"); - var basename = require("path").basename; + var join = require("path").join; var dirname = require("path").dirname; var staticPrefix = options.staticPrefix; @@ -52,7 +53,7 @@ define(function(require, exports, module) { }); var emit = plugin.getEmitter(); - var container, winFilesViewer; //UI elements + var container, winFilesViewer; // UI elements var showHideScrollPos, scrollTimer; var tree; @@ -404,15 +405,10 @@ define(function(require, exports, module) { emit("expand", { path: id }); - if (node.justLoaded) { - delete node.justLoaded; - return; - } - // Only save if we are not loading the tree if (!refreshing || loadedSettings != -1) { if (!node.isRoot) { - var refresh = !refreshing && node.status == "loaded"; + var refresh = !refreshing && node.status == "loaded" && Date.now() - node.$lastReadT > 500; watcher.watch(id, refresh); // watch children @@ -424,8 +420,10 @@ define(function(require, exports, module) { }); } - changed = true; - settings.save(); + if (!updateSingleDirectoryChain(true, node)) { + changed = true; + settings.save(); + } } }, plugin); @@ -451,13 +449,28 @@ define(function(require, exports, module) { }); } - changed = true; - settings.save(); + if (!updateSingleDirectoryChain(false, node)) { + changed = true; + settings.save(); + } }, plugin); - - function abortNoStorage() { - if (!c9.has(c9.STORAGE)) - return false; + + function updateSingleDirectoryChain(isExpand, node) { + if (!node.children || node.children.length !== 1) + return; + var child = node.children[0]; + if (!child || !child.isFolder || child.$depth > 0xff) + return; + + if (isExpand && !child.isOpen) { + expandNode(child); + return true; + } + else if (!isExpand && child.isOpen) { + updateSingleDirectoryChain(false, child); + delete expandedList[child.path]; + return true; + } } // Rename @@ -479,34 +492,58 @@ define(function(require, exports, module) { } var node = e.node; - var name = e.value; + var name = e.value.trim(); // check for a path with the same name, which is not allowed to rename to: var path = node.path; - var newpath = path.replace(/[^\/]+$/, name); + var newpath = join(path, "..", name); // No point in renaming when the name is the same - if (basename(path) == name) + if (path == newpath) return; - - // Returning false from this function will cancel the rename. We do this - // when the name to which the file is to be renamed contains invalid - // characters - if (/[\\\/\n\r]/.test(name)) { - // todo is this still needed? + + var m = /([\0\\\n\r])/.exec(name) || c9.platform == "win32" && /([\\:*?"<>|])/.exec(name); + if (m) { showError( - "Could not rename to '" + ui.htmlentities(name) - + "'. Names can only contain alfanumeric characters, space, . (dot)" - + ", - and _ (underscore). Use the terminal to rename to other names." + "Invalid character '" + m[0] + "' in '" + name + "'" ); return false; } - fs.rename(path, newpath, {}, function(err, success) { }); + // renaming to hidden file can be confusing if one doesn't know about hidden files + if (fsCache.isFileHidden(newpath) && !settings.getBool("user/projecttree/@showhidden")) { + settings.set("user/projecttree/@showhidden", true); + changed = true; + fsCache.showHidden = true; + refresh(true, function(){}); + } - emit("rename", { path: newpath, oldpath: path }); + if (dirname(newpath) != dirname(path)) { + tree.edit.ace.blur(); // TODO this shouldn't be needed when apf focus works + question( + "Confirm move to a new folder", + "move '" + e.oldValue + "' to \n" + + "'" + dirname(newpath) + "'?", + "", + doRename + ); + } else { + doRename(); + } - return false; + function doRename() { + fs.rename(path, newpath, {}, function(err, success) { + if (err) { + var message = err.message; + if (err.code == "EEXIST") + message = "File " + path + " already exists."; + return showError(message); + } + if (dirname(newpath) != dirname(path)) + expandAndSelect(newpath); + }); + emit("rename", { path: newpath, oldpath: path }); + } }, plugin); // Context Menu @@ -977,7 +1014,7 @@ define(function(require, exports, module) { } else { var node = fsCache.findNode(path); - if (node) //Otherwise orphan-append will pick it up + if (node) // Otherwise orphan-append will pick it up expandNode(node); } @@ -1045,14 +1082,14 @@ define(function(require, exports, module) { if (typeof node == "string") node = fsCache.findNode(node, "refresh"); + if (node && !node.isFolder) + node = node.parent; if (node && node.status === "loaded") { tree.provider.setAttribute(node, "status", "pending"); node.children = null; } }); - //c9.dispatchEvent("track_action", { type: "reloadtree" }); - loadProjectTree(false, function(err) { var expandedNodes = Object.keys(expandedList); expandedList = {}; @@ -1067,7 +1104,7 @@ define(function(require, exports, module) { callback(err); tree.provider.on("changeScrollTop", scrollHandler); - emit("refreshComplete") + emit("refreshComplete"); }); } @@ -1100,6 +1137,7 @@ define(function(require, exports, module) { function expandAndSelect(path_or_node) { var node = findNode(path_or_node); expand(node, function(){ + refreshing = false; tree.select(node); scrollToSelection(); }); @@ -1212,10 +1250,12 @@ define(function(require, exports, module) { } function select(path_or_node) { + refreshing = false; tree.select(findNode(path_or_node)); } function selectList(list) { + refreshing = false; tree.selection.setSelection(list.map(function(n) { return findNode(n); })); @@ -1293,6 +1333,9 @@ define(function(require, exports, module) { callback(err, data); }); + var node = fsCache.findNode(newpath, "expand"); + if (node) + expandAndSelect(node); }); } diff --git a/plugins/c9.ide.ui/menus.js b/plugins/c9.ide.ui/menus.js index f3078363..0c06c306 100644 --- a/plugins/c9.ide.ui/menus.js +++ b/plugins/c9.ide.ui/menus.js @@ -947,8 +947,10 @@ define(function(require, exports, module) { } function show(x, y, type) { - if (type == "context") - y++; + if (type == "context") { + x += 2; + y += 2; + } lastCoords = { x : x, y : y }; aml.display(x, y); }