| @@ -53,6 +53,7 @@ func (s *Server) siteName() string { |
| 53 | func (s *Server) stylesheet(w http.ResponseWriter, r *http.Request) { |
53 | func (s *Server) stylesheet(w http.ResponseWriter, r *http.Request) { |
| 54 | w.Header().Set("Content-Type", "text/css; charset=utf-8") |
54 | w.Header().Set("Content-Type", "text/css; charset=utf-8") |
| 55 | w.Write(web.StyleCSS) |
55 | w.Write(web.StyleCSS) |
| |
56 | w.Write(chromaCSS) |
| 56 | } |
57 | } |
| 57 | |
58 | |
| 58 | func (s *Server) favicon(w http.ResponseWriter, r *http.Request) { |
59 | func (s *Server) favicon(w http.ResponseWriter, r *http.Request) { |
| @@ -734,25 +735,40 @@ type numberedLine struct { |
| 734 | Text string |
735 | Text string |
| 735 | } |
736 | } |
| 736 | |
737 | |
| |
738 | // chromaFormatter emits class-based markup (no inline colors), so the |
| |
739 | // stylesheet can swap palettes with the color scheme. |
| |
740 | var chromaFormatter = html.New(html.WithClasses(true), |
| |
741 | html.WithLineNumbers(true), html.LineNumbersInTable(false), |
| |
742 | html.WithLinkableLineNumbers(true, "L")) |
| |
743 | |
| 737 | func highlight(filePath string, data []byte) template.HTML { |
744 | func highlight(filePath string, data []byte) template.HTML { |
| 738 | lexer := lexers.Match(filePath) |
745 | lexer := lexers.Match(filePath) |
| 739 | if lexer == nil { |
746 | if lexer == nil { |
| 740 | lexer = lexers.Fallback |
747 | lexer = lexers.Fallback |
| 741 | } |
748 | } |
| 742 | style := styles.Get("friendly") |
| |
| 743 | formatter := html.New(html.WithLineNumbers(true), html.LineNumbersInTable(false), |
| |
| 744 | html.WithLinkableLineNumbers(true, "L")) |
| |
| 745 | iterator, err := lexer.Tokenise(nil, string(data)) |
749 | iterator, err := lexer.Tokenise(nil, string(data)) |
| 746 | if err != nil { |
750 | if err != nil { |
| 747 | return template.HTML("<pre>" + template.HTMLEscapeString(string(data)) + "</pre>") |
751 | return template.HTML("<pre>" + template.HTMLEscapeString(string(data)) + "</pre>") |
| 748 | } |
752 | } |
| 749 | var buf bytes.Buffer |
753 | var buf bytes.Buffer |
| 750 | if err := formatter.Format(&buf, style, iterator); err != nil { |
754 | if err := chromaFormatter.Format(&buf, styles.Get("friendly"), iterator); err != nil { |
| 751 | return template.HTML("<pre>" + template.HTMLEscapeString(string(data)) + "</pre>") |
755 | return template.HTML("<pre>" + template.HTMLEscapeString(string(data)) + "</pre>") |
| 752 | } |
756 | } |
| 753 | return template.HTML(buf.String()) |
757 | return template.HTML(buf.String()) |
| 754 | } |
758 | } |
| 755 | |
759 | |
| |
760 | // chromaCSS is both syntax palettes: light by default, dark under the same |
| |
761 | // media query the rest of the stylesheet uses. The site's --code-bg stays |
| |
762 | // the background either way. |
| |
763 | var chromaCSS = func() []byte { |
| |
764 | var buf bytes.Buffer |
| |
765 | chromaFormatter.WriteCSS(&buf, styles.Get("friendly")) |
| |
766 | buf.WriteString("\n@media (prefers-color-scheme: dark) {\n") |
| |
767 | chromaFormatter.WriteCSS(&buf, styles.Get("github-dark")) |
| |
768 | buf.WriteString("}\n.chroma, .bg { background: var(--code-bg) !important; }\n") |
| |
769 | return buf.Bytes() |
| |
770 | }() |
| |
771 | |
| 756 | func (s *Server) raw(w http.ResponseWriter, r *http.Request) { |
772 | func (s *Server) raw(w http.ResponseWriter, r *http.Request) { |
| 757 | p, ok := s.repoFor(w, r, r.PathValue("ref")) |
773 | p, ok := s.repoFor(w, r, r.PathValue("ref")) |
| 758 | if !ok { |
774 | if !ok { |