kopia lustrzana https://github.com/c9/core
201 wiersze
7.0 KiB
JavaScript
201 wiersze
7.0 KiB
JavaScript
/**
|
|
* Cloud9 Language Foundation
|
|
*
|
|
* @copyright 2013, Ajax.org B.V.
|
|
*/
|
|
define(function(require, exports, module) {
|
|
main.consumes = [
|
|
"Plugin", "tabManager", "ace", "language",
|
|
"language.complete", "language.tooltip"
|
|
];
|
|
main.provides = ["language.keyhandler"];
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
var Plugin = imports.Plugin;
|
|
var language = imports.language;
|
|
var complete = imports["language.complete"];
|
|
var tooltip = imports["language.tooltip"];
|
|
var complete_util = require("plugins/c9.ide.language/complete_util");
|
|
var DEFAULT_ID_REGEX = complete_util.DEFAULT_ID_REGEX;
|
|
var ace;
|
|
|
|
/***** Initialization *****/
|
|
|
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
|
//var emit = plugin.getEmitter();
|
|
|
|
var loaded = false;
|
|
function load() {
|
|
if (loaded) return false;
|
|
loaded = true;
|
|
|
|
language.on("attachToEditor", function addBinding(ace) {
|
|
var kb = ace.keyBinding;
|
|
var defaultCommandHandler = kb.onCommandKey.bind(kb);
|
|
kb.onCommandKey = composeHandlers(onCommandKey, defaultCommandHandler, ace);
|
|
ace.commands.on("afterExec", onAfterExec, true);
|
|
});
|
|
complete.on("replaceText", function(e) {
|
|
onTextInput(e.newText, false, true);
|
|
});
|
|
}
|
|
|
|
/***** Methods *****/
|
|
|
|
function onAfterExec(e) {
|
|
if (e.command.name === "insertstring") {
|
|
ace = e.editor;
|
|
onTextInput(e.args);
|
|
} else if (e.command.name === "backspace") {
|
|
ace = e.editor;
|
|
if (language.isContinuousCompletionEnabled())
|
|
onBackspace(e);
|
|
}
|
|
}
|
|
|
|
function composeHandlers(mainHandler, fallbackHandler, myAce) {
|
|
return function onKeyPress() {
|
|
ace = myAce;
|
|
|
|
var result = mainHandler.apply(null, arguments);
|
|
if (!result)
|
|
fallbackHandler.apply(null, arguments);
|
|
};
|
|
}
|
|
|
|
function onTextInput(text, pasted, completed) {
|
|
inputTriggerTooltip(text, pasted);
|
|
if (completed)
|
|
return false;
|
|
if (complete.isPopupVisible())
|
|
return false;
|
|
if (language.isContinuousCompletionEnabled())
|
|
typeAlongCompleteTextInput(text, pasted);
|
|
else
|
|
inputTriggerComplete(text, pasted);
|
|
return false;
|
|
}
|
|
|
|
function onCommandKey(e) {
|
|
if (e.keyCode == 27) // Esc
|
|
tooltip.hide();
|
|
}
|
|
|
|
function onBackspace(e) {
|
|
if (complete.isPopupVisible())
|
|
return false;
|
|
var pos = ace.getCursorPosition();
|
|
var line = ace.session.doc.getLine(pos.row);
|
|
if (inCommentToken(pos))
|
|
return false;
|
|
if (!complete_util.precededByIdentifier(line, pos.column, null, ace) && !inTextToken(pos))
|
|
return false;
|
|
if (complete.getCompletionRegex(null, ace))
|
|
complete.deferredInvoke(false, ace, true);
|
|
}
|
|
|
|
function inputTriggerComplete(text, pasted) {
|
|
var pos = ace.getCursorPosition();
|
|
var completionRegex = complete.getCompletionRegex(null, ace);
|
|
var idRegex = complete.getIdentifierRegex(null, ace);
|
|
if (!pasted && completionRegex && text.match(completionRegex) && !inCommentToken(pos))
|
|
handleChar(text, idRegex, completionRegex);
|
|
}
|
|
|
|
function inputTriggerTooltip(text, pasted) {
|
|
var tooltipRegex = tooltip.getTooltipRegex(null, ace);
|
|
if (!pasted && tooltipRegex && text.match(tooltipRegex))
|
|
language.onCursorChange(null, null, true);
|
|
}
|
|
|
|
function typeAlongCompleteTextInput(text, pasted) {
|
|
var completionRegex = complete.getCompletionRegex(null, ace);
|
|
var idRegex = complete.getIdentifierRegex(null, ace);
|
|
if (pasted)
|
|
return false;
|
|
handleChar(text, idRegex, completionRegex);
|
|
}
|
|
|
|
function inTextToken(pos) {
|
|
var token = ace.getSession().getTokenAt(pos.row, pos.column - 1);
|
|
return token && token.type && token.type === "text";
|
|
}
|
|
|
|
function inCommentToken(pos) {
|
|
var token = ace.getSession().getTokenAt(pos.row, pos.column - 1);
|
|
return token && token.type && token.type.indexOf("comment") === 0;
|
|
}
|
|
|
|
function handleChar(ch, idRegex, completionRegex) {
|
|
var pos = ace.getCursorPosition();
|
|
if (inCommentToken(pos))
|
|
return;
|
|
|
|
var line = ace.getSession().getDocument().getLine(pos.row);
|
|
var matchIdRegex = ch.match(idRegex || DEFAULT_ID_REGEX);
|
|
|
|
if (matchIdRegex || complete.matchCompletionRegex(completionRegex, line, pos)) {
|
|
if (!complete_util.precededByIdentifier(line, pos.column, ch, ace))
|
|
return false;
|
|
complete.deferredInvoke(true, ace);
|
|
}
|
|
else if (ch === '"' || ch === "'") {
|
|
// TODO: move this special handing into infer_completer's getCompletionRegex
|
|
if (complete_util.isRequireJSCall(line, pos.column, "", ace, true))
|
|
complete.deferredInvoke(true, ace);
|
|
}
|
|
else {
|
|
// No useful character was pressed, but maybe we can
|
|
// predict what the user wants to complete next?
|
|
setTimeout(complete.invoke.bind(complete, { predictOnly: true }));
|
|
}
|
|
}
|
|
|
|
function setSkipInput(input) {
|
|
// TODO: skip characters in input
|
|
}
|
|
|
|
/***** Lifecycle *****/
|
|
|
|
plugin.on("load", function() {
|
|
load();
|
|
});
|
|
plugin.on("enable", function() {
|
|
|
|
});
|
|
plugin.on("disable", function() {
|
|
|
|
});
|
|
plugin.on("unload", function() {
|
|
loaded = false;
|
|
});
|
|
|
|
/***** Register and define API *****/
|
|
|
|
/**
|
|
*/
|
|
plugin.freezePublicAPI({
|
|
/**
|
|
*
|
|
*/
|
|
composeHandlers: composeHandlers,
|
|
|
|
/**
|
|
* Set text to skip when typed in.
|
|
* Used when automatically inserting text, but tolerating
|
|
* users also typing it, e.g. when inserting a closing }.
|
|
*
|
|
* @ignore not implemented
|
|
*
|
|
* @param {String} input
|
|
*/
|
|
setSkipInput: setSkipInput
|
|
});
|
|
|
|
register(null, {
|
|
"language.keyhandler": plugin
|
|
});
|
|
}
|
|
});
|