kopia lustrzana https://github.com/c9/core
1187 wiersze
45 KiB
JavaScript
1187 wiersze
45 KiB
JavaScript
define(function(require, exports, module) {
|
|
main.consumes = [
|
|
"Editor", "editors", "util", "commands", "terminal",
|
|
"settings", "ui", "proc", "tabManager", "run", "console", "run.gui",
|
|
"layout", "debugger", "settings", "dialog.question", "c9", "preferences",
|
|
"dialog.error", "dialog.file", "dialog.alert"
|
|
];
|
|
main.provides = ["output"];
|
|
return main;
|
|
|
|
// On line 894 trigger connect to output or connect after process is started
|
|
// add special case in terminal.js to not auto connect when isOutput
|
|
|
|
function main(options, imports, register) {
|
|
var editors = imports.editors;
|
|
var ui = imports.ui;
|
|
var c9 = imports.c9;
|
|
var commands = imports.commands;
|
|
var console = imports.console;
|
|
var layout = imports.layout;
|
|
var tabs = imports.tabManager;
|
|
var util = imports.util;
|
|
var run = imports.run;
|
|
var prefs = imports.preferences;
|
|
var runGui = imports["run.gui"];
|
|
var question = imports["dialog.question"];
|
|
var showError = imports["dialog.error"].show;
|
|
var showAlert = imports["dialog.alert"].show;
|
|
var showSave = imports["dialog.file"].show;
|
|
var Terminal = imports.terminal.Terminal;
|
|
var debug = imports.debugger;
|
|
var settings = imports.settings;
|
|
|
|
var join = require("path").join;
|
|
var markup = require("text!./output.xml");
|
|
|
|
var keys = require("ace/lib/keys");
|
|
var Tree = require("ace_tree/tree");
|
|
var TreeData = require("ace_tree/data_provider");
|
|
var TreeEditor = require("ace_tree/edit");
|
|
|
|
var basePath = options.basePath;
|
|
|
|
// Set up the generic handle
|
|
var handle = editors.register("output", "Output", Output, []);
|
|
var handleEmit = handle.getEmitter();
|
|
|
|
var defaults = {
|
|
"flat-light": ["#e0e5e7", "#333333", "#aebabf", false],
|
|
"flat-dark": ["#003a58", "#FFFFFF", "#225477", true],
|
|
"light": ["#eef7ff", "#333333", "#89c1ff", false],
|
|
"light-gray": ["#eef7ff", "#333333", "#89c1ff", false],
|
|
"dark": ["#003a58", "#FFFFFF", "#225477", true],
|
|
"dark-gray": ["#003a58", "#FFFFFF", "#225477", true]
|
|
};
|
|
|
|
handle.on("load", function() {
|
|
// Import CSS
|
|
ui.insertCss(require("text!./style.css"), options.staticPrefix, handle);
|
|
|
|
commands.addCommand({
|
|
name: "showoutput",
|
|
group: "Panels",
|
|
exec: function (editor, argv) {
|
|
if (!argv) argv = false;
|
|
var id = argv.id;
|
|
var cmd = argv.config && argv.config.command;
|
|
|
|
if (id === undefined)
|
|
id = getOutputId();
|
|
|
|
// Search for the output pane
|
|
if (search(id, cmd, argv)) return;
|
|
|
|
// If not found show the console
|
|
console.show();
|
|
|
|
// Search again
|
|
if (search(id, cmd, argv)) return;
|
|
|
|
var config = argv.config || {};
|
|
if (config.debug === undefined && debug.state != "disconnected")
|
|
config.debug = false;
|
|
|
|
if (config.toolbar === undefined)
|
|
config.toolbar = true;
|
|
|
|
// Else open the output panel in the console
|
|
tabs.open({
|
|
editorType: "output",
|
|
active: true,
|
|
pane: argv.pane || console.getPanes()[0],
|
|
document: {
|
|
title: "Output",
|
|
output: {
|
|
id: id || "output",
|
|
config: config,
|
|
runner: argv.runner || config.runner,
|
|
run: argv.run,
|
|
callback: argv.callback
|
|
}
|
|
}
|
|
}, function() {});
|
|
}
|
|
}, handle);
|
|
|
|
function setSettings() {
|
|
var cname = ".output .c9terminal .c9terminalcontainer .terminal";
|
|
var sname = ".output .c9terminal .c9terminalcontainer";
|
|
var fcolor = settings.get("user/output/@foregroundColor");
|
|
var bcolor = settings.get("user/output/@backgroundColor");
|
|
var scolor = settings.get("user/output/@selectionColor");
|
|
[
|
|
[cname, "color", fcolor || "rgb(255,255,255)"],
|
|
[sname, "backgroundColor", bcolor || "rgb(25, 34, 39)"],
|
|
[cname + " .ace_selection", "backgroundColor", scolor || "rgb(81, 93, 119)"]
|
|
].forEach(function(i) {
|
|
ui.setStyleRule(i[0], i[1], i[2]);
|
|
});
|
|
|
|
handleEmit("settingsUpdate");
|
|
}
|
|
|
|
settings.on("read", function(e) {
|
|
var skin = settings.get("user/general/@skin");
|
|
var colors = defaults[skin] || defaults["dark"];
|
|
|
|
settings.setDefaults("user/output", [
|
|
["backgroundColor", colors[0]],
|
|
["foregroundColor", colors[1]],
|
|
["selectionColor", colors[2]],
|
|
["nosavequestion", "false"],
|
|
["keepOutput", "false"]
|
|
]);
|
|
|
|
setSettings();
|
|
}, handle);
|
|
|
|
settings.on("user/output", setSettings);
|
|
|
|
layout.on("themeChange", function(e) {
|
|
var colors = defaults[e.oldTheme];
|
|
if (!colors) return;
|
|
if (!(settings.get("user/output/@backgroundColor") == colors[0] &&
|
|
settings.get("user/output/@foregroundColor") == colors[1] &&
|
|
settings.get("user/output/@selectionColor") == colors[2]))
|
|
return false;
|
|
});
|
|
|
|
layout.on("themeDefaults", function(e) {
|
|
var colors = defaults[e.theme];
|
|
if (!colors) return;
|
|
settings.set("user/output/@backgroundColor", colors[0]);
|
|
settings.set("user/output/@foregroundColor", colors[1]);
|
|
settings.set("user/output/@selectionColor", colors[2]);
|
|
}, handle);
|
|
|
|
// Settings UI
|
|
|
|
prefs.add({
|
|
"Editors": {
|
|
"Output": {
|
|
position: 130,
|
|
"Text Color": {
|
|
type: "colorbox",
|
|
path: "user/output/@foregroundColor",
|
|
position: 10100
|
|
},
|
|
"Background Color": {
|
|
type: "colorbox",
|
|
path: "user/output/@backgroundColor",
|
|
position: 10200
|
|
},
|
|
"Selection Color": {
|
|
type: "colorbox",
|
|
path: "user/output/@selectionColor",
|
|
position: 10250
|
|
},
|
|
"Warn Before Closing Unnamed Configuration": {
|
|
type: "checkbox",
|
|
path: "user/output/@nosavequestion",
|
|
position: 10300
|
|
},
|
|
"Preserve log between runs": {
|
|
type: "checkbox",
|
|
path: "user/output/@keepOutput",
|
|
position: 10300
|
|
}
|
|
}
|
|
}
|
|
}, handle);
|
|
});
|
|
|
|
// Search through pages
|
|
function search(id, cmd, argv) {
|
|
if (!id) id = "output";
|
|
var tablist = tabs.getTabs();
|
|
for (var i = 0; i < tablist.length; i++) {
|
|
if (tablist[i].editorType != "output")
|
|
continue;
|
|
var state = tablist[i].document.getState();
|
|
var session = tablist[i].document.getSession();
|
|
if (!session)
|
|
continue;
|
|
var config = state.output && state.output.config || session.config;
|
|
var command = config.command || "";
|
|
var isSameCommand = command == cmd || command.startsWith(cmd) && /\s/.test(command[cmd.length]);
|
|
if (session.id == id || cmd && isSameCommand) {
|
|
tabs.activateTab(tablist[i]);
|
|
|
|
if (argv && argv.run)
|
|
tablist[i].editor.run(session, argv.callback);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function getOutputId() {
|
|
return "output" + Math.round(Math.random() * 100000) + counter++;
|
|
}
|
|
|
|
handle.search = search;
|
|
|
|
/***** Initialization *****/
|
|
|
|
var counter = 0;
|
|
|
|
function Output() {
|
|
var plugin = new Terminal(true);
|
|
|
|
var htmlNode;
|
|
var btnRun, currentSession, btnRunner, btnDebug, btnRestart;
|
|
var tbName, tbCommand, btnEnv, btnCwd;
|
|
|
|
/***** Methods *****/
|
|
|
|
function runNow(session, callback) {
|
|
if (!session)
|
|
session = currentSession;
|
|
|
|
var runner = session.runner;
|
|
if (!runner) {
|
|
session.runOnRunner = { callback: callback };
|
|
return;
|
|
}
|
|
|
|
if (session.terminal) {
|
|
var term = session.terminal.aceSession.term;
|
|
term.$resetScreenOnStateChange = false;
|
|
|
|
if (settings.getBool("user/output/@keepOutput"))
|
|
term.clearScreen(2);
|
|
else
|
|
term.reset();
|
|
}
|
|
|
|
// ignore if tmux tries to redraw old screen
|
|
var filter = session.filter;
|
|
session.filter = function() { return ""; };
|
|
|
|
var path = session.config.command;
|
|
var cfg = session.config;
|
|
var args = splitPathArgs(path);
|
|
|
|
path = args.shift();
|
|
|
|
if (session.process && session.process.running)
|
|
stop(done);
|
|
else
|
|
done();
|
|
|
|
function done() {
|
|
var refresh = tabs.getTabs().some(function(tab) {
|
|
return tab.path && /\.run$/.test(tab.path);
|
|
});
|
|
run.getRunner(runner.caption, refresh, function(err, result) {
|
|
// Make sure we have the latest runner if possible, or ignore err
|
|
if (!err)
|
|
runner = session.runner = result;
|
|
if (!runner.debugger) {
|
|
cfg.debug = undefined;
|
|
} else if (cfg.debug == null) {
|
|
cfg.debug = runner.$debugDefaultState != false;
|
|
}
|
|
|
|
if (cfg.debug)
|
|
debug.checkAttached(start);
|
|
else
|
|
start();
|
|
});
|
|
}
|
|
|
|
function start() {
|
|
if (!runner)
|
|
runner = "auto";
|
|
|
|
var cwd = session.config.cwd || "";
|
|
if (cwd.charAt(0) == "/")
|
|
cwd = join(basePath, cwd);
|
|
|
|
session.process = debug.run(runner, {
|
|
path: path,
|
|
cwd: cwd,
|
|
env: session.config.env || {},
|
|
args: args,
|
|
debug: cfg.debug
|
|
}, session.id, function(err, pid) {
|
|
session.connect();
|
|
|
|
if (filter)
|
|
session.filter = filter;
|
|
|
|
if (err) {
|
|
transformButton(session);
|
|
session.process = null;
|
|
return showError(err);
|
|
}
|
|
|
|
session.updateTitle();
|
|
|
|
if (!session.process || session.process.running < session.process.STARTING)
|
|
return;
|
|
|
|
session.process.meta.debug = cfg.debug;
|
|
});
|
|
|
|
decorateProcess(session);
|
|
updateToolbar(session);
|
|
|
|
callback && callback(session.process, session.tab);
|
|
}
|
|
|
|
runGui.lastRun = [runner, path];
|
|
}
|
|
|
|
function splitPathArgs(pathArgs) {
|
|
if (!pathArgs) return [];
|
|
|
|
var results = [];
|
|
var lastStart = 0;
|
|
for (var i = 0; i < pathArgs.length; i++) {
|
|
var c = pathArgs[i];
|
|
if (c === "\\") {
|
|
pathArgs = pathArgs.substr(0, i) + pathArgs.substr(i + 1);
|
|
continue;
|
|
}
|
|
if (c === " ") {
|
|
if (lastStart < i)
|
|
results.push(pathArgs.substring(lastStart, i));
|
|
lastStart = i + 1;
|
|
}
|
|
}
|
|
var lastPart = pathArgs.substring(lastStart, i);
|
|
if (lastPart.length)
|
|
results.push(lastPart);
|
|
return results;
|
|
}
|
|
|
|
function decorateProcess(session) {
|
|
session.process.on("away", function() {
|
|
if (session == currentSession) {
|
|
btnRun.disable();
|
|
btnRestart.disable();
|
|
}
|
|
});
|
|
session.process.on("back", function() {
|
|
if (session == currentSession) {
|
|
btnRun.enable();
|
|
|
|
if (!session.process || session.process.running != session.process.STOPPED)
|
|
btnRestart.enable();
|
|
}
|
|
});
|
|
session.process.on("started", function() {
|
|
if (session == currentSession) {
|
|
btnRun.enable();
|
|
btnRestart.enable();
|
|
transformButton(session);
|
|
}
|
|
session.updateTitle();
|
|
}, plugin);
|
|
session.process.on("stopping", function() {
|
|
if (session == currentSession) {
|
|
btnRun.disable();
|
|
btnRestart.disable();
|
|
}
|
|
session.updateTitle();
|
|
}, plugin);
|
|
session.process.on("stopped", function() {
|
|
if (session == currentSession) {
|
|
btnRun.enable();
|
|
btnRestart.enable();
|
|
transformButton(session);
|
|
}
|
|
session.updateTitle();
|
|
}, plugin);
|
|
}
|
|
|
|
function transformButton(session) {
|
|
if (session != currentSession)
|
|
return;
|
|
|
|
btnRun.setAttribute("disabled", !c9.has(c9.NETWORK));
|
|
|
|
if (session && session.process && session.process.running) {
|
|
btnRun.setAttribute("caption", "Stop");
|
|
btnRun.setAttribute("tooltip", "");
|
|
btnRun.setAttribute("class", "runbtn running");
|
|
btnRun.enable();
|
|
|
|
btnRestart.show();
|
|
btnRestart.enable();
|
|
}
|
|
else {
|
|
var path = (tbCommand.value || "").split(" ", 1)[0];
|
|
|
|
btnRun.setAttribute("caption", "Run");
|
|
btnRun.setAttribute("class", "runbtn stopped");
|
|
|
|
btnRestart.disable();
|
|
|
|
return path;
|
|
}
|
|
}
|
|
|
|
function stop(callback) {
|
|
var session = currentSession;
|
|
if (!session) return;
|
|
|
|
var process = session.process;
|
|
if (process)
|
|
process.stop(function(err) {
|
|
if (err) {
|
|
showError(err.message || err);
|
|
}
|
|
else {
|
|
debug.stop();
|
|
}
|
|
|
|
if (session == currentSession)
|
|
transformButton(session);
|
|
|
|
callback(err);
|
|
});
|
|
}
|
|
|
|
function detectRunner(session) {
|
|
var path = session.path;
|
|
if (!path) return;
|
|
|
|
run.detectRunner({ path: path }, function(err, runner) {
|
|
session.setRunner(err ? null : runner);
|
|
});
|
|
}
|
|
|
|
function saveConfig() {
|
|
if (!currentSession || !currentSession.config.name)
|
|
return;
|
|
|
|
var json = settings.getJson("project/run/configs") || {};
|
|
json[currentSession.config.name] = currentSession.config;
|
|
settings.setJson("project/run/configs", json);
|
|
|
|
currentSession.updateTitle();
|
|
handleEmit("runConfigSaved", currentSession.config);
|
|
}
|
|
|
|
function removeConfig() {
|
|
if (!currentSession || !currentSession.config.name)
|
|
return;
|
|
|
|
var json = settings.getJson("project/run/configs") || {};
|
|
delete json[currentSession.config.name];
|
|
settings.setJson("project/run/configs", json);
|
|
|
|
currentSession.updateTitle();
|
|
}
|
|
|
|
var model, datagrid, mnuEnv;
|
|
function drawEnv() {
|
|
if (model) return;
|
|
|
|
model = new TreeData();
|
|
model.emptyMessage = "Type a new environment variable here...";
|
|
|
|
layout.on("eachTheme", function(e) {
|
|
var height = parseInt(ui.getStyleRule(".blackdg .row", "height"), 10) || 24;
|
|
model.rowHeight = height;
|
|
|
|
if (e.changed) datagrid.resize(true);
|
|
});
|
|
|
|
model.$sorted = false;
|
|
model.columns = [{
|
|
caption: "Name",
|
|
value: "name",
|
|
width: "40%",
|
|
editor: "textbox"
|
|
}, {
|
|
caption: "Value",
|
|
value: "value",
|
|
width: "60%",
|
|
editor: "textbox"
|
|
}];
|
|
model.updateNodeAfterChange = function(node) {
|
|
return findNode(node.name);
|
|
};
|
|
|
|
mnuEnv.$setStyleClass(mnuEnv.$ext, "envcontainer");
|
|
var div = mnuEnv.$ext.appendChild(document.createElement("div"));
|
|
|
|
datagrid = new Tree(div);
|
|
datagrid.renderer.setTheme({ cssClass: "blackdg" });
|
|
datagrid.setDataProvider(model);
|
|
datagrid.edit = new TreeEditor(datagrid);
|
|
|
|
var justEdited = false;
|
|
|
|
datagrid.textInput.getElement().addEventListener("keydown", function(e) {
|
|
var cursor = datagrid.selection.getCursor();
|
|
var key = keys[e.keyCode] || "";
|
|
if (key.length == 1 || key.substr(0, 3) == "num" && cursor && !justEdited)
|
|
datagrid.edit.startRename(cursor, 0);
|
|
}, true);
|
|
|
|
datagrid.textInput.getElement().addEventListener("keyup", function(e) {
|
|
var cursor = datagrid.selection.getCursor();
|
|
if (e.keyCode == 13 && cursor && !justEdited)
|
|
datagrid.edit.startRename(cursor, 0);
|
|
}, true);
|
|
|
|
datagrid.on("delete", function(e) {
|
|
datagrid.selection.getSelectedNodes().forEach(function(n) {
|
|
delete model.session.config.env[n.name];
|
|
model._signal("remove", n);
|
|
});
|
|
|
|
reloadModel();
|
|
saveConfig();
|
|
|
|
mnuEnv.resize();
|
|
});
|
|
|
|
datagrid.on("createEditor", function(e) {
|
|
e.ace.commands.bindKeys({
|
|
"Up": function(ace) { ace.treeEditor.editNext(-1, true); },
|
|
"Down": function(ace) { ace.treeEditor.editNext(1, true); }
|
|
});
|
|
});
|
|
|
|
datagrid.on("rename", function(e) {
|
|
if (!e.column) return;
|
|
|
|
var node = e.node;
|
|
var config = model.session.config;
|
|
var name, value;
|
|
|
|
if (e.column.value == "name" || node.isNew) {
|
|
name = e.value;
|
|
value = node.value || "";
|
|
}
|
|
else {
|
|
name = node.name;
|
|
value = e.value;
|
|
}
|
|
|
|
if (name === node.name && value === node.value)
|
|
return;
|
|
|
|
if (!node.isNew || !name)
|
|
delete config.env[node.name];
|
|
|
|
if (name) {
|
|
config.env[name] = value;
|
|
var envVariable = {};
|
|
envVariable[name] = value;
|
|
handleEmit("envSet", name, config.env);
|
|
}
|
|
|
|
reloadModel();
|
|
saveConfig();
|
|
|
|
if (node.isNew && findNode(name))
|
|
datagrid.edit.startRename(findNode(name), 1);
|
|
else
|
|
model.selection.setSelection(findNode(name));
|
|
|
|
mnuEnv.resize();
|
|
});
|
|
|
|
datagrid.on("rename", function(e) {
|
|
justEdited = true;
|
|
setTimeout(function() { justEdited = false; }, 500);
|
|
});
|
|
|
|
mnuEnv.resize = function() {
|
|
if (!mnuEnv.visible) return;
|
|
|
|
setTimeout(function() {
|
|
if (mnuEnv.opener) {
|
|
mnuEnv.reopen = true;
|
|
mnuEnv.display(null, null, true, mnuEnv.opener);
|
|
mnuEnv.reopen = false;
|
|
}
|
|
}, 10);
|
|
};
|
|
}
|
|
|
|
function findNode(name) {
|
|
var f;
|
|
model.root.children.some(function(n) {
|
|
return n.name == name && (f = n);
|
|
});
|
|
return f;
|
|
}
|
|
|
|
function reloadModel() {
|
|
var env = [];
|
|
var cfg = model.session.config;
|
|
var sel = model.selection.getCursor();
|
|
|
|
for (var name in cfg.env) {
|
|
env.push({
|
|
name: name,
|
|
value: cfg.env[name]
|
|
});
|
|
}
|
|
env.sort(function(a, b) {
|
|
return TreeData.alphanumCompare(a.name, b.name);
|
|
});
|
|
model.newEnvNode = model.newEnvNode || {
|
|
name: model.emptyMessage,
|
|
className: "newenv",
|
|
fullWidth: true,
|
|
isNew: true,
|
|
};
|
|
model.setRoot({
|
|
items: [].concat(env, model.newEnvNode),
|
|
$sorted: true
|
|
});
|
|
|
|
// restore selection
|
|
if (sel && sel.name)
|
|
model.selection.setSelection(findNode(sel.name));
|
|
}
|
|
|
|
function updateConfig(session) {
|
|
var configs = settings.getJson("project/run/configs");
|
|
var cfg = configs[session.config.name] || session.config;
|
|
|
|
session.config = cfg;
|
|
updateRunner(session);
|
|
|
|
updateToolbar(session);
|
|
}
|
|
|
|
function updateRunner(session) {
|
|
session.runner = null;
|
|
|
|
var runner = session.config.runner;
|
|
if (runner && runner != "auto") {
|
|
run.getRunner(session.config.runner, function(err, result) {
|
|
session.setRunner(err ? null : result);
|
|
});
|
|
}
|
|
else {
|
|
var path = /([^\\ ]|\\.)*/.exec(session.config.command || "")[0];
|
|
if (!path) return;
|
|
|
|
run.detectRunner({ path: path }, function(err, runner) {
|
|
session.setRunner(err ? null : runner);
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateToolbar(session) {
|
|
if (session != currentSession)
|
|
return;
|
|
|
|
transformButton(session);
|
|
|
|
var cfg = session.config;
|
|
btnDebug.setAttribute("visible",
|
|
!session.runner || session.runner.debugger ? true : false);
|
|
if (cfg.debug != null)
|
|
btnDebug.setAttribute("value", cfg.debug);
|
|
btnRunner.setAttribute("caption", "Runner: "
|
|
+ (cfg.runner || "Auto"));
|
|
tbCommand.setAttribute("value", cfg.command);
|
|
tbName.setAttribute("value", cfg.name);
|
|
// btnEnv.setAttribute("value", );
|
|
btnCwd.$ext.title = cfg.cwd || "Current working directory (unset)";
|
|
|
|
btnRun.setAttribute("disabled", !c9.has(c9.NETWORK));
|
|
|
|
if (session.config.toolbar === false) {
|
|
htmlNode.classList.add("hidetoolbar");
|
|
} else {
|
|
htmlNode.classList.remove("hidetoolbar");
|
|
}
|
|
}
|
|
|
|
/***** Lifecycle *****/
|
|
|
|
plugin.on("draw", function(e) {
|
|
// Create UI elements
|
|
ui.insertMarkup(e.tab, markup, plugin);
|
|
|
|
htmlNode = e.htmlNode;
|
|
|
|
// Set output class name
|
|
e.htmlNode.className += " output";
|
|
|
|
// Decorate UI
|
|
btnRun = plugin.getElement("btnRun");
|
|
btnRestart = plugin.getElement("btnRestart");
|
|
btnDebug = plugin.getElement("btnDebug");
|
|
btnRunner = plugin.getElement("btnRunner");
|
|
tbCommand = plugin.getElement("tbCommand");
|
|
tbName = plugin.getElement("tbName");
|
|
btnEnv = plugin.getElement("btnEnv");
|
|
btnCwd = plugin.getElement("btnCwd");
|
|
|
|
btnRun.on("click", function() {
|
|
var session = currentSession;
|
|
if (!session) return;
|
|
|
|
if (session.process && session.process.running) {
|
|
stop(function() {});
|
|
}
|
|
else {
|
|
runNow(session);
|
|
}
|
|
});
|
|
|
|
btnRestart.on("click", function() {
|
|
var session = currentSession;
|
|
if (!session) return;
|
|
|
|
if (session.process && session.process.running > 0)
|
|
stop(function() { runNow(session); });
|
|
});
|
|
|
|
btnDebug.on("prop.value", function(e) {
|
|
if (currentSession) {
|
|
currentSession.config.debug = e.value;
|
|
saveConfig();
|
|
}
|
|
});
|
|
tbCommand.on("afterchange", function(e) {
|
|
if (currentSession)
|
|
currentSession.changeCommand(e.value);
|
|
});
|
|
tbCommand.$ext.addEventListener("keydown", function(e) {
|
|
if (e.keyCode === 13)
|
|
currentSession && runNow(currentSession);
|
|
});
|
|
tbName.on("afterchange", function(e) {
|
|
if (!currentSession) return;
|
|
|
|
currentSession.changeName(e.value);
|
|
});
|
|
|
|
btnRunner.setAttribute("submenu", runGui.getElement("mnuRunAs"));
|
|
btnRunner.onitemclick = function(value) {
|
|
// Stop the current process
|
|
// @todo
|
|
|
|
// Start this run config with the new runner
|
|
run.getRunner(value, function(err, result) {
|
|
if (err)
|
|
return showError("Cannot use " + value + ": " + err);
|
|
|
|
currentSession.setRunner(result);
|
|
});
|
|
btnRunner.setAttribute("caption", "Runner: " + value);
|
|
|
|
// Set Button Caption
|
|
};
|
|
|
|
btnCwd.on("click", function selectCwd(e, cwd) {
|
|
cwd = cwd || currentSession.config && currentSession.config.cwd
|
|
|| currentSession.runner && currentSession.runner.working_dir
|
|
|| "/";
|
|
|
|
showSave("Select current working directory", cwd,
|
|
function(directory, stat, hide) {
|
|
if (!stat) {
|
|
hide();
|
|
return showAlert(
|
|
"Select current working directory",
|
|
"Directory does not exist",
|
|
directory,
|
|
selectCwd.bind(null, e, directory)
|
|
);
|
|
}
|
|
currentSession.config.cwd = directory;
|
|
updateToolbar(currentSession);
|
|
handleEmit("cwdSet", directory);
|
|
hide();
|
|
},
|
|
function() {},
|
|
{
|
|
chooseCaption: "Select",
|
|
hideFileInput: true
|
|
}
|
|
);
|
|
});
|
|
|
|
mnuEnv = new ui.menu({
|
|
htmlNode: document.body,
|
|
width: 250
|
|
});
|
|
btnEnv.setAttribute("submenu", mnuEnv);
|
|
|
|
mnuEnv.on("prop.visible", function(e) {
|
|
if (!e.value || mnuEnv.reopen)
|
|
return;
|
|
|
|
drawEnv();
|
|
model.session = currentSession;
|
|
if (!model.session.config.env)
|
|
model.session.config.env = {};
|
|
reloadModel();
|
|
|
|
var rect = mnuEnv.opener.$ext.getBoundingClientRect();
|
|
var top = rect.top;
|
|
var bottom = window.innerHeight - rect.bottom;
|
|
|
|
var maxRows = Math.floor(Math.max(top, bottom) / datagrid.model.rowHeight) - 2;
|
|
datagrid.setOption("maxLines", maxRows);
|
|
datagrid.resize();
|
|
mnuEnv.resize();
|
|
|
|
var node = datagrid.getFirstNode();
|
|
var isNew = node.className == "newenv";
|
|
if (isNew) datagrid.select(node);
|
|
|
|
if (isNew) {
|
|
setTimeout(function() {
|
|
datagrid.edit.startRename(node);
|
|
}, 30);
|
|
}
|
|
});
|
|
|
|
c9.on("stateChange", function() {
|
|
updateToolbar(currentSession);
|
|
}, plugin);
|
|
});
|
|
|
|
plugin.on("documentLoad", function(e) {
|
|
var doc = e.doc;
|
|
var tab = e.doc.tab;
|
|
var session = doc.getSession();
|
|
|
|
if (!session.config)
|
|
session.config = { env: {}};
|
|
|
|
session.tab = tab;
|
|
|
|
session.run = function() {
|
|
runNow(session);
|
|
};
|
|
|
|
session.setRunner = function(runner) {
|
|
if (!runner) {
|
|
run.getRunner("Shell command", function(err, runner) {
|
|
if (!err) session.setRunner(runner);
|
|
});
|
|
return;
|
|
}
|
|
|
|
session.runner = runner;
|
|
session.config.runner = runner.caption;
|
|
|
|
if (session.runOnRunner) {
|
|
runNow(session, session.runOnRunner.callback);
|
|
delete session.runOnRunner;
|
|
}
|
|
|
|
saveConfig();
|
|
|
|
if (session == currentSession) {
|
|
btnRunner.setAttribute("caption", "Runner: "
|
|
+ (runner ? runner.caption : "Auto"));
|
|
updateToolbar(session);
|
|
}
|
|
};
|
|
|
|
session.filter = function(data, recur) {
|
|
// Ignore clear screen when detaching
|
|
if (/output:0:.*\[dead\] - /.test(data))
|
|
return;
|
|
|
|
if (
|
|
/\[exited\]\r/.test(data) ||
|
|
/Set option: remain-on-exit \-\> on/.test(data)
|
|
) {
|
|
session.stopped = false;
|
|
session.terminal.showCursor();
|
|
if (!session.process) {
|
|
plugin.setState(session.doc, {
|
|
running: {
|
|
runner: session.runner,
|
|
debug: session.config.debug,
|
|
name: session.id,
|
|
pid: -1,
|
|
},
|
|
cwd: session.cwd,
|
|
id: session.id,
|
|
});
|
|
}
|
|
// tab.classList.add(session.process
|
|
// && session.process.running > 0 ? "running" : "loading");
|
|
return session.process && session.process.checkState();
|
|
}
|
|
|
|
// Change the last lines of TMUX saying the pane is dead
|
|
if (data.indexOf("Pane is dead") > -1) {
|
|
if (data.lastIndexOf("\x1b[1mPane is dead\x1b[H") === 0) {
|
|
data = "";
|
|
} else if (data === "\r\x1b[1mPane is dead\x1b[m\x1b[K") {
|
|
data = "";
|
|
} else {
|
|
data = data
|
|
.replace(/\s*Pane is dead([\s\S]*)13H/g, "") // "$117H")
|
|
.replace(/\s*Pane is dead/g, "");
|
|
}
|
|
data = data.replace(/\s+$/, "");
|
|
|
|
session.terminal.hideCursor();
|
|
|
|
tab.classList.remove(session.process
|
|
&& session.process.running > 0 ? "running" : "loading");
|
|
|
|
if (session.process && session.process.running > 1)
|
|
session.process.checkState();
|
|
|
|
// sometimes if process finishes quickly and with little output
|
|
// tmux won't show most of it so we have to reload
|
|
if (!recur && session.terminal.lines.length < 2 * session.terminal.rows)
|
|
setTimeout(session.$reloadHistory);
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
session.$reloadHistory = function() {
|
|
if (session.getOutputHistory) {
|
|
session.getOutputHistory({
|
|
id: session.id,
|
|
start: -1000,
|
|
end: 1000
|
|
}, function(e, output) {
|
|
if (e || !output) return;
|
|
if (session.filter)
|
|
output = session.filter(output, true);
|
|
session.terminal.reset();
|
|
var convertEol = session.terminal.convertEol;
|
|
session.terminal.convertEol = true;
|
|
session.terminal.write(output);
|
|
session.terminal.convertEol = convertEol;
|
|
});
|
|
}
|
|
};
|
|
|
|
session.updateTitle = function() {
|
|
var process = session.process;
|
|
|
|
doc.tooltip =
|
|
doc.title = (session.config.name || session.config.command || "[New]")
|
|
+ " - " + (!process
|
|
? "Idle"
|
|
: (process.running
|
|
? "Running"
|
|
: "Stopped"));
|
|
|
|
if (process && process.running)
|
|
tab.classList.add("running");
|
|
else
|
|
tab.classList.remove("running");
|
|
tab.classList.remove("loading");
|
|
};
|
|
|
|
session.changeCommand = function(value) {
|
|
currentSession.config.command = value;
|
|
saveConfig();
|
|
|
|
if (!currentSession.runner)
|
|
updateRunner(currentSession);
|
|
};
|
|
|
|
session.changeName = function(value) {
|
|
if (!value && session.config.name) {
|
|
question.show("Remove this configuration?",
|
|
"You have cleared the name of this configuration.",
|
|
"Would you like to remove this configuration from your project settings?",
|
|
function() { // Yes
|
|
removeConfig();
|
|
session.config.name = "";
|
|
session.updateTitle();
|
|
handleEmit("runnerNameChanged", "");
|
|
},
|
|
function() { // No
|
|
// Revert change
|
|
tbName.setAttribute("value", session.config.name);
|
|
});
|
|
}
|
|
else {
|
|
removeConfig();
|
|
session.config.name = value;
|
|
saveConfig();
|
|
handleEmit("runnerNameChanged", value);
|
|
}
|
|
};
|
|
|
|
session.show = function(v) {
|
|
// plugin.ace.container.style.visibility = "visible";
|
|
};
|
|
|
|
session.hide = function(v) {
|
|
// plugin.ace.container.style.visibility = "hidden";
|
|
};
|
|
|
|
tab.on("beforeClose", function() {
|
|
if (!settings.getBool("user/output/nosavequestion")
|
|
&& (!session.config.name && session.config.command
|
|
&& !tab.meta.$ignore)) {
|
|
question.show("Unsaved changes",
|
|
"Are you sure you want to close this run configuration without saving it?",
|
|
"You can keep these settings in a run configuration "
|
|
+ "for easy access later. If you would like to do "
|
|
+ "this, choose No and fill in the name of the "
|
|
+ "run configuration prior to closing this tab.",
|
|
function() { // Yes
|
|
tab.meta.$ignore = true;
|
|
tab.close();
|
|
|
|
if (question.dontAsk)
|
|
settings.set("user/output/nosavequestion", "true");
|
|
},
|
|
function() { // No
|
|
// do nothing; allow user to set a name
|
|
|
|
if (question.dontAsk)
|
|
settings.set("user/output/nosavequestion", "true");
|
|
},
|
|
{ showDontAsk: true, yes: "Close", no: "Cancel" });
|
|
return false;
|
|
}
|
|
}, session);
|
|
|
|
// Preferred before to be before the state is serialized
|
|
tab.on("beforeUnload", function() {
|
|
if (session.process && session.process.running) {
|
|
session.process.stop(function() {});
|
|
tab.classList.remove("running");
|
|
}
|
|
});
|
|
|
|
if (e.state.hidden || e.state.run)
|
|
session.hide();
|
|
|
|
function setTabColor() {
|
|
var bg = settings.get("user/output/@backgroundColor");
|
|
var shade = util.shadeColor(bg, 0.75);
|
|
var skinName = settings.get("user/general/@skin");
|
|
var isLight = ~skinName.indexOf("flat") || shade.isLight;
|
|
doc.tab.backgroundColor = isLight ? bg : shade.color;
|
|
|
|
if (isLight) {
|
|
if (~skinName.indexOf("flat") && !shade.isLight) {
|
|
doc.tab.classList.add("dark");
|
|
plugin.container.className = "c9terminalcontainer flat-dark";
|
|
}
|
|
else {
|
|
doc.tab.classList.remove("dark");
|
|
plugin.container.className = "c9terminalcontainer";
|
|
}
|
|
}
|
|
else {
|
|
doc.tab.classList.add("dark");
|
|
plugin.container.className = "c9terminalcontainer dark";
|
|
}
|
|
}
|
|
setTabColor();
|
|
|
|
handle.on("settingsUpdate", setTabColor, doc);
|
|
});
|
|
|
|
plugin.on("documentActivate", function(e) {
|
|
if (currentSession && currentSession.loaded) {
|
|
// needed because tab change fires before blur event
|
|
if (tbCommand.getValue() != currentSession.config.command)
|
|
currentSession.changeCommand(tbCommand.getValue());
|
|
if (tbName.getValue() != currentSession.config.name)
|
|
currentSession.changeName(tbName.getValue());
|
|
}
|
|
|
|
currentSession = e.doc.getSession();
|
|
updateToolbar(currentSession);
|
|
});
|
|
|
|
plugin.on("documentUnload", function(e) {
|
|
|
|
});
|
|
|
|
plugin.on("getState", function(e) {
|
|
var session = e.doc.getSession();
|
|
if (!session.id)
|
|
return;
|
|
|
|
var state = e.state;
|
|
state.config = session.config;
|
|
|
|
if (session.process && session.process.running) {
|
|
state.running = session.process.getState();
|
|
state.running.debug = session.process.meta.debug;
|
|
}
|
|
});
|
|
|
|
plugin.on("setState", function(e) {
|
|
var session = e.doc.getSession();
|
|
var state = e.state;
|
|
|
|
if (state.config) {
|
|
session.config = state.config;
|
|
updateConfig(session);
|
|
}
|
|
|
|
if (state.running && !session.process) {
|
|
session.process = run.restoreProcess(state.running);
|
|
decorateProcess(session);
|
|
transformButton(session);
|
|
|
|
if (state.running.debug && session.process.running > 0) {
|
|
session.process.meta.debug = true;
|
|
session.process.once("back", function() {
|
|
debug.debug(session.process, true, function(err) {
|
|
if (err)
|
|
return; // Either the debugger is not found or paused
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
if (state.run)
|
|
runNow(session, state.callback);
|
|
else
|
|
session.connect();
|
|
|
|
session.updateTitle();
|
|
});
|
|
|
|
plugin.on("unload", function() {
|
|
currentSession = null;
|
|
});
|
|
|
|
plugin.freezePublicAPI({
|
|
/**
|
|
* @param {Session} session
|
|
*/
|
|
run: runNow,
|
|
|
|
/**
|
|
* @ignore This is here to overwrite default behavior
|
|
*/
|
|
isClipboardAvailable: function(e) { return !e.fromKeyboard; },
|
|
|
|
get relatedPath() {
|
|
if (!currentSession) return;
|
|
var path = currentSession && currentSession.config.command;
|
|
if (path && path[0] != "~" && path[0] != "/")
|
|
path = "/" + path;
|
|
return path && splitPathArgs(path)[0];
|
|
}
|
|
});
|
|
|
|
return plugin;
|
|
}
|
|
|
|
register(null, {
|
|
output: handle
|
|
});
|
|
}
|
|
});
|