This commit is contained in:
Talon Poole 2021-01-28 23:07:57 +00:00
parent 69d524e79e
commit e587d1a933
7 changed files with 73 additions and 29 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
*.min.*
node_modules/
gmi-web.1
capsule/

View file

@ -75,19 +75,17 @@ gmi.css will respect system dark mode preferences by inverting `--foreground` an
## gmi-web(1)
```
gmi-web [--out path] [--no-css] [files]
gmi-web [--no-css] [files..]
A bridge between Gemini and HTML. See gmi-web(1) for more details.
Convert .gmi to .html. See gmi-web(1) for more details.
Positionals:
files .gmi files to convert to .html
files .gmi files to convert to .html [required]
Options:
--version Show version number
--help Show help
--out Write .html files to a seperate directory located at path.
--no-css Do not include gmi.css in the rendered HTML markup.
--version Show version number [boolean]
--help Show help [boolean]
--css Toggle inclusion of gmi.css. [boolean] [default: true]
```
*You will need*:

19
cli.js
View file

@ -3,28 +3,29 @@ const path = require("path");
const fs = require("vinyl-fs");
const map = require("map-stream");
const tokenize = require("./tokenize");
const toHTML = require("./to-html");
require("yargs")
.scriptName("gmi-web")
.command(
"$0 [--no-css] [files..]",
"A bridge between Gemini and HTML. See gmi-web(1) for more details.",
"Convert .gmi to .html. See gmi-web(1) for more details.",
(yargs) =>
yargs
.positional("files", {
describe: ".gmi files to convert to .html",
})
.required("files", true)
.option("no-css", {
.option("css", {
type: "boolean",
description: "Do not include gmi.css in the rendered HTML markup.",
default: true,
description: "Toggle inclusion of gmi.css.",
}),
(argv) => {
fs.src(argv.files).pipe(map(tokenize)).pipe(map(log));
//.pipe(fs.dest((file) => {
// const dest = path.dirname(file.path)
// console.log(file.path, dest)
// return dest
//}));
fs.src(argv.files)
.pipe(map(tokenize))
.pipe(map(toHTML({css: argv["css"]})))
.pipe(fs.dest((file) => path.dirname(file.path)));
}
)
.help().argv;

View file

@ -6,7 +6,7 @@ gmi-web - A bridge between Gemini and HTML
# SYNOPSIS
*gmi-web* [--out _path_] [--no-css] _files_
*gmi-web* [--no-css] _files_
# DESCRIPTION
@ -15,9 +15,6 @@ and mobile-friendly fashion!
# OPTIONS
*--out* _path_
Write .html files to a seperate directory located at _path_.
*--no-css*
Do not include gmi.css in the rendered HTML markup.
@ -29,12 +26,6 @@ The following example will create .html converted files next to their .gmi count
$ gmi-web gmi/*.gmi
```
If you would like to seperate the .html files out to their own folder use the *--out* flag.
```
$ gmi-web --out html gmi/*.gmi
```
# AUTHORS
Maintained by Talon Poole <code@talon.computer>. Up-to-date sources can be

View file

@ -1 +1 @@
module.exports = /^((=>\s?(?<href>[^\s]+)\s(?<title>.+))|(?<pre>```\s?(?<alt>.+)?)|(###\s?(?<h3>.+))|(##\s?(?<h2>.+))|(#\s?(?<h1>.+))|(\*\s?(?<li>.+))|(>\s?(?<quote>.+))|(?<text>(.+)?))$/;
module.exports = /^((=>\s?(?<href>[^\s]+)(\s(?<title>.+))?)|(?<pre>```\s?(?<alt>.+)?)|(###\s?(?<h3>.+))|(##\s?(?<h2>.+))|(#\s?(?<h1>.+))|(\*\s?(?<li>.+))|(>\s?(?<quote>.+))|(?<text>(.+)?))$/;

54
to-html.js Normal file
View file

@ -0,0 +1,54 @@
const TOKENS_EXT = /\.tokens\.json$/;
module.exports = ({css} = {css: true}) => (file, cb) => {
if (!TOKENS_EXT.test(file.path)) return cb(null, file);
file.path = file.path.replace(TOKENS_EXT, ".html");
file.contents = Buffer.from(`<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">${css ?
'\n<meta name="color-scheme" content="dark light">\n<link rel="stylesheet" href="/gmi.min.css">'
: ''}
<body>
${toHTML(JSON.parse(file.contents.toString("utf8")))}
</body>
</html>
`);
return cb(null, file);
};
function toHTML(tokens) {
let body = []
let cursor = tokens.shift()
while (tokens.length) {
if (cursor.pre) {
body.push(`<pre${cursor.alt ? `title="${cursor.alt}"` : ""}>`)
const closing = tokens.findIndex(token => token.pre)
body = body.concat(tokens.slice(0, closing).map(({text}) => text))
body.push("</pre>")
tokens = tokens.slice(closing + 1)
}
if (cursor.li) {
body.push(`<ul>`)
const closing = tokens.findIndex(token => !token.li)
body = body.concat(tokens.slice(0, closing).map(line))
body.push("</ul>")
tokens = tokens.slice(closing + 1)
}
body.push(line(cursor))
cursor = tokens.shift()
}
return body.join("\n")
}
function line({ text, href, title, pre, alt, h1, h2, h3, li, quote }) {
if (text) return `<p>${text}</p>`;
if (href) return `<a href="${href}">${title || href}</a>`;
if (h1) return `<h1>${h1}</h1>`;
if (h2) return `<h2>${h2}</h2>`;
if (h3) return `<h3>${h3}</h3>`;
if (li) return `<li>${li}</li>`;
if (quote) return `<blockquote>${quote}</blockquote>`;
return `<p><br></p>`;
}

View file

@ -4,7 +4,6 @@ module.exports = (file, cb) => {
if (!GMI_EXT.test(file.path)) return cb(null, file);
file.path = file.path.replace(GMI_EXT, ".tokens.json");
console.log(`tokenizing ${file.path}`);
file.contents = Buffer.from(
JSON.stringify(
file.contents