summaryrefslogtreecommitdiff
path: root/gopher
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-09-01 12:37:42 -0600
committertjpcc <tjp@ctrl-c.club>2023-09-01 12:37:42 -0600
commita61bcdeb314d4e0e9f6e8915b92010895170e785 (patch)
tree29611d33a0e65f334c7238a7748244ab63ad0d5c /gopher
parent2ce5be68acd3c66d4d135d7eb68b9ecd1563aa1d (diff)
refactor gophermap template handling and add markdown conversion
Diffstat (limited to 'gopher')
-rw-r--r--gopher/gophermap/htmlconv/convert.go135
-rw-r--r--gopher/gophermap/internal/templates.go153
-rw-r--r--gopher/gophermap/mdconv/convert.go52
-rw-r--r--gopher/gophermap/mdconv/convert_test.go69
4 files changed, 278 insertions, 131 deletions
diff --git a/gopher/gophermap/htmlconv/convert.go b/gopher/gophermap/htmlconv/convert.go
index a669601..8fa2f52 100644
--- a/gopher/gophermap/htmlconv/convert.go
+++ b/gopher/gophermap/htmlconv/convert.go
@@ -1,13 +1,11 @@
package htmlconv
import (
- "bytes"
"html/template"
"io"
- "strings"
"tildegit.org/tjp/sliderule/gopher"
- "tildegit.org/tjp/sliderule/internal/types"
+ "tildegit.org/tjp/sliderule/gopher/gophermap/internal"
)
// Convert writes html to a writer from the provided gophermap document.
@@ -32,13 +30,13 @@ func Convert(wr io.Writer, doc gopher.MapDocument, overrides *template.Template)
return err
}
- tmpl, err = addOverrides(tmpl, overrides)
+ tmpl, err = internal.AddHTMLOverrides(tmpl, overrides)
if err != nil {
return err
}
- for _, item := range renderItems(doc) {
- if err := tmpl.ExecuteTemplate(wr, item.template, item.object); err != nil {
+ for _, item := range internal.RenderItems(doc) {
+ if err := tmpl.ExecuteTemplate(wr, item.Template, item.Object); err != nil {
return err
}
}
@@ -46,131 +44,6 @@ func Convert(wr io.Writer, doc gopher.MapDocument, overrides *template.Template)
return nil
}
-type renderItem struct {
- template string
- object any
-}
-
-type renderRef struct {
- Type types.Status
- Display string
- Selector template.URL
- Hostname string
- Port string
-}
-
-func refItem(item gopher.MapItem) renderRef {
- return renderRef{
- Type: item.Type,
- Display: item.Display,
- Selector: template.URL(item.Selector),
- Hostname: item.Hostname,
- Port: item.Port,
- }
-}
-
-func renderItems(doc gopher.MapDocument) []renderItem {
- out := make([]renderItem, 0, len(doc))
- out = append(out, renderItem{
- template: "header",
- object: doc,
- })
- inMsg := false
- msg := &bytes.Buffer{}
- var currentHost, currentPort string
-
- for _, mapItem := range doc {
- switch mapItem.Type {
- case gopher.InfoMessageType:
- if inMsg {
- _, _ = msg.WriteString("\n")
- } else {
- msg.Reset()
- }
- _, _ = msg.WriteString(mapItem.Display)
- inMsg = true
-
- if currentHost == "" {
- currentHost = mapItem.Hostname
- }
- if currentPort == "" {
- currentPort = mapItem.Port
- }
- case gopher.GifFileType, gopher.ImageFileType, gopher.BitmapType, gopher.PngImageFileType:
- if inMsg {
- out = append(out, renderItem{
- template: "message",
- object: msg.String(),
- })
- inMsg = false
- }
- out = append(out, renderItem{
- template: "image",
- object: refItem(mapItem),
- })
- default:
- if inMsg {
- out = append(out, renderItem{
- template: "message",
- object: msg.String(),
- })
- inMsg = false
- }
- out = append(out, renderItem{
- template: "link",
- object: refItem(mapItem),
- })
- }
- }
-
- if inMsg {
- out = append(out, renderItem{
- template: "message",
- object: msg.String(),
- })
- }
-
- simplifyLinks(out, currentHost, currentPort)
-
- return append(out, renderItem{
- template: "footer",
- object: doc,
- })
-}
-
-func simplifyLinks(items []renderItem, currentHost, currentPort string) {
- for i, item := range items {
- if item.template != "link" && item.template != "image" {
- continue
- }
-
- m := item.object.(renderRef)
- if m.Hostname == currentHost && m.Port == currentPort {
- m.Hostname = ""
- m.Port = ""
- m.Selector = template.URL(strings.TrimPrefix(string(m.Selector), "URL:"))
- items[i].object = m
- }
- }
-}
-
-func addOverrides(base *template.Template, overrides *template.Template) (*template.Template, error) {
- if overrides == nil {
- return base, nil
- }
-
- tmpl := base
- var err error
- for _, override := range overrides.Templates() {
- tmpl, err = tmpl.AddParseTree(override.Name(), override.Tree)
- if err != nil {
- return nil, err
- }
- }
-
- return tmpl, nil
-}
-
var baseTmpl = template.Must(template.New("htmlconv").Parse(`
{{ define "header" -}}
<!DOCTYPE html>
diff --git a/gopher/gophermap/internal/templates.go b/gopher/gophermap/internal/templates.go
new file mode 100644
index 0000000..cc8ba14
--- /dev/null
+++ b/gopher/gophermap/internal/templates.go
@@ -0,0 +1,153 @@
+package internal
+
+import (
+ "bytes"
+ "text/template"
+ htemplate "html/template"
+ "strings"
+
+ "tildegit.org/tjp/sliderule/gopher"
+ "tildegit.org/tjp/sliderule/internal/types"
+)
+
+type renderItem struct {
+ Template string
+ Object any
+}
+
+type renderRef struct {
+ Type types.Status
+ Display string
+ Selector htemplate.URL
+ Hostname string
+ Port string
+}
+
+func simplifyLinks(items []renderItem, currentHost, currentPort string) {
+ for i, item := range items {
+ if item.Template != "link" && item.Template != "image" {
+ continue
+ }
+
+ m := item.Object.(renderRef)
+ if m.Hostname == currentHost && m.Port == currentPort {
+ m.Hostname = ""
+ m.Port = ""
+ m.Selector = htemplate.URL(strings.TrimPrefix(string(m.Selector), "URL:"))
+ items[i].Object = m
+ }
+ }
+}
+
+func AddOverrides(base *template.Template, overrides *template.Template) (*template.Template, error) {
+ if overrides == nil {
+ return base, nil
+ }
+
+ tmpl := base
+ var err error
+ for _, override := range overrides.Templates() {
+ tmpl, err = tmpl.AddParseTree(override.Name(), override.Tree)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return tmpl, nil
+}
+
+func AddHTMLOverrides(base *htemplate.Template, overrides *htemplate.Template) (*htemplate.Template, error) {
+ if overrides == nil {
+ return base, nil
+ }
+
+ tmpl := base
+ var err error
+ for _, override := range overrides.Templates() {
+ tmpl, err = tmpl.AddParseTree(override.Name(), override.Tree)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return tmpl, nil
+}
+
+func refItem(item gopher.MapItem) renderRef {
+ return renderRef{
+ Type: item.Type,
+ Display: item.Display,
+ Selector: htemplate.URL(item.Selector),
+ Hostname: item.Hostname,
+ Port: item.Port,
+ }
+}
+
+func RenderItems(doc gopher.MapDocument) []renderItem {
+ out := make([]renderItem, 0, len(doc))
+ out = append(out, renderItem{
+ Template: "header",
+ Object: doc,
+ })
+ inMsg := false
+ msg := &bytes.Buffer{}
+ var currentHost, currentPort string
+
+ for _, mapItem := range doc {
+ switch mapItem.Type {
+ case gopher.InfoMessageType:
+ if inMsg {
+ _, _ = msg.WriteString("\n")
+ } else {
+ msg.Reset()
+ }
+ _, _ = msg.WriteString(mapItem.Display)
+ inMsg = true
+
+ if currentHost == "" {
+ currentHost = mapItem.Hostname
+ }
+ if currentPort == "" {
+ currentPort = mapItem.Port
+ }
+ case gopher.GifFileType, gopher.ImageFileType, gopher.BitmapType, gopher.PngImageFileType:
+ if inMsg {
+ out = append(out, renderItem{
+ Template: "message",
+ Object: msg.String(),
+ })
+ inMsg = false
+ }
+ out = append(out, renderItem{
+ Template: "image",
+ Object: refItem(mapItem),
+ })
+ default:
+ if inMsg {
+ out = append(out, renderItem{
+ Template: "message",
+ Object: msg.String(),
+ })
+ inMsg = false
+ }
+ out = append(out, renderItem{
+ Template: "link",
+ Object: refItem(mapItem),
+ })
+ }
+ }
+
+ if inMsg {
+ out = append(out, renderItem{
+ Template: "message",
+ Object: msg.String(),
+ })
+ }
+
+ simplifyLinks(out, currentHost, currentPort)
+
+ return append(out, renderItem{
+ Template: "footer",
+ Object: doc,
+ })
+}
diff --git a/gopher/gophermap/mdconv/convert.go b/gopher/gophermap/mdconv/convert.go
new file mode 100644
index 0000000..5d4da08
--- /dev/null
+++ b/gopher/gophermap/mdconv/convert.go
@@ -0,0 +1,52 @@
+package mdconv
+
+import (
+ "io"
+ "text/template"
+
+ "tildegit.org/tjp/sliderule/gopher"
+ "tildegit.org/tjp/sliderule/gopher/gophermap/internal"
+)
+
+func Convert(wr io.Writer, doc gopher.MapDocument, overrides *template.Template) error {
+ tmpl, err := baseTmpl.Clone()
+ if err != nil {
+ return err
+ }
+
+ tmpl, err = internal.AddOverrides(tmpl, overrides)
+ if err != nil {
+ return err
+ }
+
+ for _, item := range internal.RenderItems(doc) {
+ if err := tmpl.ExecuteTemplate(wr, item.Template, item.Object); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+var baseTmpl = template.Must(template.New("mdconv").Parse(`
+{{ define "header" }}{{ end }}
+
+{{ define "message" -}}
+` + "```" + `
+{{.}}
+` + "```" + `
+
+{{ end }}
+
+{{ define "link" -}}
+[{{.Display}}]({{ if .Hostname | and .Port }}gopher://{{.Hostname}}:{{.Port}}{{ end }}{{.Selector}})
+
+{{ end }}
+
+{{ define "image" -}}
+![{{.Display}}]({{ if .Hostname | and .Port }}gopher://{{.Hostname}}:{{.Port}}{{ end }}{{.Selector}})
+
+{{ end }}
+
+{{ define "footer" }}{{ end }}
+`))
diff --git a/gopher/gophermap/mdconv/convert_test.go b/gopher/gophermap/mdconv/convert_test.go
new file mode 100644
index 0000000..2e39106
--- /dev/null
+++ b/gopher/gophermap/mdconv/convert_test.go
@@ -0,0 +1,69 @@
+package mdconv
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "testing"
+
+ "tildegit.org/tjp/sliderule/gopher/gophermap"
+)
+
+func TestConvert(t *testing.T) {
+ tests := []struct {
+ name string
+ input string
+ output string
+ }{
+ {
+ name: "basic doc",
+ input: strings.ReplaceAll(`
+iI am informational text localhost 70
+icontinued on this line localhost 70
+i localhost 70
+0this is my text file /file.txt localhost 70
+i localhost 70
+1here's a sub-menu /sub/ localhost 70
+.
+`[1:], "\n", "\r\n"),
+ output: (`
+` + "```" + `
+I am informational text
+continued on this line
+
+` + "```" + `
+
+[this is my text file](/file.txt)
+
+` + "```" + `
+
+` + "```" + `
+
+[here's a sub-menu](/sub/)
+
+`)[1:],
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ doc, err := gophermap.Parse(bytes.NewBufferString(test.input))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ buf := &bytes.Buffer{}
+ if err := Convert(buf, doc, nil); err != nil {
+ t.Fatal(err)
+ }
+
+ if buf.String() != test.output {
+ fmt.Println(">>> expected:")
+ fmt.Println(test.output)
+ fmt.Println(">>> got:")
+ fmt.Println(buf.String())
+ t.Fatal("html body mismatch")
+ }
+ })
+ }
+}