Added basic terminal coloring to the infolines
This commit is contained in:
@@ -65,6 +65,7 @@ Note that currently, Kopher and hi01379.js assume that the search request from a
|
||||
- Unlimited navigation history (doesn't persist between sessions)
|
||||
- Up to 10 numbered bookmarks plus customizable homepage
|
||||
- Binary blob downloads (see "Downloads")
|
||||
- Limited support of ANSI terminal escape codes in Gophermap infolines (see "Does it have terminal emulation support for character styling?")
|
||||
|
||||
## Controls
|
||||
|
||||
@@ -105,9 +106,17 @@ For your convenience, only the current hole hostname is always displayed in the
|
||||
|
||||
Yes. In fact, UTF-8 is the only supported encoding. As ASCII is a subset of UTF-8, old ASCII-only resources will be displayed just fine as well.
|
||||
|
||||
## Does it have terminal emulation support for character coloring purposes?
|
||||
## Does it have terminal emulation support for character styling?
|
||||
|
||||
No, but that feature is considered to be implemented if this client gains more traction and if there still is enough amount of the resources that actually use VT escape characters.
|
||||
As of April 2023, Kopher implements a subset of ANSI terminal escape codes for text styling purposes with the following limitations:
|
||||
|
||||
- they are applied to the Gophermap information lines **only** (and detected and deleted everywhere else);
|
||||
- they only work within the single infoline or a block of sequential infolines and all styling gets reset when another entry type is encountered, even if the reset sequence isn't there;
|
||||
- only the basic 8/16-color palette is implemented (because these codes physically translate into corresponding data attributes);
|
||||
- beside the colors, the following text attributes are implemented: bold, italic, underline, blinking, inverse, hidden, strikethrough;
|
||||
- any unsupported escape sequences are automatically deleted from the rendered output.
|
||||
|
||||
All these limitations are intended to keep Kopher's codebase simple, and not likely to change in the foreseeable future.
|
||||
|
||||
## Can I use the hi01379.js library in non-KaiOS environments?
|
||||
|
||||
|
||||
@@ -64,3 +64,54 @@ footer .status {width: 100%; text-overflow: ellipsis; overflow: hidden; white-sp
|
||||
}
|
||||
.content a[data-focused="1"] {text-decoration: underline}
|
||||
|
||||
/* Terminal infoline styling */
|
||||
|
||||
/* modes = ['', 'BB', 'FN', 'IT', 'UL', 'BL', '', 'IN', 'HI', 'ST'] */
|
||||
|
||||
/* colors (FC/BC): 0 black, 1 red, 2 green, 3 yellow, 4 blue, 5 magenta, 6 cyan, 7 white */
|
||||
|
||||
.content span[data-styling] {
|
||||
--ds-fg-color: var(--fg-color);
|
||||
--ds-bg-color: var(--bg-color);
|
||||
background: var(--ds-bg-color);
|
||||
color: var(--ds-fg-color);
|
||||
}
|
||||
|
||||
@keyframes strict_blink {
|
||||
0% {
|
||||
visibility: hidden
|
||||
}
|
||||
50% {
|
||||
visibility: hidden
|
||||
}
|
||||
100% {
|
||||
visibility: visible
|
||||
}
|
||||
}
|
||||
|
||||
.content span[data-styling~="BB"] {font-weight: bolder}
|
||||
.content span[data-styling~="IT"] {font-style: italic}
|
||||
.content span[data-styling~="UL"] {text-decoration: underline}
|
||||
.content span[data-styling~="BL"] {animation: 2s linear infinite strict_blink}
|
||||
.content span[data-styling~="IN"] {background:var(--ds-fg-color);color:var(--ds-bg-color)}
|
||||
.content span[data-styling~="HI"] {visibility: hidden}
|
||||
.content span[data-styling~="ST"] {text-decoration: line-through}
|
||||
|
||||
.content span[data-styling~="FC0"] {--ds-fg-color: black}
|
||||
.content span[data-styling~="FC1"] {--ds-fg-color: red}
|
||||
.content span[data-styling~="FC2"] {--ds-fg-color: green}
|
||||
.content span[data-styling~="FC3"] {--ds-fg-color: yellow}
|
||||
.content span[data-styling~="FC4"] {--ds-fg-color: blue}
|
||||
.content span[data-styling~="FC5"] {--ds-fg-color: magenta}
|
||||
.content span[data-styling~="FC6"] {--ds-fg-color: cyan}
|
||||
.content span[data-styling~="FC7"] {--ds-fg-color: white}
|
||||
|
||||
.content span[data-styling~="BC0"] {--ds-bg-color: black}
|
||||
.content span[data-styling~="BC1"] {--ds-bg-color: red}
|
||||
.content span[data-styling~="BC2"] {--ds-bg-color: green}
|
||||
.content span[data-styling~="BC3"] {--ds-bg-color: yellow}
|
||||
.content span[data-styling~="BC4"] {--ds-bg-color: blue}
|
||||
.content span[data-styling~="BC5"] {--ds-bg-color: magenta}
|
||||
.content span[data-styling~="BC6"] {--ds-bg-color: cyan}
|
||||
.content span[data-styling~="BC7"] {--ds-bg-color: white}
|
||||
|
||||
|
||||
+67
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"name": "Kopher",
|
||||
"description": "A Gopher client for KaiOS",
|
||||
"launch_path": "/index.html",
|
||||
|
||||
Reference in New Issue
Block a user