{{ .ID }}. {{ .Title }}
+ {{ if .Extra }} + {{ .Text | htmlify }} + {{ else }} +-
+ {{ range .Rules }}
+
- ({{ .ID }}) {{ .Text | htmlify }} + {{ end }} +
diff --git a/main.go b/main.go index f557261..0c7746f 100644 --- a/main.go +++ b/main.go @@ -17,13 +17,30 @@ const ( // TemplateData is the data that is filled and passed to the HTML template type TemplateData struct { - Title string - CSSFile string - Credits string + Title string + Credits string + Sections []*TemplateSection +} + +// TemplateSection is a section of the rules +type TemplateSection struct { + ID string + Title string + Extra bool + Rules []TemplateRule + Text string +} + +// TemplateRule is a single rule +type TemplateRule struct { + ID string + Text string + Depth int } var funmap = template.FuncMap{ - "htmlify": tplHtmlify, + "toCredits": tplToCredits, + "htmlify": tplHtmlify, } // HTMLrocCredits is the credit string to append to the other credits @@ -33,15 +50,12 @@ func main() { txtfile := flag.String("in", "rules.txt", "Path to rules.txt file") tplfile := flag.String("template", "template.html", "Path to template file") outname := flag.String("out", "out.html", "Output file") - style := flag.String("css", "style.css", "Name of the CSS stylesheet") // Read template file tpl, err := template.New(*tplfile).Funcs(funmap).ParseFiles(*tplfile) checkErr(err, "Could not load template file \"%s\"", *tplfile) - tpldata := TemplateData{ - CSSFile: *style, - } + tpldata := TemplateData{} // Read rules file filebytes, err := ioutil.ReadFile(*txtfile) @@ -74,12 +88,73 @@ func main() { // Every rule is a line (pretty handy!) lines := strings.Split(filestr, "\n") + var currentSection *TemplateSection for _, line := range lines { + // Trim line (used for several purposes) + trimmed := strings.TrimSpace(line) + // Skip empty lines - line = strings.TrimSpace(line) - if len(line) < 1 { + if len(trimmed) < 1 { continue } + + // All rules begin with "(ID)" + isRule := trimmed[0] == '(' + + // All sections begin with "N. " + // for sake of not making this check extra complicated we're going to + // assume it has to be within the first 5 characters + isSection := strings.Index(trimmed[:5], ". ") > 0 + + // Calculate depth based on number of whitespace (/2) + depth := len(line) - len(trimmed) + + switch { + // It's a section + case isSection: + parts := strings.SplitN(trimmed, ". ", 2) + if len(parts) < 2 { + // ??? + fmt.Fprintf(os.Stderr, "Found unexpected line: \"%s\"\n", trimmed) + continue + } + // Create new section + currentSection = &TemplateSection{ + ID: parts[0], + Title: parts[1], + Rules: []TemplateRule{}, + Extra: false, + } + tpldata.Sections = append(tpldata.Sections, currentSection) + + // It's a new rule + case isRule: + + // ID is between ()s + endID := strings.IndexRune(trimmed, ')') + if endID < 0 { + // ??? + fmt.Fprintf(os.Stderr, "Found unexpected or malformed line: \"%s\"\n", trimmed) + continue + } + + currentSection.Rules = append(currentSection.Rules, TemplateRule{ + ID: trimmed[1:endID], + Text: strings.TrimSpace(trimmed[endID+1:]), + Depth: depth, + }) + + // It's something else + default: + // If there is at least a rule, assume it's a continuation of the last rule + if len(currentSection.Rules) > 0 { + currentSection.Rules[len(currentSection.Rules)-1].Text += "\n" + line + } else { + // No rules? Might be an extra + currentSection.Extra = true + currentSection.Text += line + "\n" + } + } } // Create output file @@ -99,13 +174,19 @@ func checkErr(err error, fmtstr string, args ...interface{}) { } } -func tplHtmlify(str string) template.HTML { +func tplToCredits(str string) template.HTML { // Make first line an heading idx := strings.IndexRune(str, '\n') if idx > 0 { - str = "
" + str[idx+1:] } - // Replace newlines with HTML line-break tag + // Wrap other lines in
tags + str = strings.ReplaceAll(str, "\n", "
") + "
" + return template.HTML(str) +} + +func tplHtmlify(str string) template.HTML { + // Replace newlines with