* Start work on pausable ANSI display/etc.
This commit is contained in:
parent
3f92a7949d
commit
5a00d219f8
|
@ -13,6 +13,11 @@ exports.ANSIEscapeParser = ANSIEscapeParser;
|
|||
var CR = 0x0d;
|
||||
var LF = 0x0a;
|
||||
|
||||
//
|
||||
// Resources, Specs, etc.
|
||||
//
|
||||
// * https://github.com/M-griffin/EtherTerm/blob/master/ansiParser.cpp
|
||||
|
||||
function ANSIEscapeParser(options) {
|
||||
var self = this;
|
||||
|
||||
|
@ -23,6 +28,10 @@ function ANSIEscapeParser(options) {
|
|||
this.scrollBack = 0;
|
||||
this.graphicRendition = {};
|
||||
|
||||
this.parseState = {
|
||||
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
|
||||
};
|
||||
|
||||
options = miscUtil.valueWithDefault(options, {
|
||||
mciReplaceChar : '',
|
||||
termHeight : 25,
|
||||
|
@ -187,6 +196,60 @@ function ANSIEscapeParser(options) {
|
|||
}
|
||||
}
|
||||
|
||||
self.reset = function(buffer) {
|
||||
self.parseState = {
|
||||
// ignore anything past EOF marker, if any
|
||||
buffer : buffer.split(String.fromCharCode(0x1a), 1)[0],
|
||||
re : /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g,
|
||||
stop : false,
|
||||
};
|
||||
};
|
||||
|
||||
self.stop = function() {
|
||||
self.parseState.stop = true;
|
||||
};
|
||||
|
||||
self.parse = function() {
|
||||
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
|
||||
var pos;
|
||||
var match;
|
||||
var opCode;
|
||||
var args;
|
||||
var re = self.parseState.re;
|
||||
var buffer = self.parseState.buffer;
|
||||
|
||||
self.parseState.stop = false;
|
||||
|
||||
do {
|
||||
if(self.parseState.stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = re.lastIndex;
|
||||
match = re.exec(buffer);
|
||||
|
||||
if(null !== match) {
|
||||
if(match.index > pos) {
|
||||
parseMCI(buffer.slice(pos, match.index));
|
||||
}
|
||||
|
||||
opCode = match[2];
|
||||
args = getArgArray(match[1].split(';'));
|
||||
|
||||
escape(opCode, args);
|
||||
|
||||
self.emit('chunk', match[0]);
|
||||
}
|
||||
} while(0 !== re.lastIndex);
|
||||
|
||||
if(pos < buffer.length) {
|
||||
parseMCI(buffer.slice(pos));
|
||||
}
|
||||
|
||||
self.emit('complete');
|
||||
};
|
||||
|
||||
/*
|
||||
self.parse = function(buffer, savedRe) {
|
||||
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
|
||||
// :TODO: move this to "constants" section @ top
|
||||
|
@ -216,6 +279,8 @@ function ANSIEscapeParser(options) {
|
|||
self.emit('chunk', match[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} while(0 !== re.lastIndex);
|
||||
|
||||
if(pos < buffer.length) {
|
||||
|
@ -224,6 +289,7 @@ function ANSIEscapeParser(options) {
|
|||
|
||||
self.emit('complete');
|
||||
};
|
||||
*/
|
||||
|
||||
function escape(opCode, args) {
|
||||
var arg;
|
||||
|
|
36
core/art.js
36
core/art.js
|
@ -382,17 +382,17 @@ function defaultEofFromExtension(ext) {
|
|||
|
||||
// :TODO: display({ art : art, client : client, ...}, cb)
|
||||
function display(options, cb) {
|
||||
assert(
|
||||
'undefined' !== typeof options &&
|
||||
'undefined' !== typeof options.client &&
|
||||
'undefined' !== typeof options.art,
|
||||
'Missing required options');
|
||||
assert(_.isObject(options));
|
||||
assert(_.isObject(options.client));
|
||||
assert(!_.isUndefined(options.art));
|
||||
|
||||
if(0 === options.art.length) {
|
||||
cb(new Error('Empty art'));
|
||||
return;
|
||||
}
|
||||
|
||||
// pause = none/off | end | termHeight | [ "key1", "key2", ... ]
|
||||
|
||||
var cancelKeys = miscUtil.valueWithDefault(options.cancelKeys, []);
|
||||
var pauseKeys = miscUtil.valueWithDefault(options.pauseKeys, []);
|
||||
var pauseAtTermHeight = miscUtil.valueWithDefault(options.pauseAtTermHeight, false);
|
||||
|
@ -426,7 +426,7 @@ function display(options, cb) {
|
|||
|
||||
var generatedId = 100;
|
||||
|
||||
var onCPR = function(pos) {
|
||||
var cprListener = function(pos) {
|
||||
if(mciPosQueue.length > 0) {
|
||||
var forMapItem = mciPosQueue.shift();
|
||||
mciMap[forMapItem].position = pos;
|
||||
|
@ -438,7 +438,7 @@ function display(options, cb) {
|
|||
};
|
||||
|
||||
function completed() {
|
||||
options.client.removeListener('cursor position report', onCPR);
|
||||
options.client.removeListener('cursor position report', cprListener);
|
||||
parser.removeAllListeners(); // :TODO: Necessary???
|
||||
|
||||
if(iceColors) {
|
||||
|
@ -448,7 +448,22 @@ function display(options, cb) {
|
|||
cb(null, mciMap);
|
||||
}
|
||||
|
||||
options.client.on('cursor position report', onCPR);
|
||||
options.client.on('cursor position report', cprListener);
|
||||
|
||||
//options.pause = 'termHeight'; // :TODO: remove!!
|
||||
var nextTermHeight = options.client.termHeight;
|
||||
|
||||
parser.on('row update', function rowUpdate(row) {
|
||||
if(row >= nextTermHeight) {
|
||||
if('termHeight' === options.pause) {
|
||||
options.client.waitForKeyPress(function kp(k) {
|
||||
parser.parse();
|
||||
});
|
||||
parser.stop();
|
||||
}
|
||||
nextTermHeight *= 2;
|
||||
}
|
||||
});
|
||||
|
||||
parser.on('mci', function mciEncountered(mciInfo) {
|
||||
|
||||
|
@ -463,6 +478,7 @@ function display(options, cb) {
|
|||
*/
|
||||
|
||||
// :TODO: ensure generatedId's do not conflict with any |id|
|
||||
// :TODO: Bug here - should only generate & increment ID's for the initial entry, not the "focus" version
|
||||
var id = !_.isNumber(mciInfo.id) ? generatedId++ : mciInfo.id;
|
||||
var mapKey = mciInfo.mci + id;
|
||||
var mapEntry = mciMap[mapKey];
|
||||
|
@ -522,5 +538,7 @@ function display(options, cb) {
|
|||
options.client.term.write(ansi.blinkToBrightIntensity());
|
||||
}
|
||||
|
||||
parser.parse(options.art);
|
||||
parser.reset(options.art);
|
||||
parser.parse();
|
||||
//parser.parse(options.art);
|
||||
}
|
|
@ -217,7 +217,7 @@
|
|||
}
|
||||
},
|
||||
"demoMain" : {
|
||||
"art" : "demo_main",
|
||||
"art" : "demo_selection_vm.ans",
|
||||
"options" : { "cls" : true },
|
||||
"form" : {
|
||||
"0" : {
|
||||
|
@ -227,6 +227,7 @@
|
|||
"items" : [
|
||||
"Single Line Text Editing Views",
|
||||
"Spinner & Toggle Views",
|
||||
"Art Display",
|
||||
"Other"
|
||||
],
|
||||
// :TODO: justify not working??
|
||||
|
@ -242,6 +243,10 @@
|
|||
{
|
||||
"value" : { "1" : 1 },
|
||||
"action" : "@menu:demoSpinAndToggleView"
|
||||
},
|
||||
{
|
||||
"value" : { "1" : 2 },
|
||||
"action" : "@menu:demoArtDisplay"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -327,7 +332,41 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"demoArtDisplay" : {
|
||||
"art" : "demo_selection_vm.ans",
|
||||
"options" : { "cls" : true },
|
||||
"form" : {
|
||||
"0" : {
|
||||
"VM1" : {
|
||||
"mci" : {
|
||||
"VM1" : {
|
||||
"items" : [
|
||||
"Defaults - DOS ANSI",
|
||||
"Defaults - Amiga",
|
||||
"Pause at Term Height"
|
||||
],
|
||||
// :TODO: justify not working??
|
||||
"focusTextStyle" : "small i"
|
||||
}
|
||||
},
|
||||
"submit" : {
|
||||
"*" : [
|
||||
{
|
||||
"value" : { "1" : 0 },
|
||||
"action" : "@menu:demoDefaultsDosAnsi"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"demoDefaultsDosAnsi" : {
|
||||
"art" : "bw_bc.ans",
|
||||
"options" : { "cls" : true }
|
||||
}
|
||||
|
||||
/*
|
||||
:TODO: conceptual simplified menus -- actions/etc. without forms
|
||||
|
||||
|
|
Loading…
Reference in New Issue