Added basic terminal coloring to the infolines

This commit is contained in:
Luxferre
2023-04-03 12:37:10 +03:00
parent 53f9dc3a46
commit 1bbe1ffd81
4 changed files with 130 additions and 4 deletions
+67 -1
View File
@@ -28,11 +28,74 @@ Hi01379 = (function(psGopherRequest) {
}).join('\n')
}
function terminalize(str, attrs) { // partial terminal styling support with ANSI codes
if(!attrs) attrs = [] // accept previous attributes array if present
var prevattrs = attrs.join(' ') // preserve stringified copy
var out = '', c, styleseq, sl, l = str.length, i, j, att, attindex, strattrs,
visualOpenTag='<span data-styling="%s">', visualCloseTag='</span>',
modes = ['', 'BB', 'FN', 'IT', 'UL', 'BL', '', 'IN', 'HI', 'ST']
for(i=0;i<l;i++) {
c = str[i]
if(c === '\x1b') { // escape character encountered
c = str[i+1] // get the next character, don't increase the counter yet
if(c === '[') { // ANSI sequence starting
i++ // increase the counter, now it's pointing to [
styleseq='' // init style sequence buffer
do { // read the style sequence until m character or any whitespace
c = str[++i] // increase the counter once more, [ is ignored
styleseq += c
} while(c !== 'm' && c !== ' ' && c !== '\t' && c !== '\r' && c !== '\n')
styleseq = styleseq.slice(0, -1).split(';') // attributes are delimited by ;
for(sl=styleseq.length,j=0;j<sl;j++) { // iterate over attributes in their order
att = parseInt(styleseq[j]) // in this case parseInt is more reliable than |0
if(att === 0) attrs = [] // reset all styling
else if(att >= 30 && att <= 37) attrs.push('FC'+(att-30)) // foreground color
else if(att >= 40 && att <= 47) attrs.push('BC'+(att-40)) // background color
else if(att < 10) attrs.push(modes[att]) // activate special modes
else if(att > 20 && att < 30) { // deactivate special modes
if(att === 22) { // also deactivate bold mode 1
attindex = attrs.indexOf('BB')
if(attindex > -1)
attrs.splice(attindex, 1)
}
attindex = attrs.indexOf(modes[att - 20])
if(attindex > -1)
attrs.splice(attindex, 1)
}
else if(att === 39) { // reset only the foreground color
attrs = attrs.map(function(v) {
return v.startsWith('FC') ? '' : v
}).filter(String)
}
else if(att === 49) { // reset only the background color
attrs = attrs.map(function(v) {
return v.startsWith('BC') ? '' : v
}).filter(String)
}
}
// now we have our attrs array with all styling applied, output the tags
strattrs = attrs.join(' ')
if(strattrs != prevattrs) { // there are some changes
if(prevattrs != '') // previous attributes were not empty
out += visualCloseTag
if(strattrs) // current attributes are not empty
out += visualOpenTag.replace('%s', strattrs)
prevattrs = strattrs // update the previous attribute cache
}
} // don't add any processed characters "as is" to the output
else continue // skip the escape and proceed with the loop
}
else out += c // just append it to the output
}
return {output: out, attrs: attrs} // return both output and remaining attributes
}
function gophermapToHTML(gmap, chost, cport) {
if(!cport) cport = 70
if(!chost) chost = 'localhost'
var lines = gmap.split(/\r?\n/), line, l = lines.length, i, lbr = '<br>',
type, rest, desc, sel, host, port,
iattrs = [], istyled, // attribute cache and styled infomessage placeholder
output = '', pretag = 'pre', preflag = false
for(i=0;i<l;i++) {
line = lines[i]
@@ -55,11 +118,14 @@ Hi01379 = (function(psGopherRequest) {
preflag = true
output += '<' + pretag + '>'
}
output += desc + '\n'
istyled = terminalize(desc, iattrs)
iattrs = istyled.attrs
output += istyled.output + '\n'
}
else { //information messages ended, stop preformatting
if(preflag) {
preflag = false
iattrs = [] // reset info styling attributes
output += '</' + pretag + '>'
}
if(desc = desc.trim()) { // ignore empty descriptions