rivit2html/main.go
Judah Caruso a3c6e4aeb5 init
2026-01-25 22:39:40 -07:00

178 lines
3.3 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)
if len(args) < 1 {
fmt.Fprintf(os.Stderr, "usage: %s [file.riv] [file.html]\n", exe)
return
}
inpath := args[0]
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, "<", "&lt;")
l = strings.ReplaceAll(l, ">", "&gt;")
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()
}