package routes import ( "bytes" "io" "log" "net/http" "strings" "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/lexers" "github.com/alecthomas/chroma/v2/styles" "go.alanpearce.eu/elgit/git" "go.alanpearce.eu/elgit/templates" ) func (d *deps) Write404(w http.ResponseWriter) { w.WriteHeader(http.StatusNotFound) data := templates.PageData{ Meta: d.c.Meta, } if err := templates.NotFound(data).Render(w); err != nil { log.Printf("404 template: %s", err) } } func (d *deps) Write500(w http.ResponseWriter) { w.WriteHeader(http.StatusInternalServerError) data := templates.PageData{ Meta: d.c.Meta, } if err := templates.ServerError(data).Render(w); err != nil { log.Printf("500 template: %s", err) } } func (d *deps) listFiles(files []git.NiceTree, data map[string]any, w http.ResponseWriter) { pageData := templates.PageData{ Meta: d.c.Meta, DisplayName: getDisplayName(data["name"].(string)), Name: data["name"].(string), Ref: data["ref"].(string), Description: data["desc"].(string), Parent: "", } if parent, ok := data["parent"]; ok && parent != nil { pageData.Parent = parent.(string) } readme := "" if readmeContent, ok := data["readme"]; ok && readmeContent != nil { readme = readmeContent.(string) } dotdot := "" if dotdotPath, ok := data["dotdot"]; ok && dotdotPath != nil { dotdot = dotdotPath.(string) } if err := templates.Tree(pageData, files, readme, dotdot).Render(w); err != nil { log.Println(err) return } } func countLines(r io.Reader) (int, error) { buf := make([]byte, 32*1024) bufLen := 0 count := 0 nl := []byte{'\n'} for { c, err := r.Read(buf) if c > 0 { bufLen += c } count += bytes.Count(buf[:c], nl) switch { case err == io.EOF: /* handle last line not having a newline at the end */ if bufLen >= 1 && buf[(bufLen-1)%(32*1024)] != '\n' { count++ } return count, nil case err != nil: return 0, err } } } func (d *deps) showFileWithHighlight( name, content string, data map[string]any, w http.ResponseWriter, ) { lexer := lexers.Get(name) if lexer == nil { lexer = lexers.Get(".txt") } style := styles.Get(d.c.Meta.SyntaxHighlight) if style == nil { style = styles.Get("monokailight") } formatter := html.New( html.WithLineNumbers(true), html.WithLinkableLineNumbers(true, "L"), ) iterator, err := lexer.Tokenise(nil, content) if err != nil { d.Write500(w) return } var code bytes.Buffer err = formatter.Format(&code, style, iterator) if err != nil { d.Write500(w) return } pageData := templates.PageData{ Meta: d.c.Meta, DisplayName: getDisplayName(data["name"].(string)), Content: code.String(), Name: data["name"].(string), Ref: data["ref"].(string), Description: data["desc"].(string), Path: data["path"].(string), } if err := templates.File(pageData, true).Render(w); err != nil { log.Println(err) return } } func (d *deps) showFile(content string, data map[string]any, w http.ResponseWriter) { lc, err := countLines(strings.NewReader(content)) if err != nil { // Non-fatal, we'll just skip showing line numbers in the template. log.Printf("counting lines: %s", err) } lines := make([]int, lc) if lc > 0 { for i := range lines { lines[i] = i + 1 } } pageData := templates.PageData{ Meta: d.c.Meta, DisplayName: getDisplayName(data["name"].(string)), LineCount: lines, Content: content, Name: data["name"].(string), Ref: data["ref"].(string), Description: data["desc"].(string), Path: data["path"].(string), } if err := templates.File(pageData, false).Render(w); err != nil { log.Println(err) return } } func (d *deps) showRaw(content string, w http.ResponseWriter) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/plain") _, err := w.Write([]byte(content)) if err != nil { log.Println(err) d.Write500(w) } }