189 lines
3.4 KiB
Go
189 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/judah-caruso/rivit"
|
|
)
|
|
|
|
func main() {
|
|
exe, args := os.Args[0], os.Args[1:]
|
|
exe = filepath.Base(exe)
|
|
|
|
usage := func() {
|
|
fmt.Fprintf(os.Stderr, "usage: %s [file.riv] [file.html]\n", exe)
|
|
}
|
|
|
|
if len(args) < 1 {
|
|
usage()
|
|
return
|
|
}
|
|
|
|
inpath := args[0]
|
|
for _, arg := range args {
|
|
if arg == "-h" || arg == "--help" {
|
|
usage()
|
|
return
|
|
}
|
|
}
|
|
|
|
file, err := os.ReadFile(inpath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "error reading file: %v\n", err)
|
|
return
|
|
}
|
|
|
|
outpath := inpath
|
|
if len(args) > 1 {
|
|
outpath = args[1]
|
|
}
|
|
|
|
if filepath.Ext(outpath) == ".riv" {
|
|
outpath = outpath[:len(outpath)-len(filepath.Ext(outpath))] + ".html"
|
|
}
|
|
|
|
riv := rivit.Parse(string(file))
|
|
|
|
var (
|
|
out strings.Builder
|
|
title string
|
|
)
|
|
for _, line := range riv {
|
|
if kind := line.Kind(); kind == rivit.LineNavLink {
|
|
continue
|
|
}
|
|
|
|
switch line := line.(type) {
|
|
default:
|
|
continue
|
|
|
|
case rivit.Header:
|
|
text := strings.Title(strings.ToLower(string(line)))
|
|
if out.Len() == 0 {
|
|
title = text
|
|
fmt.Fprintf(&out, "<h1>%s</h1>", text)
|
|
} else {
|
|
fmt.Fprintf(&out, "<h2>%s</h2>", text)
|
|
}
|
|
|
|
case rivit.Paragraph:
|
|
if len(line) == 0 && line[0].Value == ". . ." {
|
|
fmt.Fprintf(&out, "<hr/>")
|
|
} else {
|
|
fmt.Fprintf(&out, "<p>%s</p>", text2html(line))
|
|
}
|
|
|
|
case rivit.List:
|
|
fmt.Fprint(&out, list2html(line))
|
|
|
|
case rivit.Block:
|
|
out.WriteString("<pre><code>")
|
|
|
|
for i, v := range line.Body {
|
|
l := v[line.Indent:]
|
|
l = strings.ReplaceAll(l, "<", "<")
|
|
l = strings.ReplaceAll(l, ">", ">")
|
|
|
|
out.WriteString(l)
|
|
|
|
if i < len(line.Body) {
|
|
out.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
out.WriteString("</code></pre>")
|
|
}
|
|
}
|
|
|
|
html := fmt.Sprintf(`
|
|
<html>
|
|
<head>
|
|
<title>%s</title>
|
|
<style>
|
|
html {
|
|
color-scheme: light dark;
|
|
}
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
padding: 0 15px;
|
|
max-width: 650px;
|
|
font-size: 115%%;
|
|
line-height: 1.4;
|
|
}
|
|
h1, h2 {
|
|
font-weight: bold;
|
|
margin-bottom: 0px;
|
|
border-bottom: 1px solid;
|
|
}
|
|
p {
|
|
text-align: justify;
|
|
}
|
|
pre {
|
|
padding-left: 20px;
|
|
}
|
|
pre code {
|
|
white-space: pre-wrap;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
%s
|
|
</body>
|
|
</html>
|
|
`, title, out.String())
|
|
|
|
if err := os.WriteFile(outpath, []byte(html), 0644); err != nil {
|
|
fmt.Fprintf(os.Stderr, "error writing file: %v\n", err)
|
|
return
|
|
}
|
|
|
|
fmt.Fprintf(os.Stdout, "wrote %s\n", outpath)
|
|
}
|
|
|
|
func text2html(text []rivit.StyledText) string {
|
|
var out strings.Builder
|
|
|
|
for _, t := range text {
|
|
switch t.Style {
|
|
default:
|
|
continue
|
|
|
|
case rivit.StyleNone:
|
|
out.WriteString(t.Value)
|
|
case rivit.StyleItalic:
|
|
fmt.Fprintf(&out, "<i>%s</i>", t.Value)
|
|
case rivit.StyleBold:
|
|
fmt.Fprintf(&out, "<b>%s</b>", t.Value)
|
|
case rivit.StyleMono:
|
|
fmt.Fprintf(&out, "<code>%s</code>", t.Value)
|
|
case rivit.StyleExternalLink:
|
|
display := t.Value
|
|
if len(display) == 0 {
|
|
display = t.Link
|
|
}
|
|
|
|
fmt.Fprintf(&out, "<a href=%q>%s</a>", t.Link, display)
|
|
}
|
|
}
|
|
|
|
return out.String()
|
|
}
|
|
|
|
func list2html(list rivit.List) string {
|
|
var out strings.Builder
|
|
|
|
fmt.Fprintf(&out, "<ul>")
|
|
for _, item := range list {
|
|
fmt.Fprintf(&out, "<li>%s", text2html(item.Value))
|
|
if len(item.Sublist) != 0 {
|
|
out.WriteString(list2html(item.Sublist))
|
|
}
|
|
out.WriteString("</li>")
|
|
}
|
|
fmt.Fprintf(&out, "</ul>")
|
|
|
|
return out.String()
|
|
}
|