Lindenii Project Forge
Login
Commit info
ID26ce57a710aac4cd8e4efcf4656c1f2448476c0d
AuthorRunxi Yu<me@runxiyu.org>
Author dateMon, 10 Feb 2025 19:55:10 +0800
CommitterRunxi Yu<me@runxiyu.org>
Committer dateMon, 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 }} &ndash; 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 }} &ndash; 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 -}}