* Moved menus -> menus.json::menus
* Move prompts -> prompts.json::prompts * Default to 80x25 if NAWS/ENV/CPR term size negotiations fail. Seeing this with Netrunner. May need more work.
This commit is contained in:
parent
9ac2e9af6e
commit
0d9add70bd
|
@ -454,6 +454,7 @@ function display(options, cb) {
|
||||||
var nextPauseTermHeight = options.client.term.termHeight;
|
var nextPauseTermHeight = options.client.term.termHeight;
|
||||||
var continous = false;
|
var continous = false;
|
||||||
|
|
||||||
|
/*
|
||||||
parser.on('row update', function rowUpdate(row) {
|
parser.on('row update', function rowUpdate(row) {
|
||||||
if(row >= nextPauseTermHeight) {
|
if(row >= nextPauseTermHeight) {
|
||||||
if(!continous && 'termHeight' === options.pause) {
|
if(!continous && 'termHeight' === options.pause) {
|
||||||
|
@ -469,6 +470,7 @@ function display(options, cb) {
|
||||||
nextPauseTermHeight += options.client.term.termHeight;
|
nextPauseTermHeight += options.client.term.termHeight;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
parser.on('mci', function mciEncountered(mciInfo) {
|
parser.on('mci', function mciEncountered(mciInfo) {
|
||||||
|
|
||||||
|
|
|
@ -14,33 +14,56 @@ var util = require('util');
|
||||||
|
|
||||||
exports.connectEntry = connectEntry;
|
exports.connectEntry = connectEntry;
|
||||||
|
|
||||||
function ansiQueryTermSizeIfNeeded(client) {
|
function ansiQueryTermSizeIfNeeded(client, cb) {
|
||||||
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
|
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
|
||||||
|
cb(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var onCPR = function(pos) {
|
var cprListener = function(pos) {
|
||||||
//
|
//
|
||||||
// If we've already found out, disregard
|
// If we've already found out, disregard
|
||||||
//
|
//
|
||||||
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
|
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
|
||||||
|
cb(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(2 === pos.length);
|
assert(2 === pos.length);
|
||||||
client.term.termHeight = pos[0];
|
var h = pos[0];
|
||||||
client.term.termWidth = pos[1];
|
var w = pos[1];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Netrunner for example gives us 1x1 here. Not really useful. Ignore
|
||||||
|
// values that seem obviously bad.
|
||||||
|
//
|
||||||
|
if(h < 10 || w < 10) {
|
||||||
|
Log.warn(
|
||||||
|
{ height : h, width : w },
|
||||||
|
'Ignoring ANSI CPR screen size query response due to very small values');
|
||||||
|
cb(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.term.termHeight = h;
|
||||||
|
client.term.termWidth = w;
|
||||||
|
|
||||||
Log.debug(
|
Log.debug(
|
||||||
{ termWidth : client.term.termWidth, termHeight : client.term.termHeight, updateSource : 'ANSI CPR' },
|
{
|
||||||
'Window size updated');
|
termWidth : client.term.termWidth,
|
||||||
|
termHeight : client.term.termHeight,
|
||||||
|
source : 'ANSI CPR'
|
||||||
|
},
|
||||||
|
'Window size updated'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
client.once('cursor position report', onCPR);
|
client.once('cursor position report', cprListener);
|
||||||
|
|
||||||
// give up after 2s
|
// give up after 2s
|
||||||
setTimeout(function onTimeout() {
|
setTimeout(function onTimeout() {
|
||||||
client.removeListener('cursor position report', onCPR);
|
client.removeListener('cursor position report', cprListener);
|
||||||
|
cb(true);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
client.term.write(ansi.queryScreenSize());
|
client.term.write(ansi.queryScreenSize());
|
||||||
|
@ -53,10 +76,10 @@ function prepareTerminal(term) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayBanner(term) {
|
function displayBanner(term) {
|
||||||
// :TODO: add URL to banner
|
// :TODO: add URL(s) to banner
|
||||||
term.write(ansi.fromPipeCode(util.format('' +
|
term.write(ansi.fromPipeCode(util.format('' +
|
||||||
'|33Conected to |32EN|33|01i|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
|
'|33Conected to |32EN|33|01i|00|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
|
||||||
'|00|33Copyright (c) 2014 Bryan Ashby\n' +
|
'|00|33Copyright (c) 2014-2015 Bryan Ashby\n' +
|
||||||
'|00', packageJson.version)));
|
'|00', packageJson.version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +90,19 @@ function connectEntry(client) {
|
||||||
// If we don't yet know the client term width/height,
|
// If we don't yet know the client term width/height,
|
||||||
// try with a nonstandard ANSI DSR type request.
|
// try with a nonstandard ANSI DSR type request.
|
||||||
//
|
//
|
||||||
ansiQueryTermSizeIfNeeded(client);
|
ansiQueryTermSizeIfNeeded(client, function ansiCprResult(result) {
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
//
|
||||||
|
// We still don't have something good for term height/width.
|
||||||
|
// Default to DOS size 80x25.
|
||||||
|
//
|
||||||
|
// :TODO: Netrunner is currenting hitting this and it feels wrong. Why is NAWS/ENV/CPR all failing???
|
||||||
|
Log.warn('Failed to negotiate term size; Defaulting to 80x25!');
|
||||||
|
|
||||||
|
term.termHeight = 25;
|
||||||
|
term.termWidth = 80;
|
||||||
|
}
|
||||||
|
|
||||||
prepareTerminal(term);
|
prepareTerminal(term);
|
||||||
|
|
||||||
|
@ -79,5 +114,6 @@ function connectEntry(client) {
|
||||||
setTimeout(function onTimeout() {
|
setTimeout(function onTimeout() {
|
||||||
client.gotoMenuModule( { name : Config.firstMenu });
|
client.gotoMenuModule( { name : Config.firstMenu });
|
||||||
}, 500);
|
}, 500);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ function MaskEditTextView(options) {
|
||||||
this.maskPattern = options.maskPattern || '';
|
this.maskPattern = options.maskPattern || '';
|
||||||
|
|
||||||
this.clientBackspace = function() {
|
this.clientBackspace = function() {
|
||||||
var fillCharSGR = this.getStyleSGR(2) || this.getSGR();
|
var fillCharSGR = this.getStyleSGR(3) || this.getSGR();
|
||||||
this.client.term.write('\b' + fillCharSGR + this.fillChar + '\b' + this.getFocusSGR());
|
this.client.term.write('\b' + fillCharSGR + this.fillChar + '\b' + this.getFocusSGR());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,10 +55,11 @@ function MaskEditTextView(options) {
|
||||||
self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]);
|
self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]);
|
||||||
t++;
|
t++;
|
||||||
} else {
|
} else {
|
||||||
self.client.term.write((self.getStyleSGR(2) || '') + self.fillChar);
|
self.client.term.write((self.getStyleSGR(3) || '') + self.fillChar);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.client.term.write((self.getStyleSGR(1) || '') + self.maskPattern[i]);
|
var styleSgr = this.hasFocus ? (self.getStyleSGR(2) || '') : (self.getStyleSGR(1) || '');
|
||||||
|
self.client.term.write(styleSgr + self.maskPattern[i]);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +80,10 @@ function MaskEditTextView(options) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getCursorEditYPosition = function() {
|
||||||
|
return this.position.y + this.patternArrayPos;
|
||||||
|
};
|
||||||
|
|
||||||
this.buildPattern();
|
this.buildPattern();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +97,21 @@ MaskEditTextView.maskPatternCharacterRegEx = {
|
||||||
'&' : /[\w\d\s]/, // Any "printable" 32-126, 128-255
|
'&' : /[\w\d\s]/, // Any "printable" 32-126, 128-255
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MaskEditTextView.prototype.setFocus = function(focused) {
|
||||||
|
// :TODO: can't call super unless we want wasted redraw stuff. This seems sloppy & should probably be looked into
|
||||||
|
//MaskEditTextView.super_.prototype.setFocus.call(this, focused);
|
||||||
|
assert(this.acceptsFocus, 'View does not accept focus');
|
||||||
|
|
||||||
|
this.hasFocus = focused;
|
||||||
|
this.restoreCursor();
|
||||||
|
|
||||||
|
this.redraw();
|
||||||
|
|
||||||
|
// position & SGR for cursor
|
||||||
|
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition()));
|
||||||
|
this.client.term.write(this.getFocusSGR());
|
||||||
|
};
|
||||||
|
|
||||||
MaskEditTextView.prototype.setMaskPattern = function(pattern) {
|
MaskEditTextView.prototype.setMaskPattern = function(pattern) {
|
||||||
this.dimens.width = pattern.length;
|
this.dimens.width = pattern.length;
|
||||||
|
|
||||||
|
@ -123,9 +143,9 @@ MaskEditTextView.prototype.onKeyPress = function(key, isSpecial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.redraw();
|
this.redraw();
|
||||||
|
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MaskEditTextView.super_.prototype.onKeyPress.call(this, key, isSpecial);
|
MaskEditTextView.super_.prototype.onKeyPress.call(this, key, isSpecial);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,21 +160,14 @@ MaskEditTextView.prototype.onSpecialKeyPress = function(keyName) {
|
||||||
this.text = this.text.substr(0, this.text.length - 1);
|
this.text = this.text.substr(0, this.text.length - 1);
|
||||||
this.clientBackspace();
|
this.clientBackspace();
|
||||||
} else {
|
} else {
|
||||||
var offset = -1;
|
|
||||||
while(this.patternArrayPos > 0) {
|
while(this.patternArrayPos > 0) {
|
||||||
if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
|
if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
|
||||||
this.text = this.text.substr(0, this.text.length - 1);
|
this.text = this.text.substr(0, this.text.length - 1);
|
||||||
this.client.term.write(ansi.goto(this.position.x, this.position.y + (this.text.length - offset)));
|
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition() + 1));
|
||||||
// :TODO: use better ANSI Position code to just go back
|
|
||||||
// this.client.term.write(ansi.goto(this.position.x, yPosition));
|
|
||||||
|
|
||||||
this.clientBackspace();
|
this.clientBackspace();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
console.log('skip past ' + this.patternArray[this.patternArrayPos])
|
|
||||||
//this.client.term.write(ansi.back() + ansi.back());
|
|
||||||
this.patternArrayPos--;
|
this.patternArrayPos--;
|
||||||
offset++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ function getMenuConfig(name, cb) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function locateMenuConfig(menuJson, callback) {
|
function locateMenuConfig(menuJson, callback) {
|
||||||
if(_.isObject(menuJson[name])) {
|
if(_.has(menuJson, [ 'menus', name ])) {
|
||||||
menuConfig = menuJson[name];
|
menuConfig = menuJson.menus[name];
|
||||||
callback(null);
|
callback(null);
|
||||||
} else {
|
} else {
|
||||||
callback(new Error('No menu entry for \'' + name + '\''));
|
callback(new Error('No menu entry for \'' + name + '\''));
|
||||||
|
@ -66,7 +66,7 @@ function getMenuConfig(name, cb) {
|
||||||
},
|
},
|
||||||
function locatePromptConfig(promptJson, callback) {
|
function locatePromptConfig(promptJson, callback) {
|
||||||
if(promptJson) {
|
if(promptJson) {
|
||||||
if(_.isObject(promptJson[menuConfig.prompt])) {
|
if(_.has(promptJson, [ 'prompts', menuConfig.prompt ])) {
|
||||||
menuConfig.promptConfig = promptJson[menuConfig.prompt];
|
menuConfig.promptConfig = promptJson[menuConfig.prompt];
|
||||||
} else {
|
} else {
|
||||||
callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\''));
|
callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\''));
|
||||||
|
|
|
@ -571,10 +571,10 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
|
||||||
self.setTermType(evt.envVars[name]);
|
self.setTermType(evt.envVars[name]);
|
||||||
} else if('COLUMNS' === name && 0 === self.term.termWidth) {
|
} else if('COLUMNS' === name && 0 === self.term.termWidth) {
|
||||||
self.term.termWidth = parseInt(evt.envVars[name]);
|
self.term.termWidth = parseInt(evt.envVars[name]);
|
||||||
Log.debug({ termWidth : self.term.termWidth, updateSource : 'NEW-ENVIRON'}, 'Window width updated');
|
Log.debug({ termWidth : self.term.termWidth, source : 'NEW-ENVIRON'}, 'Window width updated');
|
||||||
} else if('ROWS' === name && 0 === self.term.termHeight) {
|
} else if('ROWS' === name && 0 === self.term.termHeight) {
|
||||||
self.term.termHeight = parseInt(evt.envVars[name]);
|
self.term.termHeight = parseInt(evt.envVars[name]);
|
||||||
Log.debug({ termHeight : self.term.termHeight, updateSource : 'NEW-ENVIRON'}, 'Window height updated');
|
Log.debug({ termHeight : self.term.termHeight, source : 'NEW-ENVIRON'}, 'Window height updated');
|
||||||
} else {
|
} else {
|
||||||
if(name in self.term.env) {
|
if(name in self.term.env) {
|
||||||
assert(evt.type === SB_COMMANDS.INFO);
|
assert(evt.type === SB_COMMANDS.INFO);
|
||||||
|
@ -604,7 +604,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
|
||||||
self.term.env['ROWS'] = evt.height;
|
self.term.env['ROWS'] = evt.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.debug({ termWidth : evt.width , termHeight : evt.height, updateSource : 'NAWS' }, 'Window size updated');
|
Log.debug({ termWidth : evt.width , termHeight : evt.height, source : 'NAWS' }, 'Window size updated');
|
||||||
} else {
|
} else {
|
||||||
console.log('unhandled SB: ' + JSON.stringify(evt));
|
console.log('unhandled SB: ' + JSON.stringify(evt));
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,16 +194,18 @@ function ViewController(options) {
|
||||||
|
|
||||||
setViewProp('maxLength');
|
setViewProp('maxLength');
|
||||||
|
|
||||||
|
//
|
||||||
['styleSGR1', 'styleSGR2'].forEach(function styleSgr(style) {
|
// styleSGRx: 1..25
|
||||||
setViewProp(style, function(v) {
|
//
|
||||||
|
for(var i = 1; i <= 25; i++) {
|
||||||
|
setViewProp('styleSGR' + i, function(v) {
|
||||||
if(_.isObject(v)) {
|
if(_.isObject(v)) {
|
||||||
view[style] = ansi.getSGRFromGraphicRendition(v, true);
|
view['styleSGR' + i] = ansi.getSGRFromGraphicRendition(v, true);
|
||||||
} else if(_.isString(v)) {
|
} else if(_.isString(v)) {
|
||||||
view[style] = ansi.fromPipeCode(v);
|
view['styleSGR' + i] = ansi.fromPipeCode(v);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
setViewProp('fillChar', function(v) {
|
setViewProp('fillChar', function(v) {
|
||||||
if(_.isNumber(v)) {
|
if(_.isNumber(v)) {
|
||||||
|
|
|
@ -33,8 +33,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
"connected" : {
|
"menus" : {
|
||||||
"art" : "CONNECT",
|
"art" : "CONNECT",
|
||||||
|
"connected" : {
|
||||||
"next" : "matrix",
|
"next" : "matrix",
|
||||||
"options" : {
|
"options" : {
|
||||||
"cls" : true,
|
"cls" : true,
|
||||||
|
@ -335,7 +336,8 @@
|
||||||
"mci" : {
|
"mci" : {
|
||||||
"ME1" : {
|
"ME1" : {
|
||||||
"maskPattern" : "##/##/##",
|
"maskPattern" : "##/##/##",
|
||||||
"styleSGR1" : "|00|30|01"
|
"styleSGR1" : "|00|30|01",
|
||||||
|
"styleSGR2" : "|00|45|01"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,3 +426,4 @@
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"userCredentials" : {
|
"prompts" : {
|
||||||
"art" : "usercred",
|
"art" : "usercred",
|
||||||
|
"userCredentials" : {
|
||||||
"mci" : {
|
"mci" : {
|
||||||
"ET1" : {
|
"ET1" : {
|
||||||
"argName" : "username",
|
"argName" : "username",
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
... better, a special prompt
|
... better, a special prompt
|
||||||
|
|
||||||
GetKeyView
|
GetKeyView
|
||||||
* showKey : false
|
* echoKey : false
|
||||||
|
|
||||||
*/
|
*/
|
||||||
},
|
},
|
||||||
|
@ -67,5 +68,5 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue