Lindenii Project Forge
Commit info | |
---|---|
ID | 26ce57a710aac4cd8e4efcf4656c1f2448476c0d |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Mon, 10 Feb 2025 19:55:10 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Mon, 10 Feb 2025 19:55:10 +0800 |
Actions | Get patch |
*: 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 -}}