Skip to content

Commit

Permalink
Add a working manpage-previewer
Browse files Browse the repository at this point in the history
References: #3
  • Loading branch information
Alhadis committed Feb 11, 2019
1 parent 59df84c commit 986f7e5
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 7 deletions.
12 changes: 7 additions & 5 deletions lib/previewing.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
"use strict";

const {Disposable} = require("atom");
const canvasStyles = require.resolve("roff/lib/postproc/canvas/viewer.css");
const fontStyles = require.resolve("urw-core35-fonts/index.css");
const {getManPrompt} = require("./utils.js");
const {parseManURL, resolveManRef} = require("roff");


module.exports = () => [
attachStyleSheet(fontStyles),
attachStyleSheet(canvasStyles),

atom.workspace.addOpener(uri => {
const page = parseManURL(uri);
if(null !== page)
return; // TODO: Reconnect once adapters are finished
return new (require("./views/manpage-view.js"))(page);
}),

atom.commands.add("body", {
Expand Down Expand Up @@ -74,13 +76,13 @@ function notifyNothingMatched(name, section = ""){
* @internal
*/
async function runOpenCmd(){
const input = await getManPrompt().promptUser({
const input = resolveManRef(await getManPrompt().promptUser({
headerText: "Enter the name of a manual-page",
footerHTML: "E.g., <code>perl</code>, <code>5 grep</code>, <code>grep(5)</code>"});
footerHTML: "E.g., <code>perl</code>, <code>5 grep</code>, <code>grep(5)</code>"}));

return input
? atom.workspace.open((console.log(page), page.toURL()))
: notifyNothingMatched(page.name, page.section);
? atom.workspace.open(`man://${input.join("/")}`)
: notifyNothingMatched(...input);
}


Expand Down
16 changes: 16 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

let promptView = null;
let manAdapter = null;
let grogAdapter = null;
let groffAdapter = null;


Expand All @@ -22,6 +23,21 @@ module.exports = {
},


/**
* Retrieve adapter instance for guessing groff(1) formatting options.
*
* @return {GrogAdapter}
* @internal
*/
async getGrogAdapter(){
if(null === grogAdapter){
const {GrogAdapter} = require("roff");
grogAdapter = await GrogAdapter.loadDefault();
}
return grogAdapter;
},


/**
* Retrieve adapter instance for integrating with groff(1).
*
Expand Down
90 changes: 88 additions & 2 deletions lib/views/manpage-view.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,69 @@
"use strict";

const {TroffCanvasViewer, TTYViewer} = require("roff");
const {getManAdapter, getGrogAdapter, getGroffAdapter} = require("../utils.js");


/**
* Wrapper class which displays rendered previews of Roff documents.
* @internal
* @class
*/
class ManpageView{

constructor(){
constructor(page = {}){
Object.assign(this, page);
this.element = document.createElement("div");
this.canvasView = new TroffCanvasViewer({parentElement: this.element});
this.ttyView = new TTYViewer(document.createElement("pre"));
this.ttyView.element.className = "troff-tty";

let mode = "";
Object.defineProperties(this, {
currentView: {
get: () => "canvas" === mode
? this.canvasView
: this.ttyView,
},

currentElement: {
get: () => this.currentView.root || this.currentView.element,
},

mode: {
get: () => mode,
set: to => {
if(mode === (to = to.trim().toLowerCase())) return;
switch(to){
case "canvas":
this.ttyView.element.remove();
this.element.appendChild(this.canvasView.root);
mode = to;
this.refresh();
break;

// FIXME: Nuke the entire TTYViewer class
case "tty":
this.canvasView.root.remove();
this.element.appendChild(this.ttyView.element);
mode = to;
Object.assign(this.ttyView.element.style, {
fontSize: atom.config.get("editor.fontSize") + "px",
fontFamily: atom.config.get("editor.fontFamily"),
lineHeight: atom.config.get("editor.lineHeight"),
});
this.refresh();
break;
}
},
},
});
this.mode = "canvas";
}


getIconName(){
return "manpage-icon";
return "manpage";
}


Expand All @@ -17,8 +73,38 @@ class ManpageView{
}


getTitle(){
if(!this.name) return "Untitled";
let title = this.name;
if(this.section) title += `(${this.section})`;
return title;
}


getPath(){
return this.path || "";
}


async refresh(){
const groff = await getGroffAdapter();

if(groff){
const grog = await getGrogAdapter();
const man = await getManAdapter();
this.path = (await man.find(this.name, this.section))[0];
this.source = await man.load(this.path);
const device = "canvas" === this.mode
? groff.devices.pdf ? "pdf" : "ps"
: groff.devices.utf8 ? "utf8" : "ascii";
const tokens = await groff.format(this.source, device, {
args: (await grog.guessOptions(this.source)).pop().slice(1),
raw: true,
});
"canvas" === this.mode
? this.currentView.load(tokens)
: this.currentView.render(tokens);
}
}
}

Expand Down
45 changes: 45 additions & 0 deletions styles/styles.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
@import "syntax-variables";

// Fix that sodding highlighting in error notifications
atom-notifications atom-notification.error pre > code{
background: inherit;
}

// Tab-icons for ManpageViews
.icon-manpage{
body:not(.file-icons-coloured):not(.file-icons-colourless) &::before{
font-family: "Octicons Regular";
font-size: 16px;
top: 1px;
content: "\f007";
}

body.file-icons-coloured &::before,
body.file-icons-colourless &::before{
content: "\e936";
font-family: file-icons;
font-size: 15px;
top: 3px;
}

body.file-icons-coloured &::before{
color: #66783e;
}
}

.troff-view-pages{
padding: 1em;
}
.troff-view-page{
margin-bottom: 1em;
}

.troff-tty{
background: @syntax-background-color;
color: @syntax-text-color;

white-space: pre;
overflow-x: hidden;
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

0 comments on commit 986f7e5

Please sign in to comment.