Auto-link URLs
3e9191c9ed9b130a1136009f3d7515e6b2066758
1 parent
3192dd09
template.go
+25 -0
| 1 | 1 | package main |
|
| 2 | 2 | ||
| 3 | 3 | import ( |
|
| 4 | 4 | "embed" |
|
| 5 | 5 | "fmt" |
|
| 6 | + | "html" |
|
| 6 | 7 | "html/template" |
|
| 7 | 8 | "io" |
|
| 8 | 9 | "path" |
|
| 10 | + | "regexp" |
|
| 9 | 11 | "strings" |
|
| 10 | 12 | "time" |
|
| 11 | 13 | ) |
|
| 12 | 14 | ||
| 13 | 15 | //go:embed templates/*.html |
| 170 | 172 | if depth == 0 { |
|
| 171 | 173 | return "" |
|
| 172 | 174 | } |
|
| 173 | 175 | return fmt.Sprintf("padding-left: %grem", float64(depth)*1.2) |
|
| 174 | 176 | }, |
|
| 177 | + | "autolink": func(s string) template.HTML { |
|
| 178 | + | var b strings.Builder |
|
| 179 | + | last := 0 |
|
| 180 | + | for _, loc := range urlRe.FindAllStringIndex(s, -1) { |
|
| 181 | + | // Strip trailing punctuation. |
|
| 182 | + | end := loc[1] |
|
| 183 | + | for end > loc[0] && strings.ContainsRune(".,;:!?)]", rune(s[end-1])) { |
|
| 184 | + | end-- |
|
| 185 | + | } |
|
| 186 | + | b.WriteString(html.EscapeString(s[last:loc[0]])) |
|
| 187 | + | u := s[loc[0]:end] |
|
| 188 | + | b.WriteString(`<a href="`) |
|
| 189 | + | b.WriteString(html.EscapeString(u)) |
|
| 190 | + | b.WriteString(`">`) |
|
| 191 | + | b.WriteString(html.EscapeString(u)) |
|
| 192 | + | b.WriteString(`</a>`) |
|
| 193 | + | last = end |
|
| 194 | + | } |
|
| 195 | + | b.WriteString(html.EscapeString(s[last:])) |
|
| 196 | + | return template.HTML(b.String()) |
|
| 197 | + | }, |
|
| 175 | 198 | } |
|
| 176 | 199 | ||
| 200 | + | var urlRe = regexp.MustCompile(`https?://[^\s<>"'` + "`" + `\x00-\x1f]+`) |
|
| 201 | + | ||
| 177 | 202 | func loadTemplates() (*templateSet, error) { |
|
| 178 | 203 | layoutContent, err := templateFS.ReadFile("templates/layout.html") |
|
| 179 | 204 | if err != nil { |
|
| 180 | 205 | return nil, fmt.Errorf("read layout: %w", err) |
|
| 181 | 206 | } |
templates/home.html
+2 -2
| 47 | 47 | <table class="blob-code"> |
|
| 48 | 48 | <tbody> |
|
| 49 | 49 | {{range $i, $line := .Data.ActiveBlob.Lines}} |
|
| 50 | 50 | <tr id="L{{add $i 1}}"> |
|
| 51 | 51 | <td class="line-num"><a href="#L{{add $i 1}}">{{add $i 1}}</a></td> |
|
| 52 | - | <td class="line-code"><pre{{with langClass $.Data.ActiveBlob.Name}} class="{{.}}"{{end}}>{{$line}}</pre></td> |
|
| 52 | + | <td class="line-code"><pre{{with langClass $.Data.ActiveBlob.Name}} class="{{.}}"{{end}}>{{autolink $line}}</pre></td> |
|
| 53 | 53 | </tr> |
|
| 54 | 54 | {{end}} |
|
| 55 | 55 | </tbody> |
|
| 56 | 56 | </table> |
|
| 57 | 57 | </div> |
| 60 | 60 | {{else if .Data.Readme}} |
|
| 61 | 61 | <div class="file-view"> |
|
| 62 | 62 | <div class="file-header"> |
|
| 63 | 63 | <span class="file-name">{{.Data.Readme.Name}}</span> |
|
| 64 | 64 | </div> |
|
| 65 | - | <pre>{{.Data.Readme.Content}}</pre> |
|
| 65 | + | <pre>{{autolink .Data.Readme.Content}}</pre> |
|
| 66 | 66 | </div> |
|
| 67 | 67 | {{end}} |
|
| 68 | 68 | </div> |
|
| 69 | 69 | </div> |
|
| 70 | 70 |