diff options
author | kaa <kaa@disroot.org> | 2023-11-17 17:42:44 -0800 |
---|---|---|
committer | kaa <kaa@disroot.org> | 2023-11-17 17:42:44 -0800 |
commit | 0a6cbfa6b91ffdb227364a6ca812bc329dfb6126 (patch) | |
tree | 9a180c988089be15c21e6f563067a59ba0c3e000 |
Initial.
-rw-r--r-- | ref.go | 167 |
1 files changed, 167 insertions, 0 deletions
@@ -0,0 +1,167 @@ +package main + +import ( + "fmt" + "log" + "os" + "strings" + "sort" + "io" +) + +const ( + bufsize = 512 + prefix = `.\"s ` + end = `.\"e` + section = `.\"ยง` + tableHead = ".TS\nexpand;\nl1w(1.5i) l1w(4.5i)." + tableFoot = ".TE" + mac = ".ref" + delim = "()" + extraPrefix = `\fC` + extraSuffix = `\fP` +) + +type Reference struct { + name string + contents string + index int +} + +func getRefTxt(lines []string) string { + var txt string + for _, line := range lines { + if strings.HasPrefix(line, end) { + break + } + txt += line + "\n" + } + return string(txt) +} + +func findIndex(refs []Reference, name string) int { + for _, ref := range refs { + if ref.name == name { + return ref.index + } + } + return -1 +} + +func checkLetter(ch rune) bool { + if ch >= 'A' && ch <= 'Z' || + ch >= 'a' && ch <= 'z' { + return true + } + return false +} + +func checkAllCaps(word string) bool { + for _, ch := range word { + if !checkLetter(ch) { + continue + } + if ch < 'A' || ch > 'Z' { + return false + } + } + return true +} +// Typographic niceties. +func extraFmt(ref string) string { + words := strings.Split(ref, " ") + if checkAllCaps(words[0]) { + words[0] = extraPrefix + words[0] + extraSuffix + } + words[1] = extraPrefix + words[1] + extraSuffix + + return words[0] + " " + words[1] +} + +func main() { + in := os.Stdin + if len(os.Args) > 1 { + var err error + in, err = os.Open(os.Args[1]) + if err != nil { + log.Fatal(err) + } + } + + bytes, err := io.ReadAll(in) + if err != nil { + log.Fatal(err) + } + contents := string(bytes) + + /* Iterate through the contents of the file twice: + Once to find and index all references. + Again to refer to each reference. */ + var refs []Reference + div := -1 + lines := strings.Split(contents, "\n") + for i, line := range lines { + if line == section { + div = i + } + } + // If no split, quietly return contents. + if div == -1 { + fmt.Print(contents) + return + } + + for i, line := range lines[div:] { + if strings.HasPrefix(line, prefix) { + var ref Reference + ref.name = line[len(prefix):] + // i is relative to the lines after div. + ref.contents = getRefTxt(lines[div+i+1:]) + refs = append(refs, ref) + } + } + + /* Sort references alphabetically. */ + sort.Slice(refs, func(i, j int) bool { + return strings.Compare(refs[i].name, refs[j].name) < 0 + }) + + for i := range refs { + refs[i].index = i + } + + // Second pass. + for _, line := range lines[:div] { + if strings.HasPrefix(line, mac) { + var name string + var start, end int + for i := range line { + if line[i] == delim[0] { + start = i+1 + } + if line[i] == delim[1] { + end = i + break + } + } + name = line[start:end] + index := findIndex(refs, name) + fmt.Printf(".post.url #%d \"%s\"\n\n", index, + extraFmt(line[start-1:])) + } else { + fmt.Println(line) + } + } + + // Format References into AMS Style bibiography. + /* As it turns out, in order to be referenced individually, + each reference needs its own table. */ + for _, ref := range refs { + fmt.Printf(".post.name %d\n", ref.index) + fmt.Println(tableHead) + fmt.Printf("T{\n%c%s%c\nT}", delim[0], extraFmt(ref.name), + delim[1]) + fmt.Printf("\tT{\n%s\nT}\n", ref.contents) + fmt.Println(tableFoot) + } +} |