kopia lustrzana https://github.com/c9/core
306 wiersze
11 KiB
JavaScript
306 wiersze
11 KiB
JavaScript
/**
|
|
* Cloud9 Language Foundation
|
|
*
|
|
* @copyright 2013, Ajax.org B.V.
|
|
*/
|
|
define(function(require, exports, module) {
|
|
main.consumes = [
|
|
"Plugin", "tabManager", "language", "ui", "menus", "dialog.question",
|
|
"ace", "language.marker", "language", "commands",
|
|
"language.complete"
|
|
];
|
|
main.provides = ["language.refactor"];
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
var Plugin = imports.Plugin;
|
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
|
var language = imports.language;
|
|
var menus = imports.menus;
|
|
var commands = imports.commands;
|
|
var complete = imports["language.complete"];
|
|
var ui = imports.ui;
|
|
var tabs = imports.tabManager;
|
|
var aceHandle = imports.ace;
|
|
var marker = imports["language.marker"];
|
|
var question = imports["dialog.question"];
|
|
var completeUtil = require("plugins/c9.ide.language/complete_util");
|
|
var PlaceHolder = require("ace/placeholder").PlaceHolder;
|
|
var Range = require("ace/range").Range;
|
|
|
|
var worker;
|
|
var mnuRename;
|
|
var mnuRename2;
|
|
var placeHolder;
|
|
var oldCommandKey;
|
|
var oldIdentifier;
|
|
var lastAce;
|
|
var isGenericRefactor;
|
|
var oldContinuousCompletion;
|
|
var selectVar;
|
|
|
|
var loaded;
|
|
function load() {
|
|
if (loaded)
|
|
return;
|
|
loaded = true;
|
|
|
|
language.getWorker(function(err, langWorker) {
|
|
if (err)
|
|
return console.error(err);
|
|
worker = langWorker;
|
|
worker.on("refactoringsResult", function(event) {
|
|
enableRefactorings(event);
|
|
});
|
|
|
|
worker.on("renamePositionsResult", function(event) {
|
|
if (!tabs.focussedTab || !tabs.focussedTab.editor || tabs.focussedTab.editor.ace !== lastAce || !event.data)
|
|
return;
|
|
isGenericRefactor = event.data.isGeneric;
|
|
initRenameUI(event.data, lastAce);
|
|
worker.emit("onRenameBegin", { data: {}});
|
|
});
|
|
|
|
worker.on("commitRenameResult", function(event) {
|
|
var data = event.data;
|
|
if (data.err) {
|
|
question.show(
|
|
"Rename",
|
|
"Are you sure you would like to rename '" + data.oldName + "' to '" + data.newName + "'?",
|
|
data.err,
|
|
function() { // yes
|
|
cleanup();
|
|
},
|
|
function() { // no
|
|
cancelRename();
|
|
},
|
|
{
|
|
yes: "Rename",
|
|
no: "Cancel",
|
|
}
|
|
);
|
|
} else {
|
|
cleanup();
|
|
}
|
|
});
|
|
});
|
|
|
|
commands.addCommand({
|
|
name: "renameVar",
|
|
hint: "Rename refactor",
|
|
bindKey: { mac: "Option-Command-R", win: "Ctrl-Alt-R" },
|
|
exec: function(editor) {
|
|
selectVar = false;
|
|
beginRename(editor);
|
|
}
|
|
}, plugin);
|
|
commands.addCommand({
|
|
name: "selectVar",
|
|
hint: "select all instances of variable",
|
|
exec: function(editor) {
|
|
selectVar = true;
|
|
beginRename(editor);
|
|
}
|
|
}, plugin);
|
|
|
|
mnuRename = new ui.item({
|
|
disabled: true,
|
|
command: "renameVar",
|
|
caption: "Rename Variable"
|
|
});
|
|
mnuRename2 = new ui.item({
|
|
id: "mnuCtxEditorRename",
|
|
caption: "Rename",
|
|
command: "renameVar"
|
|
});
|
|
menus.addItemByPath("Tools/~", new ui.divider(), 10000, plugin);
|
|
menus.addItemByPath("Tools/Rename Variable", mnuRename, 2100, plugin);
|
|
|
|
// right click context item in ace
|
|
aceHandle.getElement("menu", function(menu) {
|
|
menus.addItemToMenu(menu, mnuRename2, 750, plugin);
|
|
menu.on("prop.visible", function(e) {
|
|
// only fire when visibility is set to true
|
|
if (e.value) {
|
|
// because of delays we'll disable by default
|
|
mnuRename2.disable();
|
|
var ace = tabs.focussedTab.editor.ace;
|
|
if (ace && worker)
|
|
worker.emit("refactorings", { data: ace.getSelection().getCursor() });
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function enableRefactorings(event) {
|
|
var names = event.data;
|
|
var enabled = false;
|
|
for (var i = 0; i < names.length; i++) {
|
|
var name = names[i];
|
|
if (name === "renameVariable" || name === "rename") {
|
|
enabled = true;
|
|
}
|
|
}
|
|
|
|
if (enabled) {
|
|
mnuRename.enable();
|
|
mnuRename2.enable();
|
|
}
|
|
else {
|
|
mnuRename.disable();
|
|
mnuRename2.disable();
|
|
}
|
|
}
|
|
|
|
function beginRename(editor) {
|
|
var ace = lastAce = editor.ace;
|
|
|
|
ace.focus();
|
|
var curPos = ace.getCursorPosition();
|
|
var doc = ace.getSession().getDocument();
|
|
var line = doc.getLine(curPos.row);
|
|
oldIdentifier = getFullIdentifier(line, curPos, ace);
|
|
worker.emit("renamePositions", { data: curPos });
|
|
}
|
|
|
|
function initRenameUI(data, ace) {
|
|
var cursor = ace.getCursorPosition();
|
|
var mainPos = data.pos;
|
|
// Exclude the main position from others
|
|
var others = data.others.filter(function (o) {
|
|
return !(o.row === mainPos.row && o.column === mainPos.column);
|
|
});
|
|
if (selectVar) {
|
|
ace.selection.toSingleRange();
|
|
others.push(mainPos);
|
|
others.forEach(function(pos) {
|
|
ace.selection.addRange(new Range(
|
|
pos.row, pos.column, pos.row, pos.column + data.length
|
|
));
|
|
});
|
|
return;
|
|
}
|
|
// Temporarily disable these markers, to prevent weird slow-updating events whilst typing
|
|
marker.disableMarkerType('occurrence_main', ace);
|
|
marker.disableMarkerType('occurrence_other', ace);
|
|
|
|
if (placeHolder)
|
|
return;
|
|
|
|
placeHolder = new PlaceHolder(ace.session, data.length, mainPos, others, "language_rename_main", "language_rename_other");
|
|
if (cursor.row !== mainPos.row || cursor.column < mainPos.column || cursor.column > mainPos.column + data.length) {
|
|
// Cursor is not "inside" the main identifier, move it there
|
|
ace.moveCursorTo(mainPos.row, mainPos.column);
|
|
}
|
|
placeHolder.showOtherMarkers();
|
|
oldContinuousCompletion = language.isContinuousCompletionEnabled();
|
|
language.setContinuousCompletionEnabled(false);
|
|
|
|
// Monkey patch
|
|
if (!oldCommandKey) {
|
|
oldCommandKey = ace.keyBinding.onCommandKey;
|
|
ace.keyBinding.onCommandKey = onKeyPress;
|
|
}
|
|
|
|
placeHolder.on("cursorLeave", function() {
|
|
commitRename();
|
|
});
|
|
}
|
|
|
|
function commitRename() {
|
|
// Finished refactoring in editor
|
|
// -> continue with the worker giving the initial refactor cursor position
|
|
var doc = lastAce.getSession().getDocument();
|
|
var oPos = placeHolder.pos;
|
|
var line = doc.getLine(oPos.row);
|
|
var newIdentifier = getFullIdentifier(line, oPos, lastAce);
|
|
worker.emit("commitRename", { data: { oldId: oldIdentifier, newName: newIdentifier.value, isGeneric: isGenericRefactor }});
|
|
}
|
|
|
|
function cancelRename() {
|
|
if (placeHolder)
|
|
placeHolder.cancel();
|
|
worker.emit("onRenameCancel", { data: {}});
|
|
// todo: currently onRenameCancel in the worker doesn't do anything
|
|
// so we need to call cleanup here
|
|
cleanup();
|
|
}
|
|
|
|
function cleanup() {
|
|
if (placeHolder)
|
|
placeHolder.detach();
|
|
language.setContinuousCompletionEnabled(oldContinuousCompletion);
|
|
marker.enableMarkerType('occurrence_main');
|
|
marker.enableMarkerType('occurrence_other');
|
|
placeHolder = null;
|
|
oldIdentifier = null;
|
|
if (oldCommandKey) {
|
|
lastAce.keyBinding.onCommandKey = oldCommandKey;
|
|
oldCommandKey = null;
|
|
}
|
|
}
|
|
|
|
function onKeyPress(e, hashKey, keyCode) {
|
|
var keyBinding = lastAce.keyBinding;
|
|
var selection = placeHolder.session.selection;
|
|
var col = 0;
|
|
|
|
switch (keyCode) {
|
|
case 32: // Space can't be accepted as it will ruin the logic of retrieveFullIdentifier
|
|
if (e.ctrlKey || e.metaKey || e.altKey)
|
|
return oldCommandKey.apply(keyBinding, arguments);
|
|
col = selection.lead.column;
|
|
var start = placeHolder.pos.column;
|
|
var end = start + placeHolder.length;
|
|
if (col == start || col == end)
|
|
commitRename();
|
|
break;
|
|
case 27: // Esc
|
|
cancelRename();
|
|
e.preventDefault();
|
|
break;
|
|
case 13: // Enter
|
|
commitRename();
|
|
e.preventDefault();
|
|
break;
|
|
case 35: // End
|
|
col = placeHolder.length;
|
|
/* falls through */
|
|
case 36: // Home
|
|
var row = selection.lead.row;
|
|
col += placeHolder.pos.column;
|
|
|
|
if (e.shiftKey)
|
|
selection.selectTo(row, col);
|
|
else
|
|
selection.moveTo(row, col);
|
|
break;
|
|
default:
|
|
return oldCommandKey.apply(keyBinding, arguments);
|
|
}
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
function getFullIdentifier(line, pos, ace) {
|
|
var regex = complete.getIdentifierRegex(null, ace);
|
|
var prefix = completeUtil.retrievePrecedingIdentifier(line, pos.column, regex);
|
|
var postfix = completeUtil.retrieveFollowingIdentifier(line, pos.column, regex);
|
|
return {
|
|
column: pos.column - prefix.length,
|
|
row: pos.row,
|
|
value: prefix + postfix
|
|
};
|
|
}
|
|
|
|
plugin.on("load", function() {
|
|
load();
|
|
});
|
|
|
|
register(null, {
|
|
"language.refactor": plugin
|
|
});
|
|
}
|
|
});
|