-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
// This package defines the data passed to templates.
//
// Copyright 2026 Shota FUJI <pockawoooh@gmail.com>
// SPDX-License-Identifier: MIT
package templates
import (
"fmt"
"html/template"
"maps"
"slices"
"github.com/bluekeyes/go-gitdiff/gitdiff"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/pocka/legit/config"
"github.com/pocka/legit/git"
)
// RepositorySummary contains overview of a git repository.
type RepositorySummary struct {
// DisplayName is a directory name without ".git" suffix.
DisplayName string
// DirName is a directory name of the repository.
DirName string
// Description is a contents of "description" text file in the repository root.
Description string
// Category is gitweb compatible repository category text. Unless "ui.category.grouping"
// option is set, this field is always empty.
Category string
LastCommit *object.Commit
}
// RepoListData is a data object passed to "repo-list" template.
type RepoListData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
// Repositories is a slice of every repositories legit sees.
Repositories []RepositorySummary
}
type RepositoriesByCategory struct {
Category string
Repositories []RepositorySummary
}
func (d RepoListData) RepositoriesByCategory() []RepositoriesByCategory {
if !d.Config.UI.Category.Grouping {
return []RepositoriesByCategory{
{
Category: "",
Repositories: d.Repositories,
},
}
}
m := make(map[string]*RepositoriesByCategory, len(d.Config.UI.Category.Order))
for _, repo := range d.Repositories {
category := repo.Category
if category == "" {
category = d.Config.UI.Category.Default
}
if group, ok := m[category]; !ok {
m[category] = &RepositoriesByCategory{
Category: category,
Repositories: []RepositorySummary{repo},
}
} else {
group.Repositories = append(group.Repositories, repo)
}
}
out := make([]RepositoriesByCategory, 0, len(m))
if empty, ok := m[""]; ok {
out = append(out, *empty)
}
for _, prioritized := range d.Config.UI.Category.Order {
if group, ok := m[prioritized]; ok {
out = append(out, *group)
}
}
for _, category := range slices.Sorted(maps.Keys(m)) {
if category == "" || slices.Contains(d.Config.UI.Category.Order, category) {
continue
}
out = append(out, *m[category])
}
return out
}
// RepositoryMeta is a shared data object passed to every pages under each repositories.
type RepositoryMeta struct {
// DisplayName is a directory name without ".git" suffix.
DisplayName string
// DirName is a directory name of the repository.
DirName string
// Description is a contents of "description" text file in the repository root.
Description string
// Ref is a ref for the current context. If a page is not tied to refs, default branch
// will be set.
Ref string
}
// RepoTopData is a data object passed to "repo-top" template.
type RepoTopData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Rendered README.
Readme template.HTML
// DefaultBranch is textual representation of repository's default branch.
DefaultBranch string
// RecentCommits is a list of recent commits made in the default branch.
RecentCommits []*object.Commit
// Whether this repository is available as Go Module.
IsGoModule bool
}
// RepoRefsData is a data object passed to "repo-refs" template.
type RepoRefsData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Tags is a list of git tags (annotate and lightweight) in the repository.
Tags []*git.TagReference
Branches []*plumbing.Reference
}
// RepoTreeRefData is a data object passed to "repo-tree-ref" template.
type RepoTreeRefData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Path to the current directory. On repository root, this is empty slice.
Path []string
// Files is a list of files for the current directory.
Files []git.NiceTree
}
// RepoBlobRefData is a data object passed to "repo-blob-ref" template.
type RepoBlobRefData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Path to the blob.
Path []string
// Content of the blob.
Content string
SyntaxHighlightedContent template.HTML
// LineNumbers holds sequential numbers starting from 1 up to line count of the blob.
LineNumbers []uint
// A list of preview output types.
PreviewTypes []string
}
// RepoBlobRefHTMLPreviewData is a data object passed to "repo-blob-ref-html-preview" template.
type RepoBlobRefHTMLPreviewData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Path to the blob.
Path []string
// Rendered HTML
Content template.HTML
}
// RepoLogRefData is a data object passed to "repo-log-ref" template.
type RepoLogRefData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
// Commits made to the ref.
Commits []*object.Commit
PrevPageHref string
NextPageHref string
}
func (r RepoLogRefData) TopCommitForRange() *object.Commit {
if len(r.Commits) == 0 {
return nil
}
return r.Commits[0]
}
func (r RepoLogRefData) BottomCommitForRange() *object.Commit {
if len(r.Commits) == 0 {
return nil
}
return r.Commits[len(r.Commits)-1]
}
// RepoCommitData is a data object passed to "repo-commit" template.
type RepoCommitData struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
Meta RepositoryMeta
Commit *object.Commit
Parent *object.Commit
Diff *git.NiceDiff
}
func (r RepoCommitData) IsLargeDiff(file *gitdiff.File) bool {
if r.Config.UI.Diff.HideThresholdLines == 0 {
return false
}
var n uint32
for _, fragment := range file.TextFragments {
n += uint32(max(0, fragment.LinesAdded))
n += uint32(max(0, fragment.LinesDeleted))
}
return n > r.Config.UI.Diff.HideThresholdLines
}
func (r RepoCommitData) FileDiffStat(file *gitdiff.File) string {
var added int64
var deleted int64
for _, fragment := range file.TextFragments {
added += fragment.LinesAdded
deleted += fragment.LinesDeleted
}
return fmt.Sprintf("+%d/-%d", added, deleted)
}
// Error404Data is a data object passed to "404" template.
type Error404Data struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
// Diagnosis is debug text supposed to attach to a bug report for website owner.
Diagnosis string
}
// Error500Data is a data object passed to "500" template.
type Error500Data struct {
// Config represents a resolved config based on "config.yaml".
Config *config.Config
// Diagnosis is debug text supposed to attach to a bug report for website owner.
Diagnosis string
}