summaryrefslogtreecommitdiff
path: root/vrsite/static.go
diff options
context:
space:
mode:
Diffstat (limited to 'vrsite/static.go')
-rw-r--r--vrsite/static.go50
1 files changed, 45 insertions, 5 deletions
diff --git a/vrsite/static.go b/vrsite/static.go
index 7d31b1d..b299975 100644
--- a/vrsite/static.go
+++ b/vrsite/static.go
@@ -13,6 +13,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"sync"
"time"
@@ -31,7 +32,7 @@ func run(dir string, name string, args ...string) []byte {
return out
}
-func buildSite(logPath, repoAbs, out, title string, theme, light *Theme) {
+func buildSite(logPath, repoAbs, out, title string, theme, light *Theme, themes *themeSet) {
start := time.Now()
entries := readLog(logPath)
ranked := buildModel(title, entries, "").Ranked
@@ -80,7 +81,7 @@ func buildSite(logPath, repoAbs, out, title string, theme, light *Theme) {
fatal("tar: %v", err)
}
- writeSite(site, out, tmp)
+ writeSite(site, out, tmp, themes)
stubs := 0
for _, f := range site.All {
if f.Stub != "" {
@@ -92,8 +93,12 @@ func buildSite(logPath, repoAbs, out, title string, theme, light *Theme) {
time.Since(start).Round(time.Millisecond), out)
}
-func writeSite(site *Site, out, srcDir string) {
- tpl := newTemplates()
+func writeSite(site *Site, out, srcDir string, themes *themeSet) {
+ if themes == nil {
+ themes = &themeSet{}
+ }
+ hl := newHighlighter(site.Theme, site.Light)
+ tpl := newTemplates(hl)
if err := os.MkdirAll(out, 0o755); err != nil {
fatal("%v", err)
}
@@ -113,7 +118,6 @@ func writeSite(site *Site, out, srcDir string) {
}
// phase A: content — coverage percentages must exist before any tree
// or index below is written
- hl := newHighlighter(site.Theme, site.Light)
each(func(f *File) {
src, err := os.ReadFile(filepath.Join(srcDir, f.Path))
switch {
@@ -142,6 +146,13 @@ func writeSite(site *Site, out, srcDir string) {
fatal("%v", err)
}
}
+ // the picker travels with the export: a <script src>/<link> pair loads
+ // from the filesystem, which is why the menu is a script and not JSON
+ for name, b := range map[string][]byte{"themes.css": themes.CSS, "themes.js": themes.JS} {
+ if err := os.WriteFile(filepath.Join(out, name), b, 0o644); err != nil {
+ fatal("%v", err)
+ }
+ }
// shared tree fragment: the only nav tree, fetched by every page; "@@" is
// replaced with the page root by app.js, since the fragment is fetched
@@ -196,6 +207,35 @@ func writeSite(site *Site, out, srcDir string) {
render(dst, &page{Kind: "file", Title: f.Path + " — " + site.Title,
Root: strings.Repeat("../", depth), Current: f.Path, File: f})
})
+
+ // phase C: a page per note, so a permalink handed to someone else opens
+ // in the export exactly as it does in the live app. The source is read
+ // again rather than kept from phase A: an export is a batch job, and the
+ // alternative is holding every file in memory for the sake of a few
+ // hundred excerpts.
+ if err := os.MkdirAll(filepath.Join(out, "note"), 0o755); err != nil {
+ fatal("%v", err)
+ }
+ for _, n := range site.Notes {
+ p := &page{Kind: "note", Title: noteTitle(n) + " — " + site.Title,
+ Root: "../", Current: n.File, Note: n, Thread: site.NoteThread(n.ID)}
+ if n.File != "" && n.Start > 0 {
+ src, err := os.ReadFile(filepath.Join(srcDir, n.File))
+ switch {
+ case err != nil:
+ p.ExErr = "not present in the archived commit"
+ case bytes.IndexByte(src, 0) >= 0:
+ p.ExErr = "binary file — not rendered"
+ default:
+ var cov []uint8
+ if f, ok := site.Files[n.File]; ok {
+ cov = f.Cov
+ }
+ p.Excerpt, p.ExFrom, p.ExTo = excerptFor(n.File, src, cov, hl, n)
+ }
+ }
+ render(filepath.Join(out, "note", strconv.Itoa(n.ID)+".html"), p)
+ }
}
func mustCreate(path string) *os.File {