Skip to content

Commit

Permalink
Add support for processing legacy nroff(1) output
Browse files Browse the repository at this point in the history
  • Loading branch information
Alhadis committed Jun 2, 2018
1 parent cdf9d5c commit 7a756b9
Show file tree
Hide file tree
Showing 6 changed files with 843 additions and 9 deletions.
5 changes: 3 additions & 2 deletions bin/html-tty
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ new Promise(resolve => {
process.stdin.on("readable", () => {
const chunk = process.stdin.read();
null !== chunk ? input += chunk : resolve(input);
})
});
}
}).then(data => {
let output = htmlTTY.process(data);
const isRaw = /\x08/.test(data);
let output = htmlTTY.process(data, isRaw);
if(process.stdout.isTTY)
output = output
.replace(/^\n+/, "")
Expand Down
24 changes: 17 additions & 7 deletions lib/postproc/html-tty.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,25 @@ class HTMLTTY extends Postprocessor {
}


process(data){
process(data, raw = false){
this.reset();
super.process(data);
if(null !== this.page){
this.output += this.page.toString().replace(/^ *\n/, "");
this.page = null;

// Raw text printed by older nroff(1) versions
if(raw){
this.output = new TextGrid().read(data).toString();
return this.output;
}

// Ditroff (intermediate troff output)
else{
super.process(data);
if(null !== this.page){
this.output += this.page.toString().replace(/^ *\n/, "");
this.page = null;
}
this.output = this.output.replace(/\s+$/, "");
return this.output;
}
this.output = this.output.replace(/\s+$/, "");
return this.output;
}


Expand Down
124 changes: 124 additions & 0 deletions lib/text-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,130 @@ class TextGrid{
: toPlainText;
return this.data.map(fn).join("\n");
}


read(text){
if(!text) return this;
let yOffset = 0;
const {length} = text;
for(let i = 0; i < length; ++i){
const next = text.charCodeAt(i + 1) || -1;
switch(text.charCodeAt(i)){

// Backspace
case 0x08:
this.left();
break;

// Horizontal tab
case 0x09:
break;

// Vertical tab ("Line tabulation")
case 0x0B:
this.up();
break;

// Carriage return
case 0x0D:
if(0x0A === next)
continue;
this.x = 0;
break;

// Newline
case 0x0A:
case 0x85:
this.write("\n");
break;

// Form feed
case 0x0C:
this.down();
break;

// Shift out: Enable reverse video
case 0x0E:
break;

// Shift in: Disable reverse video
case 0x0F:
break;

// Space
case 0x20:
this.right();
break;

// Escape
case 0x1B:
switch(next){
// Full-reverse line feed
case 0x07:
case 0x37:
this.up();
yOffset = 0;
++i;
break;

// Half-reverse line feed
case 0x08:
case 0x38:
++i;
yOffset -= 0.5;
if(-1 === yOffset){
yOffset = 0;
this.up();
}
break;

// Half-forward line feed
case 0x09:
case 0x39:
++i;
yOffset += 0.5;
if(1 === yOffset){
yOffset = 0;
this.down();
}
break;

// CSI introducer (omitted for now)
case 0x5B:
break;
}
break;

// Anything else
default:{
const char = this.currentChar;

if(char && /\S/.test(char)){
const prevFont = this.data[this.y][this.x][1];

// Underline
if("_" === char || "_" === text[i]){
this.font = ("B" === prevFont || "BI" === prevFont) ? "BI" : "I";
this.write("_" === char ? text[i] : char);
this.font = "R";
}

// Embolden
else if(/\S/.test(text[i]) && text[i] === char){
this.font = ("I" === prevFont || "BI" === prevFont) ? "BI" : "B";
this.write(char);
this.font = "R";
}

// Print normally
else this.write(text[i]);
}
else this.write(text[i]);
}
}
}
return this;
}


write(text){
Expand Down
7 changes: 7 additions & 0 deletions test/1-html-tty.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ describe("HTMLTTY", () => {
});
}

it("formats raw nroff(1) output correctly", () => {
const source = read("teletype.txt");
const expected = read("teletype.html");
const result = [tmplHeader, htmlTTY.process(source, true), tmplFooter, ""].join("\n");
expect(result).to.eql(expected);
});

it("can be used as a command-line postprocessor", () => {
return new Promise((resolve, reject) => {
const {exec} = require("child_process");
Expand Down
Loading

0 comments on commit 7a756b9

Please sign in to comment.