Skip to content

Commit

Permalink
Add partial logic for piping data through troff(1)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alhadis committed Jun 2, 2018
1 parent 795aae7 commit e74070d
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 34 deletions.
77 changes: 54 additions & 23 deletions lib/manpager.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,6 @@ class ManPager{
}


/**
* Format a chunk of raw Roff source.
*
* @param {String} input
* @param {String} [format="tty"]
* @public
*/
async formatSource(input, format = "tty"){
await this.resolveTroff();
if(TroffType.GROFF === this.troffType){

}
const data = this.renderer.process(input);
!this.headless
? this.element.innerHTML = this.renderer.output
: process.stdout.write(this.renderer.output);
}


/**
* Load a manpage file, then render it.
*
Expand All @@ -86,6 +67,26 @@ class ManPager{
}


/**
* Format a chunk of raw Roff source.
*
* @param {String} input
* @param {String} [format="tty"]
* @public
*/
async formatSource(input, format = "tty"){
const troffType = await this.resolveTroff();
const [cmd, args] = await troffType.guessPipeline(input, format);
const ll = this.columns * 9/10;
input = `.ll ${ll}v\n.nr LL ${ll}v\n${input}`;
input = (await shell.exec(cmd, args, input)).stdout;
const data = this.renderer.process(input);
!this.headless
? this.element.innerHTML = this.renderer.output
: process.stdout.write(this.renderer.output);
}


/**
* Retrieve the path(s) for a named manpage.
*
Expand All @@ -96,7 +97,7 @@ class ManPager{
*/
async locatePage(...args){
const {stdout} = await shell.exec("man", [
...await this.resolveArgs(),
...await this.argsToLocate(),
...ManPager.resolve(...args).reverse(),
].filter(Boolean));
return stdout.trim().split(/\n+/);
Expand All @@ -111,11 +112,11 @@ class ManPager{
* any support, while on Illumos, it updates the whatis(1) database
* instead of printing the location of manpages.
*
* @example resolveArgs() => ["-k"]; // Solaris 11.3
* @example argsToLocate() => ["-k"]; // Solaris 11.3
* @return {Promise} Resolves with an array of option strings.
* @internal
*/
async resolveArgs(){
async argsToLocate(){
if(this.manOpts && this.manOpts.length)
return this.manOpts;

Expand Down Expand Up @@ -162,7 +163,37 @@ class ManPager{
if(null === hostTroff)
hostTroff = await TroffType.resolveDefault();

return hostTroff;
return this.troffType = hostTroff;
}


/**
* Width of the container element, measured in columns.
* @property {Number}
* @default 80
* @readonly
*/
get columns(){
if(this.element)
return Math.ceil(this.element.offsetWidth / this.pointSize);
return ("object" === typeof process)
? process.stdout.columns
: 80;
}


/**
* Height of the container element, measured in lines.
* @property {Number}
* @default 25
* @readonly
*/
get rows(){
if(this.element)
return Math.ceil(this.element.offsetHeight / this.pointSize);
return ("object" === typeof process)
? process.stdout.rows
: 25;
}


Expand Down
63 changes: 53 additions & 10 deletions lib/troff-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,40 @@ class TroffType{

switch(this.name){
case TroffType.GROFF:
this.fullName = "GNU Troff";
this.hasDitroff = true;
this.hasGrog = true;
this.html = "groff -Thtml";
this.html = "groff -ZThtml";
this.markdown = null;
this.pdf = "groff -Tpdf";
this.postscript = "groff -Tps";
this.tty = "groff -Tutf8";
this.pdf = "groff -ZTpdf";
this.postscript = "groff -ZTps";
this.tty = "groff -ZTutf8";
break;

case TroffType.GROFF_LIKE:
this.fullName = "GNU-compatible Troff";
this.hasDitroff = true;
this.hasGrog = false;
this.html = "troff -Thtml";
this.html = "troff -ZThtml";
this.markdown = null;
this.pdf = "troff -Tpdf";
this.postscript = "troff -Tps";
this.tty = "nroff -Tutf8";
this.pdf = "troff -ZTpdf";
this.postscript = "troff -ZTps";
this.tty = "nroff -ZTutf8";
break;

case TroffType.HEIRLOOM:
this.hasDitroff = true;
this.fullName = "Heirloom Doctools";
this.hasDitroff = "troff-only";
this.hasGrog = false;
this.html = "troff -Thtml";
this.markdown = null;
this.pdf = null;
this.postscript = "troff -Tps";
this.tty = "nroff -Tlocale";
this.tty = "nroff -T37";
break;

case TroffType.MANDOC:
this.fullName = "mandoc";
this.hasDitroff = false;
this.hasGrog = false;
this.html = "mandoc -Thtml -a";
Expand All @@ -64,6 +68,7 @@ class TroffType{
break;

case TroffType.AIX:
this.fullName = "IBM AIX Troff";
this.hasDitroff = true;
this.hasGrog = false;
this.html = null;
Expand All @@ -74,6 +79,7 @@ class TroffType{
break;

case TroffType.SOLARIS10:
this.fullName = "Solaris 10 Troff";
this.hasDitroff = false;
this.hasGrog = false;
this.html = null;
Expand All @@ -84,6 +90,7 @@ class TroffType{
break;

case TroffType.SOLARIS11:
this.fullName = "Solaris 11 Troff";
this.hasDitroff = "troff-only";
this.hasGrog = false;
this.html = null;
Expand All @@ -98,6 +105,11 @@ class TroffType{
case TroffType.FRONT:
case TroffType.PLAN9:
this.env = { DWBHOME: dirname(dirname(this.path)) };
this.fullName = {
[TroffType.DWB]: "Documenter's Workbench",
[TroffType.FRONT]: "9front Troff",
[TroffType.PLAN9]: "Plan 9 Troff",
}[this.name];
this.hasDitroff = "troff-only";
this.hasGrog = false;
this.html = null;
Expand All @@ -110,6 +122,37 @@ class TroffType{
}


/**
* Determine which arguments to use for processing a Roff document.
*
* @example guessPipeline(source) => ["groff", ["-Tutf8", "-Z"]];
* @param {String} source - Unprocessed Roff source
* @param {String} [format="tty"] - Destination format
* @return {String[]} An array of CLI args, starting with the command
* @internal
*/
async guessPipeline(source, format = "tty"){
let cmd, args;

// Format not supported by implementation.
if(!this[format]){
const message = `Output "${format}" not supported by ${this.fullName}`;
throw Object.assign(new ReferenceError(message), {troffType: this});
}

// Use grog(1) if available
if(this.hasGrog){
const {stdout} = (await shell.exec("grog", ["-ZTutf8"], source));
[cmd, ...args] = stdout.trim().split(/\s+/g);
}

// Guess the pipeline ourselves (TODO)
else [cmd, ...args] = this[format].split(" ");

return [cmd, args];
}


/**
* Determine which implementation of troff(1) the host system uses.
*
Expand Down
2 changes: 1 addition & 1 deletion preview-manpager.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
});

// Load ditroff source from file, then render it
view.formatPage("./test/fixtures/text/groff_char.7.out");
view.formatPage("groff_char");
</script>
</body>
</html>
29 changes: 29 additions & 0 deletions test/fixtures/text/preproc.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'\" t
.\" Pipeline-guessing fixture
.
.TH TITLE 1
.SH SYNOPSIS
Irrelevant preamble goes here.
.
.SH STUFF
.
.\" Chemicals
.cstart
.ps 26
size 28
R1:
ring double 1,2 3,4 5,6
bond 60 from R1.V2
bond 120
A1:
front bond down ; CH3
bond 60 from A1 ; NH2
.ps
.cend
.
.so symbol-list.roff
.
.\" Math
.EQ I (3.1a)
x = f(y/2) + y/2
.EN

0 comments on commit e74070d

Please sign in to comment.