gmi2html.go (3494B) - raw
1 package main 2 3 import ( 4 "fmt" 5 "html" 6 "net/url" 7 "path/filepath" 8 "strings" 9 "mime" 10 11 "git.sr.ht/~adnano/go-gemini" 12 ) 13 14 type ConvertedGmiDoc struct { 15 Content string 16 Title string 17 } 18 19 func textToHTML(reqUrl *url.URL, text gemini.Text) ConvertedGmiDoc { 20 var b strings.Builder 21 var pre bool 22 var blockquote bool 23 var list bool 24 var title string 25 for _, l := range text { 26 if _, ok := l.(gemini.LineQuote); ok { 27 if !blockquote { 28 blockquote = true 29 fmt.Fprintf(&b, "<blockquote>\n") 30 } 31 } else if blockquote { 32 blockquote = false 33 fmt.Fprintf(&b, "</blockquote>\n") 34 } 35 if _, ok := l.(gemini.LineListItem); ok { 36 if !list { 37 list = true 38 fmt.Fprint(&b, "<ul>\n") 39 } 40 } else if list { 41 list = false 42 fmt.Fprint(&b, "</ul>\n") 43 } 44 switch l.(type) { 45 case gemini.LineLink: 46 link := l.(gemini.LineLink) 47 urlstring := html.EscapeString(link.URL) 48 // u = ctx.URL.ResolveReference(u) ? 49 u, err := url.Parse(urlstring) 50 if err != nil { 51 continue 52 } 53 if reqUrl != nil { 54 u = reqUrl.ResolveReference(u) 55 } 56 if u.Scheme == "gemini" || (reqUrl != nil && u.Scheme == "") { 57 if strings.HasSuffix(u.Host, c.Host) { 58 u.Scheme = "" 59 urlstring = html.EscapeString(u.String()) 60 } else { 61 // TODO make configurable 62 u.Path = fmt.Sprintf("gemini/%s%s", u.Host, u.Path) 63 u.Scheme = "" 64 u.Host = "portal.mozz.us" 65 urlstring = html.EscapeString(u.String()) 66 } 67 } 68 name := html.EscapeString(link.Name) 69 if name == "" { 70 name = urlstring 71 } 72 // embed images 73 if strings.HasPrefix(mime.TypeByExtension(filepath.Ext(u.Path)), "image") { 74 fmt.Fprintf(&b, "<p><img src='%s' alt='%s'></p>\n", urlstring, name) 75 } else { 76 fmt.Fprintf(&b, "<p><a href='%s'>%s</a></p>\n", urlstring, name) 77 } 78 case gemini.LinePreformattingToggle: 79 pre = !pre 80 if pre { 81 altText := string(l.(gemini.LinePreformattingToggle)) 82 if altText != "" { 83 altText = html.EscapeString(altText) 84 fmt.Fprintf(&b, "<pre title='%s'>\n", altText) 85 } else { 86 fmt.Fprint(&b, "<pre>\n") 87 } 88 } else { 89 fmt.Fprint(&b, "</pre>\n") 90 } 91 case gemini.LinePreformattedText: 92 text := string(l.(gemini.LinePreformattedText)) 93 fmt.Fprintf(&b, "%s\n", html.EscapeString(text)) 94 case gemini.LineHeading1: 95 text := html.EscapeString(string(l.(gemini.LineHeading1))) 96 fmt.Fprintf(&b, "<h1 id='%s'>%s</h1>\n", text, text) 97 if title == "" { 98 title = text 99 } // TODO deal with repetition 100 case gemini.LineHeading2: 101 text := html.EscapeString(string(l.(gemini.LineHeading2))) 102 fmt.Fprintf(&b, "<h2 id='%s'>%s</h2>\n", text, text) 103 if title == "" { 104 title = text 105 } 106 case gemini.LineHeading3: 107 text := html.EscapeString(string(l.(gemini.LineHeading3))) 108 fmt.Fprintf(&b, "<h3 id='%s'>%s</h3>\n", text, text) 109 if title == "" { 110 title = text 111 } 112 case gemini.LineListItem: 113 text := string(l.(gemini.LineListItem)) 114 fmt.Fprintf(&b, "<li>%s</li>\n", html.EscapeString(text)) 115 case gemini.LineQuote: 116 text := string(l.(gemini.LineQuote)) 117 fmt.Fprintf(&b, "<p>%s</p>\n", html.EscapeString(text)) 118 case gemini.LineText: 119 text := string(l.(gemini.LineText)) 120 if text == "" { 121 fmt.Fprint(&b, "<br>\n") 122 } else { 123 fmt.Fprintf(&b, "<p>%s</p>\n", html.EscapeString(text)) 124 } 125 } 126 } 127 if pre { 128 fmt.Fprint(&b, "</pre>\n") 129 } 130 if list { 131 fmt.Fprint(&b, "</ul>\n") 132 } 133 if blockquote { 134 fmt.Fprint(&b, "</blockquote>\n") 135 } 136 return ConvertedGmiDoc{ 137 b.String(), 138 title, 139 } 140 }