this repo has no description
1package routes
2
3import (
4 "bytes"
5 "fmt"
6 "html/template"
7 "io"
8 "log"
9 "net/http"
10 "path/filepath"
11 "strings"
12
13 "github.com/alecthomas/chroma/v2/formatters/html"
14 "github.com/alecthomas/chroma/v2/lexers"
15 "github.com/alecthomas/chroma/v2/styles"
16 "github.com/icyphox/bild/legit/git"
17)
18
19func (h *Handle) Write404(w http.ResponseWriter) {
20 w.WriteHeader(404)
21 if err := h.t.ExecuteTemplate(w, "404", nil); err != nil {
22 log.Printf("404 template: %s", err)
23 }
24}
25
26func (h *Handle) Write500(w http.ResponseWriter) {
27 w.WriteHeader(500)
28 if err := h.t.ExecuteTemplate(w, "500", nil); err != nil {
29 log.Printf("500 template: %s", err)
30 }
31}
32
33func (h *Handle) WriteOOBNotice(w http.ResponseWriter, id, msg string) {
34 html := fmt.Sprintf(`<span id="%s" hx-swap-oob="innerHTML">%s</span>`, id, msg)
35
36 w.Header().Set("Content-Type", "text/html")
37 w.WriteHeader(http.StatusOK)
38 w.Write([]byte(html))
39}
40
41func (h *Handle) listFiles(files []git.NiceTree, data map[string]any, w http.ResponseWriter) {
42 tpath := filepath.Join(h.c.Dirs.Templates, "*")
43 t := template.Must(template.ParseGlob(tpath))
44
45 data["files"] = files
46 data["meta"] = h.c.Meta
47
48 if err := t.ExecuteTemplate(w, "tree", data); err != nil {
49 log.Println(err)
50 return
51 }
52}
53
54func countLines(r io.Reader) (int, error) {
55 buf := make([]byte, 32*1024)
56 bufLen := 0
57 count := 0
58 nl := []byte{'\n'}
59
60 for {
61 c, err := r.Read(buf)
62 if c > 0 {
63 bufLen += c
64 }
65 count += bytes.Count(buf[:c], nl)
66
67 switch {
68 case err == io.EOF:
69 /* handle last line not having a newline at the end */
70 if bufLen >= 1 && buf[(bufLen-1)%(32*1024)] != '\n' {
71 count++
72 }
73 return count, nil
74 case err != nil:
75 return 0, err
76 }
77 }
78}
79
80func (d *Handle) showFileWithHighlight(name, content string, data map[string]any, w http.ResponseWriter) {
81 tpath := filepath.Join(d.c.Dirs.Templates, "*")
82 t := template.Must(template.ParseGlob(tpath))
83
84 lexer := lexers.Get(name)
85 if lexer == nil {
86 lexer = lexers.Get(".txt")
87 }
88
89 style := styles.Get(d.c.Meta.SyntaxHighlight)
90 if style == nil {
91 style = styles.Get("monokailight")
92 }
93
94 formatter := html.New(
95 html.WithLineNumbers(true),
96 html.WithLinkableLineNumbers(true, "L"),
97 )
98
99 iterator, err := lexer.Tokenise(nil, content)
100 if err != nil {
101 d.Write500(w)
102 return
103 }
104
105 var code bytes.Buffer
106 err = formatter.Format(&code, style, iterator)
107 if err != nil {
108 d.Write500(w)
109 return
110 }
111
112 data["content"] = template.HTML(code.String())
113 data["meta"] = d.c.Meta
114 data["chroma"] = true
115
116 if err := t.ExecuteTemplate(w, "file", data); err != nil {
117 log.Println(err)
118 return
119 }
120}
121
122func (d *Handle) showFile(content string, data map[string]any, w http.ResponseWriter) {
123 tpath := filepath.Join(d.c.Dirs.Templates, "*")
124 t := template.Must(template.ParseGlob(tpath))
125
126 lc, err := countLines(strings.NewReader(content))
127 if err != nil {
128 // Non-fatal, we'll just skip showing line numbers in the template.
129 log.Printf("counting lines: %s", err)
130 }
131
132 lines := make([]int, lc)
133 if lc > 0 {
134 for i := range lines {
135 lines[i] = i + 1
136 }
137 }
138
139 data["linecount"] = lines
140 data["content"] = content
141 data["meta"] = d.c.Meta
142 data["chroma"] = false
143
144 if err := t.ExecuteTemplate(w, "file", data); err != nil {
145 log.Println(err)
146 return
147 }
148}
149
150func (d *Handle) showRaw(content string, w http.ResponseWriter) {
151 w.WriteHeader(http.StatusOK)
152 w.Header().Set("Content-Type", "text/plain")
153 w.Write([]byte(content))
154 return
155}