mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-01-23 18:55:26 +00:00
feature(terminal) add optional --terminal support
This commit is contained in:
parent
9c80c0f3ac
commit
db2a58ca44
14 changed files with 266 additions and 19 deletions
64
HELP.md
64
HELP.md
|
|
@ -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
|
||||
---------------
|
||||

|
||||
|
||||
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 */
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
129
client/modules/terminal.js
Normal 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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
.view {
|
||||
height: 100%;
|
||||
font-size: 16px;
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
|
|||
BIN
img/screen/terminal.png
Normal file
BIN
img/screen/terminal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -24,6 +24,8 @@
|
|||
"configDialog": true,
|
||||
"onePanelMode": false,
|
||||
"configDialog": true,
|
||||
"console": true
|
||||
"console": true,
|
||||
"terminal": false,
|
||||
"terminalPath": ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"upload",
|
||||
"operation",
|
||||
"konsole",
|
||||
"terminal",
|
||||
"cloud", [{
|
||||
"name": "remote",
|
||||
"data": [{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
29
server/terminal.js
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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`,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue