From 8276f6bcb97be2a2ab0c76de1135517a3b97dc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Tue, 22 Jun 2021 01:57:15 +0200 Subject: [PATCH] hswg: an initial attempt at refactoring main() --- hswg/main.go | 233 +++++++++++++++++++++++++++++---------------------- 1 file changed, 131 insertions(+), 102 deletions(-) diff --git a/hswg/main.go b/hswg/main.go index 5076bd1..a23e343 100644 --- a/hswg/main.go +++ b/hswg/main.go @@ -187,6 +187,127 @@ func expand(m *map[string]*Entry, name string, chunk []byte) []byte { }) } +var tagRE = regexp.MustCompile(`<[^<>]+>`) + +func renderEntry(name string, entries *map[string]*Entry) error { + e := (*entries)[name] + + f, err := os.Open(e.PathSource) + if err != nil { + return err + } + + if i, err := f.Stat(); err != nil { + return err + } else { + e.mtime = i.ModTime() + } + + var html *bytes.Buffer + if html, e.Metadata, err = Render(f, configuration.NewConfiguration( + configuration.WithFilename(e.PathSource), + configuration.WithLastUpdated(e.mtime), + )); err != nil { + return err + } + + // Every page needs to have a title. + if e.Title == "" { + e.Title = name + } + + // Expand LinkWords anywhere between . + // We want something like the inverse of Regexp.ReplaceAllStringFunc. + raw, last, expanded := html.Bytes(), 0, bytes.NewBuffer(nil) + for _, where := range tagRE.FindAllIndex(raw, -1) { + _, _ = expanded.Write(expand(entries, name, raw[last:where[0]])) + _, _ = expanded.Write(raw[where[0]:where[1]]) + last = where[1] + } + _, _ = expanded.Write(expand(entries, name, raw[last:])) + e.Content = template.HTML(expanded.String()) + return nil +} + +func loadEntries(globs []string) (map[string]*Entry, error) { + // Create a map from document names to their page entries. + entries := map[string]*Entry{} + for _, glob := range globs { + matches, err := filepath.Glob(glob) + if err != nil { + return nil, fmt.Errorf("%s: %s\n", glob, err) + } + for _, path := range matches { + name := stripExtension(filepath.Base(path)) + if conflict, ok := entries[name]; ok { + return nil, fmt.Errorf("%s: conflicts with %s\n", + name, conflict.PathSource) + } + entries[name] = &Entry{ + PathSource: path, + PathDestination: resultPath(path), + backlinks: map[string]bool{}, + } + } + } + + for name := range entries { + if err := renderEntry(name, &entries); err != nil { + return nil, err + } + } + return entries, nil +} + +func writeEntry(e *Entry, t *template.Template, + entries *map[string]*Entry) error { + f, err := os.Create(e.PathDestination) + if err != nil { + return err + } + + backlinks := []string{} + for name := range e.backlinks { + backlinks = append(backlinks, name) + } + sort.Strings(backlinks) + for _, name := range backlinks { + e.Backlinks = + append(e.Backlinks, template.HTML(makeLink(entries, name))) + } + + return t.Execute(f, e) +} + +func writeIndex(t *template.Template, entries *map[string]*Entry) error { + // Reorder entries reversely, primarily by date, secondarily by filename. + ordered := []*Entry{} + for _, e := range *entries { + ordered = append(ordered, e) + } + + sort.Slice(ordered, func(i, j int) bool { + a, b := ordered[i], ordered[j] + p1, p2 := a.Published(), b.Published() + if p1 == nil && p2 != nil { + return true + } + if p1 == nil && p2 == nil { + return a.PathSource > b.PathSource + } + if p2 == nil { + return false + } + if p1.Equal(*p2) { + return a.PathSource > b.PathSource + } + return p2.Before(*p1) + }) + + // TODO(p): Splitting content to categories would be nice. + return t.Execute(os.Stdout, ordered) +} + func singleFile() { html, meta, err := Render(os.Stdin, configuration.NewConfiguration()) if err != nil { @@ -213,124 +334,32 @@ func main() { if err != nil { log.Fatalln(err) } - t, err := template.New("page").Parse(string(header)) if err != nil { log.Fatalln(err) } - // Create a map from document names to their page entries. - entries := map[string]*Entry{} - for _, glob := range os.Args[2:] { - matches, err := filepath.Glob(glob) - if err != nil { - log.Fatalf("%s: %s\n", glob, err) - } - for _, path := range matches { - name := stripExtension(filepath.Base(path)) - if conflict, ok := entries[name]; ok { - log.Fatalf("%s: conflicts with %s\n", name, conflict.PathSource) - } - entries[name] = &Entry{ - PathSource: path, - PathDestination: resultPath(path), - backlinks: map[string]bool{}, - } - } + // Process all entries. + entries, err := loadEntries(os.Args[2:]) + if err != nil { + log.Fatalln(err) } - - tagRE := regexp.MustCompile(`<[^<>]+>`) - for name, e := range entries { - f, err := os.Open(e.PathSource) - if err != nil { - log.Fatalln(err) - } - - if i, err := f.Stat(); err != nil { - log.Fatalln(err) - } else { - e.mtime = i.ModTime() - } - - var html *bytes.Buffer - if html, e.Metadata, err = Render(f, configuration.NewConfiguration( - configuration.WithFilename(e.PathSource), - configuration.WithLastUpdated(e.mtime), - )); err != nil { - log.Fatalln(err) - } - - // Every page needs to have a title. - if e.Title == "" { - e.Title = name - } - - // Expand LinkWords anywhere between . - // We want something like the inverse of Regexp.ReplaceAllStringFunc. - raw, last, expanded := html.Bytes(), 0, bytes.NewBuffer(nil) - for _, where := range tagRE.FindAllIndex(raw, -1) { - _, _ = expanded.Write(expand(&entries, name, raw[last:where[0]])) - _, _ = expanded.Write(raw[where[0]:where[1]]) - last = where[1] - } - _, _ = expanded.Write(expand(&entries, name, raw[last:])) - e.Content = template.HTML(expanded.String()) - } - for _, e := range entries { - f, err := os.Create(e.PathDestination) - if err != nil { - log.Fatalln(err) - } - - backlinks := []string{} - for name := range e.backlinks { - backlinks = append(backlinks, name) - } - sort.Strings(backlinks) - for _, name := range backlinks { - e.Backlinks = - append(e.Backlinks, template.HTML(makeLink(&entries, name))) - } - - if err = t.Execute(f, e); err != nil { + if err := writeEntry(e, t, &entries); err != nil { log.Fatalln(err) } } - // Reorder entries reversely, primarily by date, secondarily by filename. - ordered := []*Entry{} - for _, e := range entries { - ordered = append(ordered, e) - } - - sort.Slice(ordered, func(i, j int) bool { - a, b := ordered[i], ordered[j] - p1, p2 := a.Published(), b.Published() - if p1 == nil && p2 != nil { - return true - } - if p1 == nil && p2 == nil { - return a.PathSource > b.PathSource - } - if p2 == nil { - return false - } - if p1.Equal(*p2) { - return a.PathSource > b.PathSource - } - return p2.Before(*p1) - }) - - // Execute a template from the standard input. + // Read a template from the standard input, write an index. var input []byte if input, err = ioutil.ReadAll(os.Stdin); err != nil { log.Fatalln(err) } - - // TODO(p): Splitting content to categories would be nice. t, err = template.New("-").Parse(string(input)) - if err = t.Execute(os.Stdout, ordered); err != nil { + if err != nil { + log.Fatalln(err) + } + if err := writeIndex(t, &entries); err != nil { log.Fatalln(err) } }