401 lines
7.1 KiB
JavaScript
Executable File
401 lines
7.1 KiB
JavaScript
Executable File
var tty = require('tty'),
|
|
fs = require('fs'),
|
|
Structr = require('structr'),
|
|
beanpole = require('beanpole'),
|
|
_buffer = '',
|
|
router = beanpole.router();
|
|
|
|
exports.utils = require('./utils');
|
|
|
|
|
|
//CLEAN ME!!!!!!!!!!!!!!!!!
|
|
|
|
_delimiterRepl = /\s+/g,
|
|
_delimiter = ' ';
|
|
|
|
|
|
var _queue = [],
|
|
_queueRunning = false;
|
|
|
|
|
|
/**
|
|
* queued commands
|
|
*/
|
|
|
|
exports.next = function(callback)
|
|
{
|
|
exports.queue(callback)();
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
exports.queue = function(callback)
|
|
{
|
|
return function()
|
|
{
|
|
var args = arguments,
|
|
listeners = [],
|
|
self = {
|
|
next: function()
|
|
{
|
|
var args = arguments;
|
|
|
|
listeners.forEach(function(listener)
|
|
{
|
|
listener.apply(null, args);
|
|
})
|
|
|
|
_queueRunning = true;
|
|
if(_queue.length)
|
|
{
|
|
_queue.shift()();
|
|
}
|
|
else
|
|
{
|
|
_queueRunning = false;
|
|
}
|
|
},
|
|
attach: function(callback)
|
|
{
|
|
listeners.push(callback);
|
|
}
|
|
}
|
|
|
|
_queue.push(function()
|
|
{
|
|
callback.apply(self, args);
|
|
});
|
|
|
|
|
|
if(!_queueRunning)
|
|
{
|
|
self.next();
|
|
}
|
|
|
|
return exports;
|
|
}
|
|
|
|
return exports;
|
|
}
|
|
|
|
/**
|
|
* spacing between arguments
|
|
*/
|
|
|
|
exports.delimiter = function(value)
|
|
{
|
|
if(!arguments.length) return _delimiter;
|
|
|
|
_delimiterRepl = new RegExp(value + '+','ig');
|
|
|
|
return _delimiter = value;
|
|
};
|
|
|
|
|
|
/**
|
|
* Converts CLI arguments to beanpole routes. Nifty huh?
|
|
*/
|
|
|
|
function _toRoute(type)
|
|
{
|
|
return type.replace(_delimiterRepl, '\/');
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* size of the terminal window
|
|
*/
|
|
|
|
exports.size = function()
|
|
{
|
|
return tty.getWindowSize();
|
|
}
|
|
|
|
/**
|
|
* number of columns in the terminal window (characters / width)
|
|
*/
|
|
|
|
exports.columns = function()
|
|
{
|
|
return exports.size()[1] || exports.size();
|
|
}
|
|
|
|
/**
|
|
* number of rows in the terminal window
|
|
*/
|
|
|
|
exports.rows = function()
|
|
{
|
|
return exports.size()[0];
|
|
}
|
|
|
|
var _inputPrefix = '> ';
|
|
|
|
exports.inputPrefix = function(prefix)
|
|
{
|
|
if(!arguments.length) return _inputPrefix;
|
|
|
|
|
|
return _inputPrefix = prefix || '';
|
|
}
|
|
|
|
|
|
exports.on = function(type, callback)
|
|
{
|
|
|
|
if(typeof type == 'object')
|
|
{
|
|
var disposables = [];
|
|
|
|
if(type instanceof Array)
|
|
{
|
|
for(var i = type.length; i--;)
|
|
{
|
|
disposables.push(exports.on(type[i], callback));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(var t in type)
|
|
{
|
|
|
|
disposables.push(exports.on(t, type[t]));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
dispose: function()
|
|
{
|
|
disposables.forEach(function(disposable)
|
|
{
|
|
disposable.dispose();
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
return router.on('push /'+_toRoute(type), callback);
|
|
|
|
}
|
|
|
|
exports.emit = function(type, data)
|
|
{
|
|
|
|
//catch parse errors
|
|
try
|
|
{
|
|
return router.push(_toRoute(type), data, { meta: { passive: 1 } });
|
|
}
|
|
catch(e)
|
|
{
|
|
//console.log(e.stack);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
exports.buffer = function(value, ignoreReplace)
|
|
{
|
|
if(!arguments.length) return _buffer;
|
|
|
|
_buffer = value;
|
|
|
|
return !ignoreReplace ? exports.replaceLine(value) : value;
|
|
}
|
|
|
|
/**
|
|
* Replaces the current line in the terminal window
|
|
*/
|
|
|
|
exports.replaceLine = function(buffer, cursorTo)
|
|
{
|
|
|
|
//need to clear the line before replacing it
|
|
process.stdout.clearLine();
|
|
|
|
//set the cursor to zero, otherwise we'll have padding we don't want
|
|
exports.cursor(0);
|
|
|
|
//write the buffer
|
|
process.stdout.write(buffer);
|
|
|
|
//set the cursor to the new position!
|
|
exports.cursor(cursorTo != undefined ? cursorTo : buffer.length);
|
|
|
|
return _buffer = buffer;
|
|
}
|
|
|
|
|
|
/**
|
|
* inserts text into the current line
|
|
*/
|
|
|
|
exports.insertText = function(str, position)
|
|
{
|
|
var buffer = exports.buffer();
|
|
exports.replaceLine(buffer.substr(0, position) + str + buffer.substr(position), position + str.length);
|
|
}
|
|
|
|
|
|
/**
|
|
* Takes a chunk of text out of the current line
|
|
*/
|
|
|
|
exports.spliceLine = function(position, length, newCursor)
|
|
{
|
|
|
|
var buffer = exports.buffer();
|
|
exports.replaceLine(buffer.substr(0, position) + buffer.substr(position + length), newCursor);
|
|
}
|
|
|
|
var _cursorPosition = 0;
|
|
|
|
|
|
/**
|
|
*/
|
|
|
|
exports.cursor = function(position)
|
|
{
|
|
if(!arguments.length) return _cursorPosition;
|
|
|
|
|
|
process.stdout.cursorTo(position);
|
|
|
|
return _cursorPosition = position;
|
|
}
|
|
|
|
|
|
|
|
function stringRep(key)
|
|
{
|
|
var chain = '';
|
|
|
|
for(var prop in key)
|
|
{
|
|
if(!key[prop]) continue;
|
|
|
|
if(key[prop] == true)
|
|
{
|
|
chain = prop+'-'+chain;
|
|
}
|
|
else
|
|
{
|
|
chain += key.name;
|
|
}
|
|
}
|
|
|
|
return chain;
|
|
}
|
|
|
|
exports.write = function(string)
|
|
{
|
|
process.stdout.write(string);
|
|
}
|
|
|
|
exports.newLine = function(buffer)
|
|
{
|
|
if(buffer) exports.write(buffer);
|
|
exports.write('\n');
|
|
exports.buffer('');
|
|
}
|
|
|
|
exports.open = function(ops)
|
|
{
|
|
if(ops)
|
|
{
|
|
if(ops.prefix) exports.inputPrefix(ops.prefix);
|
|
if(ops.delimiter) exports.delimiter(ops.delimiter);
|
|
}
|
|
|
|
if(exports.opened) return;
|
|
exports.opened = true;
|
|
|
|
|
|
stdin = process.openStdin();
|
|
stdin.setEncoding('utf8');
|
|
tty.setRawMode(true);
|
|
|
|
|
|
|
|
stdin.on('keypress', function(c, key)
|
|
{
|
|
|
|
//integer?
|
|
if(!key) key = { name: c.toString() }
|
|
|
|
|
|
|
|
|
|
var chain = stringRep(key),
|
|
emitSuccess = exports.emit(chain);
|
|
|
|
|
|
//not a handled item to boot? Probably enter, delete, left, right, up, etc. Append it.
|
|
if(!emitSuccess && c)
|
|
{
|
|
if(!_buffer.length)
|
|
{
|
|
exports.insertText(exports.inputPrefix(), _cursorPosition);
|
|
}
|
|
exports.insertText(c, _cursorPosition);
|
|
//exports.insertText(c, Math.max(_cursorPosition, exports.inputPrefix().length));
|
|
}
|
|
|
|
|
|
//new line? reset
|
|
if(key && key.name == 'enter')
|
|
{
|
|
//exports.replaceLine(exports.buffer().magenta);
|
|
process.stdout.write('\n');
|
|
_buffer = '';
|
|
_cursorPosition = 0;
|
|
//exports.insertText(exports.inputPrefix(), _cursorPosition);
|
|
//exports.cursor(0);
|
|
}
|
|
|
|
|
|
//for custom handlers: password, confirm, etc.
|
|
exports.emit('keypress', { char: c, key: key });
|
|
|
|
//character code?
|
|
if(key.name.length == 1)
|
|
{
|
|
exports.emit('charpress', c);
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
|
|
exports.parse = function(args)
|
|
{
|
|
var self = this;
|
|
|
|
args.forEach(function(arg)
|
|
{
|
|
var argParts = arg.split(':');
|
|
|
|
for(var i = argParts.length; i--;)
|
|
{
|
|
argParts[i] = encodeURIComponent(argParts[i]);
|
|
}
|
|
self.emit(argParts.join('/'));
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fs.readdirSync( __dirname + '/modules').forEach(function(module)
|
|
{
|
|
|
|
require( __dirname + '/modules/'+module).plugin(exports);
|
|
}); |