c9-core/plugins/c9.ide.ui/widgets.terminal.js

402 wiersze
13 KiB
JavaScript

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
});
}
});