* 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:
Bryan Ashby 2015-05-15 23:02:58 -06:00
parent 9ac2e9af6e
commit 0d9add70bd
8 changed files with 511 additions and 454 deletions

View File

@ -454,6 +454,7 @@ function display(options, cb) {
var nextPauseTermHeight = options.client.term.termHeight;
var continous = false;
/*
parser.on('row update', function rowUpdate(row) {
if(row >= nextPauseTermHeight) {
if(!continous && 'termHeight' === options.pause) {
@ -469,6 +470,7 @@ function display(options, cb) {
nextPauseTermHeight += options.client.term.termHeight;
}
});
*/
parser.on('mci', function mciEncountered(mciInfo) {

View File

@ -14,33 +14,56 @@ var util = require('util');
exports.connectEntry = connectEntry;
function ansiQueryTermSizeIfNeeded(client) {
function ansiQueryTermSizeIfNeeded(client, cb) {
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
cb(true);
return;
}
var onCPR = function(pos) {
var cprListener = function(pos) {
//
// If we've already found out, disregard
//
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
cb(true);
return;
}
assert(2 === pos.length);
client.term.termHeight = pos[0];
client.term.termWidth = pos[1];
var h = pos[0];
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(
{ 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
setTimeout(function onTimeout() {
client.removeListener('cursor position report', onCPR);
client.removeListener('cursor position report', cprListener);
cb(true);
}, 2000);
client.term.write(ansi.queryScreenSize());
@ -53,10 +76,10 @@ function prepareTerminal(term) {
}
function displayBanner(term) {
// :TODO: add URL to banner
// :TODO: add URL(s) to banner
term.write(ansi.fromPipeCode(util.format('' +
'|33Conected to |32EN|33|01i|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
'|00|33Copyright (c) 2014 Bryan Ashby\n' +
'|33Conected to |32EN|33|01i|00|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
'|00|33Copyright (c) 2014-2015 Bryan Ashby\n' +
'|00', packageJson.version)));
}
@ -67,7 +90,19 @@ function connectEntry(client) {
// If we don't yet know the client term width/height,
// 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);
@ -79,5 +114,6 @@ function connectEntry(client) {
setTimeout(function onTimeout() {
client.gotoMenuModule( { name : Config.firstMenu });
}, 500);
});
}

View File

@ -37,7 +37,7 @@ function MaskEditTextView(options) {
this.maskPattern = options.maskPattern || '';
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());
};
@ -55,10 +55,11 @@ function MaskEditTextView(options) {
self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]);
t++;
} else {
self.client.term.write((self.getStyleSGR(2) || '') + self.fillChar);
self.client.term.write((self.getStyleSGR(3) || '') + self.fillChar);
}
} 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++;
}
@ -79,6 +80,10 @@ function MaskEditTextView(options) {
}
};
this.getCursorEditYPosition = function() {
return this.position.y + this.patternArrayPos;
};
this.buildPattern();
}
@ -92,6 +97,21 @@ MaskEditTextView.maskPatternCharacterRegEx = {
'&' : /[\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) {
this.dimens.width = pattern.length;
@ -123,9 +143,9 @@ MaskEditTextView.prototype.onKeyPress = function(key, isSpecial) {
}
this.redraw();
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition()));
}
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.clientBackspace();
} else {
var offset = -1;
while(this.patternArrayPos > 0) {
if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
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)));
// :TODO: use better ANSI Position code to just go back
// this.client.term.write(ansi.goto(this.position.x, yPosition));
this.client.term.write(ansi.goto(this.position.x, this.getCursorEditYPosition() + 1));
this.clientBackspace();
break;
}
console.log('skip past ' + this.patternArray[this.patternArrayPos])
//this.client.term.write(ansi.back() + ansi.back());
this.patternArrayPos--;
offset++;
}
}
}

View File

@ -48,8 +48,8 @@ function getMenuConfig(name, cb) {
});
},
function locateMenuConfig(menuJson, callback) {
if(_.isObject(menuJson[name])) {
menuConfig = menuJson[name];
if(_.has(menuJson, [ 'menus', name ])) {
menuConfig = menuJson.menus[name];
callback(null);
} else {
callback(new Error('No menu entry for \'' + name + '\''));
@ -66,7 +66,7 @@ function getMenuConfig(name, cb) {
},
function locatePromptConfig(promptJson, callback) {
if(promptJson) {
if(_.isObject(promptJson[menuConfig.prompt])) {
if(_.has(promptJson, [ 'prompts', menuConfig.prompt ])) {
menuConfig.promptConfig = promptJson[menuConfig.prompt];
} else {
callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\''));

View File

@ -538,7 +538,7 @@ TelnetClient.prototype.setTermType = function(ttype) {
this.term.env['TERM'] = ttype;
this.term.termType = ttype;
Log.debug({ termType : ttype }, 'Set terminal type');
Log.debug( { termType : ttype }, 'Set terminal type');
}
TelnetClient.prototype.handleSbCommand = function(evt) {
@ -571,10 +571,10 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
self.setTermType(evt.envVars[name]);
} else if('COLUMNS' === name && 0 === self.term.termWidth) {
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) {
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 {
if(name in self.term.env) {
assert(evt.type === SB_COMMANDS.INFO);
@ -604,7 +604,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
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 {
console.log('unhandled SB: ' + JSON.stringify(evt));
}

View File

@ -194,16 +194,18 @@ function ViewController(options) {
setViewProp('maxLength');
['styleSGR1', 'styleSGR2'].forEach(function styleSgr(style) {
setViewProp(style, function(v) {
//
// styleSGRx: 1..25
//
for(var i = 1; i <= 25; i++) {
setViewProp('styleSGR' + i, function(v) {
if(_.isObject(v)) {
view[style] = ansi.getSGRFromGraphicRendition(v, true);
view['styleSGR' + i] = ansi.getSGRFromGraphicRendition(v, true);
} else if(_.isString(v)) {
view[style] = ansi.fromPipeCode(v);
view['styleSGR' + i] = ansi.fromPipeCode(v);
}
});
});
}
setViewProp('fillChar', function(v) {
if(_.isNumber(v)) {

View File

@ -33,8 +33,9 @@
}
}
*/
"connected" : {
"menus" : {
"art" : "CONNECT",
"connected" : {
"next" : "matrix",
"options" : {
"cls" : true,
@ -335,7 +336,8 @@
"mci" : {
"ME1" : {
"maskPattern" : "##/##/##",
"styleSGR1" : "|00|30|01"
"styleSGR1" : "|00|30|01",
"styleSGR2" : "|00|45|01"
}
}
}
@ -423,4 +425,5 @@
}
}
*/
}
}

View File

@ -1,6 +1,7 @@
{
"userCredentials" : {
"prompts" : {
"art" : "usercred",
"userCredentials" : {
"mci" : {
"ET1" : {
"argName" : "username",
@ -33,7 +34,7 @@
... better, a special prompt
GetKeyView
* showKey : false
* echoKey : false
*/
},
@ -67,5 +68,5 @@
}
}
*/
}
}