Add PCB/WildCat!, WWIV, Renegade, etc. color code support to file descriptions
This commit is contained in:
parent
30d76d173e
commit
6d31589c8b
|
@ -11,11 +11,13 @@ exports.enigmaToAnsi = enigmaToAnsi;
|
||||||
exports.stripPipeCodes = exports.stripEnigmaCodes = stripEnigmaCodes;
|
exports.stripPipeCodes = exports.stripEnigmaCodes = stripEnigmaCodes;
|
||||||
exports.pipeStrLen = exports.enigmaStrLen = enigmaStrLen;
|
exports.pipeStrLen = exports.enigmaStrLen = enigmaStrLen;
|
||||||
exports.pipeToAnsi = exports.renegadeToAnsi = renegadeToAnsi;
|
exports.pipeToAnsi = exports.renegadeToAnsi = renegadeToAnsi;
|
||||||
|
exports.controlCodesToAnsi = controlCodesToAnsi;
|
||||||
|
|
||||||
// :TODO: Not really happy with the module name of "color_codes". Would like something better
|
// :TODO: Not really happy with the module name of "color_codes". Would like something better
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Also add:
|
// Also add:
|
||||||
// * fromCelerity(): |<case sensitive letter>
|
// * fromCelerity(): |<case sensitive letter>
|
||||||
// * fromPCBoard(): (@X<bg><fg>)
|
// * fromPCBoard(): (@X<bg><fg>)
|
||||||
|
@ -148,3 +150,159 @@ function renegadeToAnsi(s, client) {
|
||||||
|
|
||||||
return (0 === result.length ? s : result + s.substr(lastIndex));
|
return (0 === result.length ? s : result + s.substr(lastIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Converts various control codes popular in BBS packages
|
||||||
|
// to ANSI escape sequences. Additionaly supports ENiGMA style
|
||||||
|
// MCI codes.
|
||||||
|
//
|
||||||
|
// Supported control code formats:
|
||||||
|
// * Renegade : |##
|
||||||
|
// * PCBoard : @X## where the first number/char is FG color, and second is BG
|
||||||
|
// * WildCat! : @##@ the same as PCBoard without the X prefix, but with a @ suffix
|
||||||
|
// * WWIV : ^#
|
||||||
|
//
|
||||||
|
// TODO: Add Synchronet and Celerity format support
|
||||||
|
//
|
||||||
|
// Resources:
|
||||||
|
// * http://wiki.synchro.net/custom:colors
|
||||||
|
//
|
||||||
|
function controlCodesToAnsi(s, client) {
|
||||||
|
const RE = /(\|([A-Z0-9]{2})|\|)|(\@X([0-9A-F]{2}))|(\@([0-9A-F]{2})\@)|(\x03[0-9]|\x03)/g; // eslint-disable-line no-control-regex
|
||||||
|
|
||||||
|
let m;
|
||||||
|
let result = '';
|
||||||
|
let lastIndex = 0;
|
||||||
|
let v;
|
||||||
|
let fg;
|
||||||
|
let bg;
|
||||||
|
|
||||||
|
while((m = RE.exec(s))) {
|
||||||
|
switch(m[0].charAt(0)) {
|
||||||
|
case '|' :
|
||||||
|
// Renegade or ENiGMA MCI
|
||||||
|
v = parseInt(m[2], 10);
|
||||||
|
|
||||||
|
if(isNaN(v)) {
|
||||||
|
v = getPredefinedMCIValue(client, m[2]) || m[0]; // value itself or literal
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_.isString(v)) {
|
||||||
|
result += s.substr(lastIndex, m.index - lastIndex) + v;
|
||||||
|
} else {
|
||||||
|
v = ansi.sgr({
|
||||||
|
0 : [ 'reset', 'black' ],
|
||||||
|
1 : [ 'reset', 'blue' ],
|
||||||
|
2 : [ 'reset', 'green' ],
|
||||||
|
3 : [ 'reset', 'cyan' ],
|
||||||
|
4 : [ 'reset', 'red' ],
|
||||||
|
5 : [ 'reset', 'magenta' ],
|
||||||
|
6 : [ 'reset', 'yellow' ],
|
||||||
|
7 : [ 'reset', 'white' ],
|
||||||
|
|
||||||
|
8 : [ 'bold', 'black' ],
|
||||||
|
9 : [ 'bold', 'blue' ],
|
||||||
|
10 : [ 'bold', 'green' ],
|
||||||
|
11 : [ 'bold', 'cyan' ],
|
||||||
|
12 : [ 'bold', 'red' ],
|
||||||
|
13 : [ 'bold', 'magenta' ],
|
||||||
|
14 : [ 'bold', 'yellow' ],
|
||||||
|
15 : [ 'bold', 'white' ],
|
||||||
|
|
||||||
|
16 : [ 'blackBG' ],
|
||||||
|
17 : [ 'blueBG' ],
|
||||||
|
18 : [ 'greenBG' ],
|
||||||
|
19 : [ 'cyanBG' ],
|
||||||
|
20 : [ 'redBG' ],
|
||||||
|
21 : [ 'magentaBG' ],
|
||||||
|
22 : [ 'yellowBG' ],
|
||||||
|
23 : [ 'whiteBG' ],
|
||||||
|
}[v] || 'normal');
|
||||||
|
|
||||||
|
result += s.substr(lastIndex, m.index - lastIndex) + v;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '@' :
|
||||||
|
// PCBoard @X## or Wildcat! @##@
|
||||||
|
if('@' === m[0].substr(-1)) {
|
||||||
|
// Wildcat!
|
||||||
|
v = m[6];
|
||||||
|
} else {
|
||||||
|
v = m[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
fg = {
|
||||||
|
0 : [ 'reset', 'black' ],
|
||||||
|
1 : [ 'reset', 'blue' ],
|
||||||
|
2 : [ 'reset', 'green' ],
|
||||||
|
3 : [ 'reset', 'cyan' ],
|
||||||
|
4 : [ 'reset', 'red' ],
|
||||||
|
5 : [ 'reset', 'magenta' ],
|
||||||
|
6 : [ 'reset', 'yellow' ],
|
||||||
|
7 : [ 'reset', 'white' ],
|
||||||
|
|
||||||
|
8 : [ 'blink', 'black' ],
|
||||||
|
9 : [ 'blink', 'blue' ],
|
||||||
|
A : [ 'blink', 'green' ],
|
||||||
|
B : [ 'blink', 'cyan' ],
|
||||||
|
C : [ 'blink', 'red' ],
|
||||||
|
D : [ 'blink', 'magenta' ],
|
||||||
|
E : [ 'blink', 'yellow' ],
|
||||||
|
F : [ 'blink', 'white' ],
|
||||||
|
}[v.charAt(0)] || ['normal'];
|
||||||
|
|
||||||
|
bg = {
|
||||||
|
0 : [ 'blackBG' ],
|
||||||
|
1 : [ 'blueBG' ],
|
||||||
|
2 : [ 'greenBG' ],
|
||||||
|
3 : [ 'cyanBG' ],
|
||||||
|
4 : [ 'redBG' ],
|
||||||
|
5 : [ 'magentaBG' ],
|
||||||
|
6 : [ 'yellowBG' ],
|
||||||
|
7 : [ 'whiteBG' ],
|
||||||
|
|
||||||
|
8 : [ 'bold', 'blackBG' ],
|
||||||
|
9 : [ 'bold', 'blueBG' ],
|
||||||
|
A : [ 'bold', 'greenBG' ],
|
||||||
|
B : [ 'bold', 'cyanBG' ],
|
||||||
|
C : [ 'bold', 'redBG' ],
|
||||||
|
D : [ 'bold', 'magentaBG' ],
|
||||||
|
E : [ 'bold', 'yellowBG' ],
|
||||||
|
F : [ 'bold', 'whiteBG' ],
|
||||||
|
}[v.charAt(1)] || [ 'normal' ];
|
||||||
|
|
||||||
|
v = ansi.sgr(fg.concat(bg));
|
||||||
|
result += s.substr(lastIndex, m.index - lastIndex) + v;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\x03' :
|
||||||
|
v = parseInt(m[8], 10);
|
||||||
|
|
||||||
|
if(isNaN(v)) {
|
||||||
|
v += m[0];
|
||||||
|
} else {
|
||||||
|
v = ansi.sgr({
|
||||||
|
0 : [ 'reset', 'black' ],
|
||||||
|
1 : [ 'bold', 'cyan' ],
|
||||||
|
2 : [ 'bold', 'yellow' ],
|
||||||
|
3 : [ 'reset', 'magenta' ],
|
||||||
|
4 : [ 'bold', 'white', 'blueBG' ],
|
||||||
|
5 : [ 'reset', 'green' ],
|
||||||
|
6 : [ 'bold', 'blink', 'red' ],
|
||||||
|
7 : [ 'bold', 'blue' ],
|
||||||
|
8 : [ 'reset', 'blue' ],
|
||||||
|
9 : [ 'reset', 'cyan' ],
|
||||||
|
}[v] || 'normal');
|
||||||
|
}
|
||||||
|
|
||||||
|
result += s.substr(lastIndex, m.index - lastIndex) + v;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = RE.lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0 === result.length ? s : result + s.substr(lastIndex));
|
||||||
|
}
|
|
@ -2,22 +2,23 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// ENiGMA½
|
// ENiGMA½
|
||||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||||
const ViewController = require('../core/view_controller.js').ViewController;
|
const ViewController = require('../core/view_controller.js').ViewController;
|
||||||
const ansi = require('../core/ansi_term.js');
|
const ansi = require('../core/ansi_term.js');
|
||||||
const theme = require('../core/theme.js');
|
const theme = require('../core/theme.js');
|
||||||
const FileEntry = require('../core/file_entry.js');
|
const FileEntry = require('../core/file_entry.js');
|
||||||
const stringFormat = require('../core/string_format.js');
|
const stringFormat = require('../core/string_format.js');
|
||||||
const FileArea = require('../core/file_base_area.js');
|
const FileArea = require('../core/file_base_area.js');
|
||||||
const Errors = require('../core/enig_error.js').Errors;
|
const Errors = require('../core/enig_error.js').Errors;
|
||||||
const ErrNotEnabled = require('../core/enig_error.js').ErrorReasons.NotEnabled;
|
const ErrNotEnabled = require('../core/enig_error.js').ErrorReasons.NotEnabled;
|
||||||
const ArchiveUtil = require('../core/archive_util.js');
|
const ArchiveUtil = require('../core/archive_util.js');
|
||||||
const Config = require('../core/config.js').config;
|
const Config = require('../core/config.js').config;
|
||||||
const DownloadQueue = require('../core/download_queue.js');
|
const DownloadQueue = require('../core/download_queue.js');
|
||||||
const FileAreaWeb = require('../core/file_area_web.js');
|
const FileAreaWeb = require('../core/file_area_web.js');
|
||||||
const FileBaseFilters = require('../core/file_base_filter.js');
|
const FileBaseFilters = require('../core/file_base_filter.js');
|
||||||
const resolveMimeType = require('../core/mime_util.js').resolveMimeType;
|
const resolveMimeType = require('../core/mime_util.js').resolveMimeType;
|
||||||
const isAnsi = require('../core/string_util.js').isAnsi;
|
const isAnsi = require('../core/string_util.js').isAnsi;
|
||||||
|
const controlCodesToAnsi = require('../core/color_codes.js').controlCodesToAnsi;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -385,9 +386,19 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
if(_.isString(self.currentFileEntry.desc)) {
|
if(_.isString(self.currentFileEntry.desc)) {
|
||||||
const descView = self.viewControllers.browse.getView(MciViewIds.browse.desc);
|
const descView = self.viewControllers.browse.getView(MciViewIds.browse.desc);
|
||||||
if(descView) {
|
if(descView) {
|
||||||
if(isAnsi(self.currentFileEntry.desc)) {
|
//
|
||||||
|
// For descriptions we want to support as many color code systems
|
||||||
|
// as we can for coverage of what is found in the while (e.g. Renegade
|
||||||
|
// pipes, PCB @X##, etc.)
|
||||||
|
//
|
||||||
|
// MLTEV doesn't support all of this, so convert. If we produced ANSI
|
||||||
|
// esc sequences, we'll proceed with specialization, else just treat
|
||||||
|
// it as text.
|
||||||
|
//
|
||||||
|
const desc = controlCodesToAnsi(self.currentFileEntry.desc);
|
||||||
|
if(desc.length != self.currentFileEntry.desc.length || isAnsi(desc)) {
|
||||||
descView.setAnsi(
|
descView.setAnsi(
|
||||||
self.currentFileEntry.desc,
|
desc,
|
||||||
{
|
{
|
||||||
prepped : false,
|
prepped : false,
|
||||||
forceLineTerm : true
|
forceLineTerm : true
|
||||||
|
|
Loading…
Reference in New Issue