trial-by-jury-book/edit-chapter.go
2023-08-03 19:19:07 -06:00

108 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is all because I don't want to deal with double-escaping regex special
// characters in sh.
package main
import (
"bytes"
"fmt"
"os"
"regexp"
)
func mapSlice[A, B any](f func(A) B, a []A) []B {
b := make([]B, len(a))
for i := range b {
b[i] = f(a[i])
}
return b
}
type Replacer struct {
re *regexp.Regexp
replacement string
}
func compile(raw [2]string) Replacer {
return Replacer{
re: regexp.MustCompile(raw[0]),
replacement: raw[1],
}
}
var replacers = mapSlice(compile, [][2]string{
// Chapter titles
{`CHAPTER [IVX]+\.` + "\n\n" + `(.*)\.`, `# $1`},
// Section titles
{`(?ms)SECTION [IVX]+\.\n\n_([^_]+)\._`, `## $1`},
// Untitled sections
{`SECTION [IVX]+\.`, `\section{}`},
// Em dashes
{"--", "—"},
// Left double typographical quote
{`"(\w|_\w)`, `“$1`},
// Right double typographical quote
{`"`, ``},
// Left single typographical quote
{`([^\pL])'(\pL|_)`, `$1$2`},
{`(?m)^'`, ``},
// Right single typographical quote
{`'`, ``},
// Block quotes
{`(?m)^ +(\S)`, `> $1`},
// Footnote superscript
{`\[(\d+)\]`, `[^$1]`},
})
var footnoteRE = regexp.MustCompile(`\[Footnote \d+: ([^\[\]]|(\[\^\d+\]))+\]`)
var footnoteNumberRE = regexp.MustCompile(`\[Footnote (\d+):`)
func replaceFootnote(src []byte) []byte {
var formatted = footnoteNumberRE.ReplaceAll(src, []byte("[^$1]:"))
// Indent footnote paragraphs.
// This only works because footnotes are stacked at the end of each chapter.
formatted = bytes.ReplaceAll(formatted, []byte("\n"), []byte("\n "))
// Strip terminal "]".
return formatted[:len(formatted)-1]
}
func run() error {
if len(os.Args) != 3 {
fmt.Fprintf(os.Stderr, "usage: %s <infile> <outfile>\n", os.Args[0])
os.Exit(64) // command line usage error
}
inpath := os.Args[1]
outpath := os.Args[2]
text, err := os.ReadFile(inpath)
if err != nil {
return err
}
for _, r := range replacers {
text = r.re.ReplaceAll(text, []byte(r.replacement))
}
text = footnoteRE.ReplaceAllFunc(text, replaceFootnote)
err = os.WriteFile(outpath, text, 0666)
if err != nil {
return err
}
return nil
}
func main() {
err := run()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}