Basic version that works

This commit is contained in:
Hamcha 2019-06-14 00:03:45 +02:00
parent cab8022414
commit 514522950a
Signed by: hamcha
GPG key ID: A40413D21021EAEE
4 changed files with 160 additions and 20 deletions

101
main.go
View file

@ -18,11 +18,28 @@ const (
// TemplateData is the data that is filled and passed to the HTML template // TemplateData is the data that is filled and passed to the HTML template
type TemplateData struct { type TemplateData struct {
Title string Title string
CSSFile string
Credits 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{ var funmap = template.FuncMap{
"toCredits": tplToCredits,
"htmlify": tplHtmlify, "htmlify": tplHtmlify,
} }
@ -33,15 +50,12 @@ func main() {
txtfile := flag.String("in", "rules.txt", "Path to rules.txt file") txtfile := flag.String("in", "rules.txt", "Path to rules.txt file")
tplfile := flag.String("template", "template.html", "Path to template file") tplfile := flag.String("template", "template.html", "Path to template file")
outname := flag.String("out", "out.html", "Output file") outname := flag.String("out", "out.html", "Output file")
style := flag.String("css", "style.css", "Name of the CSS stylesheet")
// Read template file // Read template file
tpl, err := template.New(*tplfile).Funcs(funmap).ParseFiles(*tplfile) tpl, err := template.New(*tplfile).Funcs(funmap).ParseFiles(*tplfile)
checkErr(err, "Could not load template file \"%s\"", *tplfile) checkErr(err, "Could not load template file \"%s\"", *tplfile)
tpldata := TemplateData{ tpldata := TemplateData{}
CSSFile: *style,
}
// Read rules file // Read rules file
filebytes, err := ioutil.ReadFile(*txtfile) filebytes, err := ioutil.ReadFile(*txtfile)
@ -74,12 +88,73 @@ func main() {
// Every rule is a line (pretty handy!) // Every rule is a line (pretty handy!)
lines := strings.Split(filestr, "\n") lines := strings.Split(filestr, "\n")
var currentSection *TemplateSection
for _, line := range lines { for _, line := range lines {
// Trim line (used for several purposes)
trimmed := strings.TrimSpace(line)
// Skip empty lines // Skip empty lines
line = strings.TrimSpace(line) if len(trimmed) < 1 {
if len(line) < 1 {
continue 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 // 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 // Make first line an heading
idx := strings.IndexRune(str, '\n') idx := strings.IndexRune(str, '\n')
if idx > 0 { if idx > 0 {
str = "<h1>" + str[:idx] + "</h1>" + str[idx:] str = "<h1>" + str[:idx] + "</h1><p>" + str[idx+1:]
} }
// Replace newlines with HTML line-break tag // Wrap other lines in <p> tags
str = strings.ReplaceAll(str, "\n", "</p><p>") + "</p>"
return template.HTML(str)
}
func tplHtmlify(str string) template.HTML {
// Replace newlines with <br />
str = strings.ReplaceAll(str, "\n", "<br />") str = strings.ReplaceAll(str, "\n", "<br />")
return template.HTML(str) return template.HTML(str)
} }

View file

@ -1 +0,0 @@
package main

View file

@ -0,0 +1,46 @@
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400&display=swap');
body {
font-family: 'Roboto', sans-serif;
font-weight: 300;
display: flex;
justify-content: center;
font-size: 11pt;
}
main {
flex: 1;
max-width: 60em;
}
h1,
h2 {
color: #4b5b69;
font-weight: 400;
}
p {
margin: 0;
padding: 2pt 0;
}
ul {
padding-left: 10pt;
}
li {
margin: 10pt 0;
list-style-type: none;
}
.depth-2 {
padding-left: 20pt;
}
.depth-4 {
padding-left: 40pt;
}
.depth-6 {
padding-left: 60pt;
}

View file

@ -3,15 +3,29 @@
<head> <head>
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
{{ if .CSSFile }} <link rel="stylesheet" href="style.css">
<link href="{{ .CSSFile }}" rel="stylesheet" />
{{ end }}
</head> </head>
<body> <body>
<main>
<header class="credits"> <header class="credits">
{{ .Credits | htmlify }} {{ .Credits | toCredits }}
</header> </header>
<section class="rules">
{{ range .Sections }}
<h2 id="{{ .ID }}">{{ .ID }}. {{ .Title }}</h2>
{{ if .Extra }}
{{ .Text | htmlify }}
{{ else }}
<ul>
{{ range .Rules }}
<li id="{{ .ID }}" class="depth-{{ .Depth }}">({{ .ID }}) {{ .Text | htmlify }}</li>
{{ end }}
</ul>
{{ end }}
{{ end }}
</section>
</main>
</body> </body>
</html> </html>