Display ANSI in file area desc view
This commit is contained in:
parent
9cb31367fd
commit
0a079ee4d8
|
@ -21,7 +21,7 @@ exports.renderStringLength = renderStringLength;
|
||||||
exports.formatByteSizeAbbr = formatByteSizeAbbr;
|
exports.formatByteSizeAbbr = formatByteSizeAbbr;
|
||||||
exports.formatByteSize = formatByteSize;
|
exports.formatByteSize = formatByteSize;
|
||||||
exports.cleanControlCodes = cleanControlCodes;
|
exports.cleanControlCodes = cleanControlCodes;
|
||||||
exports.createCleanAnsi = createCleanAnsi;
|
exports.prepAnsi = prepAnsi;
|
||||||
|
|
||||||
// :TODO: create Unicode verison of this
|
// :TODO: create Unicode verison of this
|
||||||
const VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
const VOWELS = [ 'a', 'e', 'i', 'o', 'u' ];
|
||||||
|
@ -373,48 +373,35 @@ function cleanControlCodes(input, options) {
|
||||||
return cleaned;
|
return cleaned;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCleanAnsi(input, options, cb) {
|
function prepAnsi(input, options, cb) {
|
||||||
|
|
||||||
if(!input) {
|
if(!input) {
|
||||||
return cb('');
|
return cb(null, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
options.width = options.width || 80;
|
options.termWidth = options.termWidth || 80;
|
||||||
options.height = options.height || 25;
|
options.termHeight = options.termHeight || 25;
|
||||||
|
|
||||||
const canvas = new Array(options.height);
|
options.cols = options.cols || options.termWidth || 80;
|
||||||
for(let i = 0; i < options.height; ++i) {
|
options.rows = options.rows || options.termHeight || 25;
|
||||||
canvas[i] = new Array(options.width);
|
|
||||||
for(let j = 0; j < options.width; ++j) {
|
|
||||||
canvas[i][j] = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parserOpts = {
|
options.startCol = options.startCol || 1;
|
||||||
termHeight : options.height,
|
|
||||||
termWidth : options.width,
|
|
||||||
};
|
|
||||||
|
|
||||||
const parser = new ANSIEscapeParser(parserOpts);
|
const canvas = Array.from( { length : options.rows }, () => Array.from( { length : options.cols}, () => new Object() ) );
|
||||||
|
const parser = new ANSIEscapeParser( { termHeight : options.termHeight, termWidth : options.termWidth } );
|
||||||
|
|
||||||
const canvasPos = {
|
const state = {
|
||||||
col : 0,
|
|
||||||
row : 0,
|
row : 0,
|
||||||
|
col : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let sgr;
|
let lastRow = 0;
|
||||||
|
|
||||||
function ensureCell() {
|
parser.on('position update', (row, col) => {
|
||||||
// we've pre-allocated a matrix, but allow for > supplied dimens up front. They will be trimmed @ finalize
|
state.row = row - 1;
|
||||||
if(!canvas[canvasPos.row]) {
|
state.col = col - 1;
|
||||||
canvas[canvasPos.row] = new Array(options.width);
|
|
||||||
for(let j = 0; j < options.width; ++j) {
|
lastRow = Math.max(state.row, lastRow);
|
||||||
canvas[canvasPos.row][j] = {};
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas[canvasPos.row][canvasPos.col] = canvas[canvasPos.row][canvasPos.col] || {};
|
|
||||||
//canvas[canvasPos.row][0].width = Math.max(canvas[canvasPos.row][0].width || 0, canvasPos.col);
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.on('literal', literal => {
|
parser.on('literal', literal => {
|
||||||
//
|
//
|
||||||
|
@ -422,99 +409,83 @@ function createCleanAnsi(input, options, cb) {
|
||||||
//
|
//
|
||||||
literal = literal.replace(/\r?\n|[\r\u2028\u2029]/g, '');
|
literal = literal.replace(/\r?\n|[\r\u2028\u2029]/g, '');
|
||||||
|
|
||||||
for(let i = 0; i < literal.length; ++i) {
|
for(let c of literal) {
|
||||||
const c = literal.charAt(i);
|
if(state.col < options.cols && state.row < options.rows) {
|
||||||
|
canvas[state.row][state.col].char = c;
|
||||||
|
|
||||||
ensureCell();
|
if(state.sgr) {
|
||||||
|
canvas[state.row][state.col].sgr = state.sgr;
|
||||||
canvas[canvasPos.row][canvasPos.col].char = c;
|
state.sgr = null;
|
||||||
|
}
|
||||||
if(sgr) {
|
|
||||||
canvas[canvasPos.row][canvasPos.col].sgr = sgr;
|
|
||||||
sgr = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasPos.col += 1;
|
state.col += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.on('control', (match, opCode) => {
|
parser.on('control', (match, opCode) => {
|
||||||
if('m' !== opCode) {
|
//
|
||||||
return; // don't care'
|
// Movement is handled via 'position update', so we really only care about
|
||||||
|
// display opCodes
|
||||||
|
//
|
||||||
|
switch(opCode) {
|
||||||
|
case 'm' :
|
||||||
|
state.sgr = (state.sgr || '') + match;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
if(-1 === [ 'C' ].indexOf(opCode)) {
|
||||||
|
console.log(`ignore opCode: ${opCode}`); // :TODO: REMOVE ME
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sgr = match;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.on('position update', (row, col) => {
|
function getLastPopulatedColumn(row) {
|
||||||
canvasPos.row = row - 1;
|
let col = row.length;
|
||||||
canvasPos.col = Math.min(col - 1, options.width);
|
while(--col > 0) {
|
||||||
});
|
if(row[col].char || row[col].sgr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
parser.on('complete', () => {
|
parser.on('complete', () => {
|
||||||
for(let row = 0; row < options.height; ++row) {
|
let output = '';
|
||||||
let col = 0;
|
let lastSgr = '';
|
||||||
|
canvas.slice(0, lastRow + 1).forEach(row => {
|
||||||
|
const lastCol = getLastPopulatedColumn(row) + 1;
|
||||||
|
|
||||||
//while(col <= canvas[row][0].width) {
|
let i;
|
||||||
while(col < options.width) {
|
for(i = 0; i < lastCol; ++i) {
|
||||||
if(!canvas[row][col].char) {
|
const col = row[i];
|
||||||
canvas[row][col].char = ' ';
|
if(col.sgr) {
|
||||||
if(!canvas[row][col].sgr) {
|
lastSgr = col.sgr;
|
||||||
// :TODO: fix duplicate SGR's in a row here - we just need one per sequence
|
|
||||||
canvas[row][col].sgr = ANSI.reset();
|
|
||||||
}
|
}
|
||||||
|
output += `${col.sgr || ''}${col.char || ' '}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
col += 1;
|
if(i < row.length) {
|
||||||
|
output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// :TODO: end *all* with CRLF - general usage will be width : 79 - prob update defaults
|
if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) {
|
||||||
|
output += '\r\n';
|
||||||
if(col <= options.width) {
|
|
||||||
canvas[row][col] = canvas[row][col] || {};
|
|
||||||
|
|
||||||
canvas[row][col].char = '\r\n';
|
|
||||||
canvas[row][col].sgr = ANSI.reset();
|
|
||||||
|
|
||||||
// :TODO: don't splice, just reset + fill with ' ' till end
|
|
||||||
for(let fillCol = col; fillCol <= options.width; ++fillCol) {
|
|
||||||
canvas[row][fillCol].char = ' ';
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//canvas[row] = canvas[row].splice(0, col + 1);
|
return cb(null, output);
|
||||||
//canvas[row][options.width - 1].char = '\r\n';
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
canvas[row] = canvas[row].splice(0, options.width + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let out = '';
|
|
||||||
for(let row = 0; row < options.height; ++row) {
|
|
||||||
out += canvas[row].map( col => {
|
|
||||||
let c = col.sgr || '';
|
|
||||||
c += col.char;
|
|
||||||
return c;
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// :TODO: finalize: @ any non-char cell, reset sgr & set to ' '
|
|
||||||
// :TODO: finalize: after sgr established, omit anything > supplied dimens
|
|
||||||
return cb(out);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.parse(input);
|
parser.parse(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create2dArray = (rows, columns) => [...Array(rows).keys()].map(i => Array(columns).fill({}))
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
const fs = require('graceful-fs');
|
const fs = require('graceful-fs');
|
||||||
let data = fs.readFileSync('/home/nuskooler/Downloads/art3.ans');
|
//let data = fs.readFileSync('/home/nuskooler/Downloads/art3.ans');
|
||||||
|
//let data = fs.readFileSync('/home/nuskooler/dev/enigma-bbs/mods/themes/nu-xibalba/MATRIX1.ANS');
|
||||||
|
let data = fs.readFileSync('/home/nuskooler/Downloads/ansi_diz_test/file_id.diz.2.ans');
|
||||||
data = iconv.decode(data, 'cp437');
|
data = iconv.decode(data, 'cp437');
|
||||||
createCleanAnsi(data, { width : 79, height : 25 }, (out) => {
|
prepAnsi(data, { cols : 45, rows : 25 }, (err, out) => {
|
||||||
out = iconv.encode(out, 'cp437');
|
out = iconv.encode(out, 'cp437');
|
||||||
fs.writeFileSync('/home/nuskooler/Downloads/art4.ans', out);
|
fs.writeFileSync('/home/nuskooler/Downloads/art4.ans', out);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,6 @@ 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 createCleanAnsi = require('../core/string_util.js').createCleanAnsi;
|
|
||||||
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;
|
||||||
|
@ -19,8 +18,6 @@ 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 cleanControlCodes = require('../core/string_util.js').cleanControlCodes;
|
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
@ -378,17 +375,15 @@ 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) {
|
||||||
createCleanAnsi(
|
descView.setAnsi(
|
||||||
self.currentFileEntry.desc,
|
self.currentFileEntry.desc,
|
||||||
{ height : self.client.termHeight, width : descView.dimens.width },
|
{
|
||||||
cleanDesc => {
|
prepped : false,
|
||||||
// :TODO: use cleanDesc -- need to finish createCleanAnsi() !!
|
forceLineTerm : true
|
||||||
//descView.setText(cleanDesc);
|
},
|
||||||
descView.setText( self.currentFileEntry.desc );
|
() => {
|
||||||
|
|
||||||
self.updateQueueIndicator();
|
self.updateQueueIndicator();
|
||||||
self.populateCustomLabels('browse', MciViewIds.browse.customRangeStart);
|
self.populateCustomLabels('browse', MciViewIds.browse.customRangeStart);
|
||||||
|
|
||||||
return callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue