feature(terminal) add optional --terminal support

This commit is contained in:
coderaiser 2017-03-03 17:06:36 +02:00
parent 9c80c0f3ac
commit db2a58ca44
14 changed files with 266 additions and 19 deletions

64
HELP.md
View file

@ -80,6 +80,8 @@ Cloud Commander supports command line parameters:
| `--one-panel-mode` | set one panel mode
`--config-dialog` | enable config dialog
`--console` | enable console
`--terminal` | enable terminal
`--terminal-path` | set terminal path
| `--no-server` | do not start server
| `--no-auth` | disable authorization
| `--no-online` | load scripts from local server
@ -90,6 +92,7 @@ Cloud Commander supports command line parameters:
| `--no-one-panel-mode` | unset one panel mode
| `--no-config-dialog` | disable config dialog
| `--no-console` | disable console
| `--no-terminal` | disable terminal
If no parameters given Cloud Commander reads information from `~/.cloudcmd.json` and use
port from it (`8000` default). if port variables `PORT` or `VCAP_APP_PORT` isn't exist.
@ -203,9 +206,62 @@ Console
For more details see [console hot keys](https://github.com/cloudcmd/console#hot-keys "Console Hot Keys").
### Environment Variables
Terminal
---------------
![Terminal](/img/screen/terminal.png "Terminal")
Every program executed in `console` has these `environment` variables:
### Install
`Terminal` disabled and not installed by default. To use it you should install [gritty](https://github.com/cloudcmd/gritty "Gritty") with:
```sh
npm i gritty -g
```
And then set the path of a terminal with:
```sh
cloudcmd --terminal --terminal-path `gritty --path` --save
```
### Windows
On Windows you need to install `windows-build-tools` before:
```sh
npm install --global windows-build-tools
```
Then get path of a `gritty` with:
```sh
gritty --path
```
It will returns something like:
```sh
C:\Users\coderaiser\AppData\Roaming\npm\node_modules\gritty
```
Set this path as `--terminal-path` with:
```sh
cloudcmd --save --terminal --terminal-path "C:\Users\coderaiser\AppData\Roaming\npm\node_modules\gritty"
```
After that you can use `terminal` in the same way as a `console`.
### Hot keys
|Key |Operation
|:----------------------|:--------------------------------------------
| `Shift` + `~` | open
| `Shift` + `Esc` | close
Environment Variables
---------------
Every program executed in `console` or `terminal` has these `environment` variables:
- `ACTIVE_DIR` - directory that contains cursor
- `PASSIVE_DIR` - directory with no cursor
@ -260,7 +316,9 @@ Here is description of options:
"htmlDialogs" : true, /* use html dialogs */
"onePanelMode" : false, /* set one panel mode */
"configDialog" : true, /* enable config dialog */
"console" : true /* enable console */
"console" : true, /* enable console */
"terminal" : false, /* disable terminal */
"terminalPath" : '', /* path of a terminal */
}
```

View file

@ -18,7 +18,8 @@ const args = require('minimist')(argv.slice(2), {
'editor',
'packer',
'root',
'prefix'
'prefix',
'terminal-path',
],
boolean: [
'auth',
@ -31,6 +32,7 @@ const args = require('minimist')(argv.slice(2), {
'progress',
'config-dialog',
'console',
'terminal',
'one-panel-mode',
'html-dialogs'
],
@ -49,7 +51,9 @@ const args = require('minimist')(argv.slice(2), {
prefix : config('prefix') || '',
progress : config('progress'),
console : config('console'),
terminal : config('terminal'),
'terminal-path': config('terminalPath'),
'config-dialog': config('configDialog'),
'one-panel-mode': config('onePanelMode'),
'html-dialogs': config('htmlDialogs')
@ -88,6 +92,8 @@ if (args.version) {
config('username', args.username);
config('progress', args.progress);
config('console', args.console);
config('terminal', args.terminal);
config('terminalPath', args.terminalPath);
config('editor', args.editor);
config('prefix', args.prefix);
config('root', args.root);

View file

@ -98,12 +98,12 @@ function showError(name) {
throw(error);
}
function getSystemFile(url, callback) {
function getSystemFile(file, callback) {
const prefix = CloudCmd.PREFIX;
if (!Promises[url])
Promises[url] = new Promise((success, error) => {
url = prefix + url;
if (!Promises[file])
Promises[file] = new Promise((success, error) => {
const url = prefix + file;
load.ajax({
url,
@ -112,10 +112,10 @@ function getSystemFile(url, callback) {
});
});
Promises[url].then((data) => {
Promises[file].then((data) => {
callback(null, data);
}, (error) => {
Promises[url] = null;
Promises[file] = null;
callback(error);
});
}

View file

@ -347,6 +347,9 @@ function KeyProto() {
break;
case Key.TRA:
if (shift)
return CloudCmd.Terminal.show();
CloudCmd.Konsole.show();
event.preventDefault();
break;

129
client/modules/terminal.js Normal file
View file

@ -0,0 +1,129 @@
'use strict';
/* global CloudCmd, gritty */
const exec = require('execon');
const load = require('../dom/load');
const DOM = require('../dom');
const Images = require('../dom/images');
const {Dialog} = DOM;
const TITLE = 'Terminal';
CloudCmd.Terminal = TerminalProto;
const {Key} = CloudCmd;
let Element;
let Loaded;
let Terminal;
const {config} = CloudCmd;
function TerminalProto() {
if (!config('terminal'))
return;
Images.show.load('top');
exec.series([
CloudCmd.View,
loadAll,
create,
show,
]);
Element = load({
name: 'div',
style: 'height: 99%',
className : 'terminal',
});
return module.exports;
}
module.exports.show = show;
module.exports.hide = hide;
function hide () {
CloudCmd.View.hide();
}
function getPrefix() {
return CloudCmd.PREFIX + '/gritty';
}
function getEnv() {
return {
ACTIVE_DIR: DOM.getCurrentDirPath,
PASSIVE_DIR: DOM.getNotCurrentDirPath,
CURRENT_NAME: DOM.getCurrentName,
CURRENT_PATH: DOM.getCurrentPath
};
}
function create(callback) {
const options = {
env: getEnv(),
prefix: getPrefix(),
socketPath: CloudCmd.PREFIX,
};
const {socket, terminal} = gritty(Element, options);
terminal.focus();
Terminal = terminal;
terminal.on('key', (char, {keyCode, shiftKey}) => {
if (shiftKey && keyCode === Key.ESC) {
hide();
}
});
socket.on('connect', exec.with(authCheck, socket));
exec(callback);
}
function authCheck(spawn) {
if (!config('auth'))
return;
spawn.emit('auth', config('username'), config('password'));
spawn.on('reject', () => {
Dialog.alert(TITLE, 'Wrong credentials!');
});
}
function show(callback) {
if (!Loaded)
return;
CloudCmd.View.show(Element, {
afterShow: () => {
if (Terminal) {
Terminal.fit(); // lines corrupt without
Terminal.focus();
}
exec(callback);
}
});
}
function loadAll(callback) {
const prefix = getPrefix();
const url = prefix + '/gritty.js';
DOM.load.js(url, (error) => {
if (error)
return Dialog.alert(TITLE, error.message);
Loaded = true;
exec(callback);
});
}

View file

@ -1,4 +1,5 @@
.view {
height: 100%;
font-size: 16px;
white-space: pre;
}

BIN
img/screen/terminal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -24,6 +24,8 @@
"configDialog": true,
"onePanelMode": false,
"configDialog": true,
"console": true
"console": true,
"terminal": false,
"terminalPath": ""
}

View file

@ -18,6 +18,8 @@
"--one-panel-mode ": "set one panel mode",
"--config-dialog ": "enable config dialog",
"--console ": "enable console",
"--terminal ": "enable terminal",
"--terminal-path ": "set terminal path",
"--open ": "open web browser when server started",
"--no-server ": "do not start server",
"--no-auth ": "disable authorization",
@ -28,5 +30,6 @@
"--no-html-dialogs ": "do not use html dialogs",
"--no-one-panel-mode ": "unset one panel mode",
"--no-config-dialog ": "disable config dialog",
"--no-console ": "disable console"
"--no-console ": "disable console",
"--no-terminal ": "disable terminal"
}

View file

@ -11,6 +11,7 @@
"upload",
"operation",
"konsole",
"terminal",
"cloud", [{
"name": "remote",
"data": [{

View file

@ -42,6 +42,8 @@ programs in browser from any computer, mobile or tablet device.
--one-panel-mode set one panel mode
--config-dialog enable config dialog
--console enable console
--terminal enable terminal
--terminal-path set terminal path
--no-auth disable authorization
--no-server do not start server
--no-online load scripts from local server
@ -52,6 +54,7 @@ programs in browser from any computer, mobile or tablet device.
--no-one-panel-mode unset one panel mode
--no-config-dialog disable config dialog
--no-console disable console
--no-terminal disable terminal
.SH RESOURCES AND DOCUMENTATION

View file

@ -13,6 +13,7 @@ const route = require(DIR + 'route');
const validate = require(DIR + 'validate');
const prefixer = require(DIR + 'prefixer');
const pluginer = require(DIR + 'plugins');
const terminal = require(DIR + 'terminal');
const apart = require('apart');
const join = require('join-io');
@ -32,8 +33,9 @@ const omnes = require('omnes/legacy');
const criton = require('criton');
const root = () => config('root');
const emptyFunc = (req, res, next) => next();
emptyFunc.middle = () => emptyFunc;
const notEmpty = (a) => a;
const clean = (a) => a.filter(notEmpty);
const isDev = process.env.NODE_ENV === 'development';
@ -44,7 +46,7 @@ function getPrefix(prefix) {
return prefix || '';
}
module.exports = function(params) {
module.exports = (params) => {
const p = params || {};
const options = p.config || {};
const plugins = p.plugins;
@ -54,7 +56,7 @@ module.exports = function(params) {
checkPlugins(plugins);
keys.forEach(function(name) {
keys.forEach((name) => {
let value = options[name];
switch(name) {
@ -176,6 +178,11 @@ function listen(prefix, socket) {
authCheck,
prefix: prefix + '/console',
});
config('terminal') && terminal.listen(socket, {
authCheck,
prefix: prefix + '/gritty',
});
}
function cloudcmd(prefix, plugins) {
@ -191,13 +198,17 @@ function cloudcmd(prefix, plugins) {
const ponseStatic = ponse.static(DIR_ROOT, {cache});
const funcs = [
konsole({
const funcs = clean([
config('console') && konsole({
prefix: prefix + '/console',
minify,
online,
}),
config('terminal') && terminal({
prefix: prefix + '/gritty',
}),
edward({
prefix : prefix + '/edward',
minify,
@ -277,7 +288,7 @@ function cloudcmd(prefix, plugins) {
pluginer(plugins),
ponseStatic
];
]);
return funcs;
}

29
server/terminal.js Normal file
View file

@ -0,0 +1,29 @@
'use strict';
const tryCatch = require('try-catch');
const config = require('./config');
const noop = () => {};
noop.listen = noop;
module.exports = getTerminal(config('terminal'));
function getTerminal(term) {
if (!term)
return noop;
let result;
const e = tryCatch(() => {
result = require(config('terminalPath'));
});
if (!e)
return result;
config('terminal', false);
console.log(`cloudcmd --terminal: ${e.message}`);
return noop;
}

View file

@ -52,6 +52,7 @@ module.exports = {
[modules + '/upload']: `${dirModules}/upload.js`,
[modules + '/operation']: `${dirModules}/operation.js`,
[modules + '/konsole']: `${dirModules}/konsole.js`,
[modules + '/terminal']: `${dirModules}/terminal.js`,
[modules + '/cloud']: `${dirModules}/cloud.js`,
[modules + '/polyfill']: `${dirModules}/polyfill.js`,
},