Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
*: Some simple styling with tables
package main
import (
"bytes"
"html/template"
"net/http"
"strings"
chroma_formatters_html "github.com/alecthomas/chroma/v2/formatters/html"
chroma_lexers "github.com/alecthomas/chroma/v2/lexers"
chroma_styles "github.com/alecthomas/chroma/v2/styles"
"github.com/go-git/go-git/v5/plumbing"
)
func handle_repo_tree(w http.ResponseWriter, r *http.Request) {
data := make(map[string]any)
// TODO: Sanitize path values
ref_name, category_name, repo_name, path_spec := r.PathValue("ref"), r.PathValue("category_name"), r.PathValue("repo_name"), strings.TrimSuffix(r.PathValue("rest"), "/")
data["category_name"], data["repo_name"], data["path_spec"] = category_name, repo_name, path_spec
data["ref"], data["category_name"], data["repo_name"], data["path_spec"] = ref_name, category_name, repo_name, path_spec
repo, err := open_git_repo(category_name, repo_name)
if err != nil {
_, _ = w.Write([]byte("Error opening repo: " + err.Error()))
return
}
ref, err := repo.Reference(plumbing.NewBranchReferenceName(ref_name), true)
if err != nil {
_, _ = w.Write([]byte("Error getting repo reference: " + err.Error()))
return
}
ref_hash := ref.Hash()
commit_object, err := repo.CommitObject(ref_hash)
if err != nil {
_, _ = w.Write([]byte("Error getting commit object: " + err.Error()))
return
}
tree, err := commit_object.Tree()
if err != nil {
_, _ = w.Write([]byte("Error getting file tree: " + err.Error()))
return
}
target, err := tree.Tree(path_spec)
if err != nil {
file, err := tree.File(path_spec)
if err != nil {
_, _ = w.Write([]byte("Error retrieving path: " + err.Error()))
return
}
file_contents, err := file.Contents()
if err != nil {
_, _ = w.Write([]byte("Error reading file: " + err.Error()))
return
}
lexer := chroma_lexers.Match(path_spec)
if lexer == nil {
lexer = chroma_lexers.Fallback
}
iterator, err := lexer.Tokenise(nil, file_contents)
if err != nil {
_, _ = w.Write([]byte("Error tokenizing code: " + err.Error()))
return
}
var formatted_unencapsulated bytes.Buffer
style := chroma_styles.Get("autumn")
formatter := chroma_formatters_html.New(chroma_formatters_html.WithClasses(true), chroma_formatters_html.TabWidth(8))
err = formatter.Format(&formatted_unencapsulated, style, iterator)
if err != nil {
_, _ = w.Write([]byte("Error formatting code: " + err.Error()))
return
}
formatted_encapsulated := template.HTML(formatted_unencapsulated.Bytes())
data["file_contents"] = formatted_encapsulated
err = templates.ExecuteTemplate(w, "repo_tree_file", data)
if err != nil {
_, _ = w.Write([]byte("Error rendering template: " + err.Error()))
return
}
return
}
data["readme"] = render_readme_at_tree(target)
data["files"] = build_display_git_tree(target)
err = templates.ExecuteTemplate(w, "repo_tree_dir", data)
if err != nil {
_, _ = w.Write([]byte("Error rendering template: " + err.Error()))
return
}
}
package main
import (
"bytes"
"html/template"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/microcosm-cc/bluemonday"
"github.com/yuin/goldmark"
)
func render_readme_at_tree(tree *object.Tree) any {
readme_file, err := tree.File("README.md")
if err != nil {
return "There is no README available."
return ""
}
readme_file_contents, err := readme_file.Contents()
if err != nil {
return "Unable to fetch contents of README: " + err.Error()
}
var readme_rendered_unsafe bytes.Buffer
err = goldmark.Convert([]byte(readme_file_contents), &readme_rendered_unsafe)
if err != nil {
return "Unable to render README: " + err.Error()
}
return template.HTML(bluemonday.UGCPolicy().SanitizeBytes(readme_rendered_unsafe.Bytes()))
}
html {
font-family: sans-serif;
--link-color: #7c3e66; --text-decoration-color: #b8b8b8; --box-background-color: #e6e6e6;
--link-color: hsl(320, 50%, 36%); --border-color: hsl(0, 0%, 72%); --text-decoration-color: hsl(0, 0%, 72%); --darker-box-background-color: hsl(0, 0%, 92%); --lighter-box-background-color: hsl(0, 0%, 95%);
}
html, code, pre {
font-size: 1rem;
font-size: 1rem; /* TODO: Not always correct */
}
.padding-wrapper {
padding: 0 1rem;
max-width: 50em;
margin: 0 auto;
margin: 1rem auto;
}
.padding-wrapper > * {
width: 100%;
}
a:link, a:visited {
text-decoration-color: var(--text-decoration-color);
color: var(--link-color);
}
code:not(pre > code) {
background-color: var(--box-background-color);
background-color: var(--lighter-box-background-color);
border-radius: 2px; padding: 2px; }
table {
border: var(--border-color) solid 1px;
border-spacing: 0px;
border-collapse: collapse;
}
td, th {
padding: 3px 5px;
border: var(--border-color) solid 1px;
}
th {
background-color: var(--darker-box-background-color);
}
{{- define "repo_index" -}}
<!DOCTYPE html>
<html>
<head>
{{ template "head_common" . }}
<title>{{ .category_name }}/repos/{{ .repo_name }} – Lindenii Forge</title>
</head>
<body class="repo-index">
<div class="padding-wrapper">
<table id="recent-commits">
<thead>
<tr>
<th colspan="4">Recent Commits</th> </tr> <tr>
<th scope="col">ID</th>
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">Time</th>
</tr>
</thead>
<tbody>
{{- range .commits }}
<tr>
<td class="commit-id">{{ slice .Hash.String 0 8 }}</td>
<td class="commit-title">{{ .Message | first_line }}</td>
<td class="commit-author">
<a class="email-name" href="mailto:{{ .Author.Email }}">{{ .Author.Name }}</a>
</td>
<td class="commit-time">
{{ .Author.When.Format "2006-01-02 15:04:05 -0700" }}
</td>
</tr>
{{- end }}
</tbody>
</table>
</div>
<div class="padding-wrapper">
<table id="file-tree">
<thead>
<tr>
<th colspan="3">/ on {{ .ref }}</th>
</tr>
<tr>
<th scope="col">Mode</th>
<th scope="col">Name</th>
<th scope="col">Size</th>
</tr>
</thead>
<tbody>
{{- $ref := .ref }}
{{- range .files }}
<tr>
<td class="file-mode">{{ .Mode }}</td>
<td class="file-name"><a href="tree/{{ $ref }}/{{ .Name }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
<td class="file-size">{{ .Size }}</td>
</tr>
{{- end }}
</tbody>
</table>
</div>
<div class="padding-wrapper">
<div id="refs">
</div>
</div>
<div class="padding-wrapper">
<div id="readme">
{{ .readme -}}
</div>
{{ if .readme }}
<table id="readme">
<thead>
<tr>
<th>
README.md
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{{ .readme -}}
</td>
</tr>
</tbody>
</table>
{{ end }}
</div>
</body>
</html>
{{- end -}}
{{- define "repo_tree_dir" -}}
<!DOCTYPE html>
<html>
<head>
{{ template "head_common" . }}
<title>{{ .category_name }}/repos/{{ .repo_name }}/{{ .path_spec }} – Lindenii Forge</title>
</head>
<body class="repo-tree-dir">
<div class="padding-wrapper">
<p>
/{{ .path_spec }}/
</p>
<table id="file-tree"> <thead>
<tr>
<th colspan="3">
/{{ .path_spec }}/ on {{ .ref }}
</th>
</tr>
<tr> <th scope="col">Mode</th> <th scope="col">Name</th> <th scope="col">Size</th> </tr> </thead> <tbody>
{{- $ref := .ref }}
{{- $path_spec := .path_spec }}
{{- range .files }}
<tr>
<td class="file-mode">{{ .Mode }}</td>
<td class="file-name"><a href="{{ $path_spec }}/{{ .Name }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
<td class="file-size">{{ .Size }}</td>
</tr>
{{- end }}
</tbody>
</table>
</div>
<div class="padding-wrapper">
<div id="refs">
</div>
</div>
<div class="padding-wrapper">
<div id="readme">
{{ .readme -}}
</div>
{{ if .readme }}
<table id="readme">
<thead>
<tr>
<th>
README.md
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{{ .readme -}}
</td>
</tr>
</tbody>
</table>
{{ end }}
</div>
</body>
</html>
{{- end -}}