1diff --git a/pkg/git/git.go b/pkg/git/git.go
2index ce72465a84f2b8f0c65411b176b7a075ca031609..6a7b91fcba4060e8c2462a6ff03cf9fd309218d4 100644
3--- a/pkg/git/git.go
4+++ b/pkg/git/git.go
5@@ -13,7 +13,8 @@
6 var ()
7
8 var (
9- MissingRefErr = errors.New("Reference not found")
10+ MissingRefErr = errors.New("Reference not found")
11+ TreeForFileErr = errors.New("Trying to get tree of a file")
12 )
13
14 type (
15@@ -145,9 +146,73 @@
16 return branches, nil
17 }
18
19+func (g *GitRepository) Tree(path string) (*object.Tree, error) {
20+ err := g.validateRef()
21+ if err != nil {
22+ return nil, err
23+ }
24+
25+ c, err := g.repository.CommitObject(g.ref)
26+ if err != nil {
27+ return nil, err
28+ }
29+
30+ tree, err := c.Tree()
31+ if err != nil {
32+ return nil, err
33+ }
34+
35+ if path == "" {
36+ return tree, nil
37+ } else {
38+ o, err := tree.FindEntry(path)
39+ if err != nil {
40+ return nil, err
41+ }
42+
43+ if !o.Mode.IsFile() {
44+ subtree, err := tree.Tree(path)
45+ if err != nil {
46+ return nil, err
47+ }
48+ return subtree, nil
49+ } else {
50+ return nil, TreeForFileErr
51+ }
52+ }
53+}
54+
55 func (g *GitRepository) validateRef() error {
56 if !g.setRef {
57 return g.SetRef("")
58 }
59 return nil
60 }
61+
62+func (g *GitRepository) FileContent(path string) (string, error) {
63+ c, err := g.repository.CommitObject(g.ref)
64+ if err != nil {
65+ return "", err
66+ }
67+
68+ tree, err := c.Tree()
69+ if err != nil {
70+ return "", err
71+ }
72+
73+ file, err := tree.File(path)
74+ if err != nil {
75+ return "", err
76+ }
77+
78+ isbin, err := file.IsBinary()
79+ if err != nil {
80+ return "", err
81+ }
82+
83+ if !isbin {
84+ return file.Contents()
85+ } else {
86+ return "Binary file", nil
87+ }
88+}
89diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
90index e2f40422ed212156620190800a9ec6569bc4c11f..f3e74c747e433b33f1b68d13473ef5ab507b5b95 100644
91--- a/pkg/handler/git/handler.go
92+++ b/pkg/handler/git/handler.go
93@@ -1,11 +1,17 @@
94 package git
95
96 import (
97+ "bytes"
98 "log/slog"
99 "net/http"
100+ "path/filepath"
101
102 "git.gabrielgio.me/cerrado/pkg/service"
103 "git.gabrielgio.me/cerrado/templates"
104+ "github.com/alecthomas/chroma/v2"
105+ "github.com/alecthomas/chroma/v2/formatters/html"
106+ "github.com/alecthomas/chroma/v2/lexers"
107+ "github.com/alecthomas/chroma/v2/styles"
108 "github.com/go-git/go-git/v5/plumbing"
109 "github.com/go-git/go-git/v5/plumbing/object"
110 )
111@@ -19,6 +25,8 @@ gitService interface {
112 ListRepositories() ([]*service.Repository, error)
113 ListCommits(name string, ref string) ([]*object.Commit, error)
114 GetHead(name string) (*plumbing.Reference, error)
115+ GetTree(name, ref, path string) (*object.Tree, error)
116+ GetFileContent(name, ref, path string) (string, error)
117 ListTags(name string) ([]*object.Tag, error)
118 ListBranches(name string) ([]*plumbing.Reference, error)
119 }
120@@ -107,10 +115,64 @@
121 func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
122 name := r.PathValue("name")
123 ref := r.PathValue("ref")
124+ rest := r.PathValue("rest")
125+
126+ tree, err := g.gitService.GetTree(name, ref, rest)
127+ if err != nil {
128+ slog.Error("Error loading tree", "error", err)
129+ return
130+ }
131+
132 gitList := &templates.GitItemPage{
133- Name: name,
134- Ref: ref,
135- GitItemBase: &templates.GitItemTreePage{},
136+ Name: name,
137+ Ref: ref,
138+ GitItemBase: &templates.GitItemTreePage{
139+ CurrentPath: rest,
140+ Tree: tree,
141+ Ref: ref,
142+ Name: name,
143+ },
144+ }
145+ templates.WritePageTemplate(w, gitList)
146+}
147+
148+func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
149+ name := r.PathValue("name")
150+ ref := r.PathValue("ref")
151+ rest := r.PathValue("rest")
152+
153+ file, err := g.gitService.GetFileContent(name, ref, rest)
154+ if err != nil {
155+ slog.Error("Error loading blob", "error", err)
156+ return
157+ }
158+
159+ filename := filepath.Base(rest)
160+ lexer := GetLexers(filename)
161+ style := styles.Get("xcode")
162+ formatter := html.New(
163+ html.WithLineNumbers(true),
164+ )
165+ iterator, err := lexer.Tokenise(nil, file)
166+ if err != nil {
167+ slog.Error("Error tokenise", "error", err)
168+ return
169+ }
170+
171+ var code bytes.Buffer
172+ err = formatter.Format(&code, style, iterator)
173+ if err != nil {
174+ slog.Error("Error format", "error", err)
175+ return
176+ }
177+
178+ gitList := &templates.GitItemPage{
179+ Name: name,
180+ Ref: ref,
181+ GitItemBase: &templates.GitItemBlobPage{
182+ File: rest,
183+ Content: code.Bytes(),
184+ },
185 }
186 templates.WritePageTemplate(w, gitList)
187 }
188@@ -134,3 +196,16 @@ },
189 }
190 templates.WritePageTemplate(w, gitList)
191 }
192+
193+func GetLexers(filename string) chroma.Lexer {
194+ if filename == "APKBUILD" {
195+ return lexers.Get("sh")
196+ }
197+
198+ lexer := lexers.Get(filename)
199+
200+ if lexer == nil {
201+ lexer = lexers.Get("txt")
202+ }
203+ return lexer
204+}
205diff --git a/pkg/handler/router.go b/pkg/handler/router.go
206index bdf883ed8a8af090669e285504118bda8d86450a..ed782f75d525c637e539a4e6c07795cc0d8ac8d2 100644
207--- a/pkg/handler/router.go
208+++ b/pkg/handler/router.go
209@@ -35,7 +35,8 @@ mux.HandleFunc("/static/{file}", staticHandler)
210 mux.HandleFunc("/{name}/about/{$}", gitHandler.About)
211 mux.HandleFunc("/{name}", gitHandler.Summary)
212 mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
213- mux.HandleFunc("/{name}/tree/{ref}", gitHandler.Tree)
214+ mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
215+ mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
216 mux.HandleFunc("/{name}/log/{ref}", gitHandler.Log)
217 mux.HandleFunc("/config", configHander)
218 mux.HandleFunc("/about", aboutHandler.About)
219diff --git a/pkg/service/git.go b/pkg/service/git.go
220index 9bf11f4e79cb77ae692820236f59db9bc9ea0453..f8867850cd8a76933da262156fdbac70134a27ff 100644
221--- a/pkg/service/git.go
222+++ b/pkg/service/git.go
223@@ -89,6 +89,38 @@ }
224 return repo.Commits()
225 }
226
227+func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
228+ // TODO: handle nil
229+ r := g.configRepo.GetByName(name)
230+
231+ repo, err := git.OpenRepository(r.Path)
232+ if err != nil {
233+ return nil, err
234+ }
235+ err = repo.SetRef(ref)
236+ if err != nil {
237+ return nil, err
238+ }
239+
240+ return repo.Tree(path)
241+}
242+
243+func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
244+ // TODO: handle nil
245+ r := g.configRepo.GetByName(name)
246+
247+ repo, err := git.OpenRepository(r.Path)
248+ if err != nil {
249+ return "", err
250+ }
251+ err = repo.SetRef(ref)
252+ if err != nil {
253+ return "", err
254+ }
255+
256+ return repo.FileContent(path)
257+}
258+
259 func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
260 // TODO: handle nil
261 r := g.configRepo.GetByName(name)
262diff --git a/templates/base.qtpl b/templates/base.qtpl
263index 16b878014575bb4d5d6dc275b17774b1d63079c3..180b1ab428bc964511451c36569b198be2f5d3ee 100644
264--- a/templates/base.qtpl
265+++ b/templates/base.qtpl
266@@ -30,6 +30,11 @@ return t.Format("2006-01-02")
267 }
268 %}
269
270+{% code func Ignore[T any](v T, _ error) T {
271+ return v
272+ }
273+%}
274+
275 Page prints a page implementing Page interface.
276 {% func PageTemplate(p Page) %}
277 <html lang="en">
278diff --git a/templates/base.qtpl.go b/templates/base.qtpl.go
279index 6d4d0a082e97a6f3bba19dc6a343ba313eabcc21..c5570c8ee4119c1861d86e15aec1f7e24a4a35a9 100644
280--- a/templates/base.qtpl.go
281+++ b/templates/base.qtpl.go
282@@ -71,174 +71,179 @@ func TimeFormat(t time.Time) string {
283 return t.Format("2006-01-02")
284 }
285
286+//line base.qtpl:33
287+func Ignore[T any](v T, _ error) T {
288+ return v
289+}
290+
291 // Page prints a page implementing Page interface.
292
293-//line base.qtpl:34
294+//line base.qtpl:39
295 func StreamPageTemplate(qw422016 *qt422016.Writer, p Page) {
296-//line base.qtpl:34
297+//line base.qtpl:39
298 qw422016.N().S(`
299 <html lang="en">
300 <head>
301 <meta charset="utf-8">
302 <link rel="icon" href="data:,">
303 <title>cerrado | `)
304-//line base.qtpl:39
305+//line base.qtpl:44
306 p.StreamTitle(qw422016)
307-//line base.qtpl:39
308+//line base.qtpl:44
309 qw422016.N().S(`</title>
310 <link rel="stylesheet" href="/static/main`)
311-//line base.qtpl:40
312+//line base.qtpl:45
313 qw422016.E().S(Slug)
314-//line base.qtpl:40
315+//line base.qtpl:45
316 qw422016.N().S(`.css">
317 <meta name="viewport" content="width=device-width, initial-scale=1" />
318 </head>
319 <body>
320 `)
321-//line base.qtpl:44
322+//line base.qtpl:49
323 p.StreamNavbar(qw422016)
324-//line base.qtpl:44
325+//line base.qtpl:49
326 qw422016.N().S(`
327 <div class="container">
328 `)
329-//line base.qtpl:46
330+//line base.qtpl:51
331 p.StreamContent(qw422016)
332-//line base.qtpl:46
333+//line base.qtpl:51
334 qw422016.N().S(`
335 </div>
336 </body>
337 `)
338-//line base.qtpl:49
339+//line base.qtpl:54
340 p.StreamScript(qw422016)
341-//line base.qtpl:49
342+//line base.qtpl:54
343 qw422016.N().S(`
344 </html>
345 `)
346-//line base.qtpl:51
347+//line base.qtpl:56
348 }
349
350-//line base.qtpl:51
351+//line base.qtpl:56
352 func WritePageTemplate(qq422016 qtio422016.Writer, p Page) {
353-//line base.qtpl:51
354+//line base.qtpl:56
355 qw422016 := qt422016.AcquireWriter(qq422016)
356-//line base.qtpl:51
357+//line base.qtpl:56
358 StreamPageTemplate(qw422016, p)
359-//line base.qtpl:51
360+//line base.qtpl:56
361 qt422016.ReleaseWriter(qw422016)
362-//line base.qtpl:51
363+//line base.qtpl:56
364 }
365
366-//line base.qtpl:51
367+//line base.qtpl:56
368 func PageTemplate(p Page) string {
369-//line base.qtpl:51
370+//line base.qtpl:56
371 qb422016 := qt422016.AcquireByteBuffer()
372-//line base.qtpl:51
373+//line base.qtpl:56
374 WritePageTemplate(qb422016, p)
375-//line base.qtpl:51
376+//line base.qtpl:56
377 qs422016 := string(qb422016.B)
378-//line base.qtpl:51
379+//line base.qtpl:56
380 qt422016.ReleaseByteBuffer(qb422016)
381-//line base.qtpl:51
382+//line base.qtpl:56
383 return qs422016
384-//line base.qtpl:51
385+//line base.qtpl:56
386 }
387
388-//line base.qtpl:53
389+//line base.qtpl:58
390 type BasePage struct{}
391
392-//line base.qtpl:54
393+//line base.qtpl:59
394 func (p *BasePage) StreamTitle(qw422016 *qt422016.Writer) {
395-//line base.qtpl:54
396+//line base.qtpl:59
397 qw422016.N().S(`Empty`)
398-//line base.qtpl:54
399+//line base.qtpl:59
400 }
401
402-//line base.qtpl:54
403+//line base.qtpl:59
404 func (p *BasePage) WriteTitle(qq422016 qtio422016.Writer) {
405-//line base.qtpl:54
406+//line base.qtpl:59
407 qw422016 := qt422016.AcquireWriter(qq422016)
408-//line base.qtpl:54
409+//line base.qtpl:59
410 p.StreamTitle(qw422016)
411-//line base.qtpl:54
412+//line base.qtpl:59
413 qt422016.ReleaseWriter(qw422016)
414-//line base.qtpl:54
415+//line base.qtpl:59
416 }
417
418-//line base.qtpl:54
419+//line base.qtpl:59
420 func (p *BasePage) Title() string {
421-//line base.qtpl:54
422+//line base.qtpl:59
423 qb422016 := qt422016.AcquireByteBuffer()
424-//line base.qtpl:54
425+//line base.qtpl:59
426 p.WriteTitle(qb422016)
427-//line base.qtpl:54
428+//line base.qtpl:59
429 qs422016 := string(qb422016.B)
430-//line base.qtpl:54
431+//line base.qtpl:59
432 qt422016.ReleaseByteBuffer(qb422016)
433-//line base.qtpl:54
434+//line base.qtpl:59
435 return qs422016
436-//line base.qtpl:54
437+//line base.qtpl:59
438 }
439
440-//line base.qtpl:55
441+//line base.qtpl:60
442 func (p *BasePage) StreamBody(qw422016 *qt422016.Writer) {
443-//line base.qtpl:55
444+//line base.qtpl:60
445 qw422016.N().S(`HelloWorld`)
446-//line base.qtpl:55
447+//line base.qtpl:60
448 }
449
450-//line base.qtpl:55
451+//line base.qtpl:60
452 func (p *BasePage) WriteBody(qq422016 qtio422016.Writer) {
453-//line base.qtpl:55
454+//line base.qtpl:60
455 qw422016 := qt422016.AcquireWriter(qq422016)
456-//line base.qtpl:55
457+//line base.qtpl:60
458 p.StreamBody(qw422016)
459-//line base.qtpl:55
460+//line base.qtpl:60
461 qt422016.ReleaseWriter(qw422016)
462-//line base.qtpl:55
463+//line base.qtpl:60
464 }
465
466-//line base.qtpl:55
467+//line base.qtpl:60
468 func (p *BasePage) Body() string {
469-//line base.qtpl:55
470+//line base.qtpl:60
471 qb422016 := qt422016.AcquireByteBuffer()
472-//line base.qtpl:55
473+//line base.qtpl:60
474 p.WriteBody(qb422016)
475-//line base.qtpl:55
476+//line base.qtpl:60
477 qs422016 := string(qb422016.B)
478-//line base.qtpl:55
479+//line base.qtpl:60
480 qt422016.ReleaseByteBuffer(qb422016)
481-//line base.qtpl:55
482+//line base.qtpl:60
483 return qs422016
484-//line base.qtpl:55
485+//line base.qtpl:60
486 }
487
488-//line base.qtpl:56
489+//line base.qtpl:61
490 func (p *BasePage) StreamScript(qw422016 *qt422016.Writer) {
491-//line base.qtpl:56
492+//line base.qtpl:61
493 }
494
495-//line base.qtpl:56
496+//line base.qtpl:61
497 func (p *BasePage) WriteScript(qq422016 qtio422016.Writer) {
498-//line base.qtpl:56
499+//line base.qtpl:61
500 qw422016 := qt422016.AcquireWriter(qq422016)
501-//line base.qtpl:56
502+//line base.qtpl:61
503 p.StreamScript(qw422016)
504-//line base.qtpl:56
505+//line base.qtpl:61
506 qt422016.ReleaseWriter(qw422016)
507-//line base.qtpl:56
508+//line base.qtpl:61
509 }
510
511-//line base.qtpl:56
512+//line base.qtpl:61
513 func (p *BasePage) Script() string {
514-//line base.qtpl:56
515+//line base.qtpl:61
516 qb422016 := qt422016.AcquireByteBuffer()
517-//line base.qtpl:56
518+//line base.qtpl:61
519 p.WriteScript(qb422016)
520-//line base.qtpl:56
521+//line base.qtpl:61
522 qs422016 := string(qb422016.B)
523-//line base.qtpl:56
524+//line base.qtpl:61
525 qt422016.ReleaseByteBuffer(qb422016)
526-//line base.qtpl:56
527+//line base.qtpl:61
528 return qs422016
529-//line base.qtpl:56
530+//line base.qtpl:61
531 }
532diff --git a/templates/gititemblob.qtpl b/templates/gititemblob.qtpl
533new file mode 100644
534index 0000000000000000000000000000000000000000..89d002d2521e4b56c31db6811d137186f830614e
535--- /dev/null
536+++ b/templates/gititemblob.qtpl
537@@ -0,0 +1,14 @@
538+{% code
539+type GitItemBlobPage struct {
540+ File string
541+ Content []byte
542+}
543+%}
544+
545+{% func (g *GitItemBlobPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Tree) %}{% endfunc %}
546+
547+{% func (g *GitItemBlobPage) GitContent() %}
548+<div class="code-view">
549+{%z= g.Content %}
550+</div>
551+{% endfunc %}
552diff --git a/templates/gititemblob.qtpl.go b/templates/gititemblob.qtpl.go
553new file mode 100644
554index 0000000000000000000000000000000000000000..6b4e1878145e79855875577f6edc748cd6b5ea1c
555--- /dev/null
556+++ b/templates/gititemblob.qtpl.go
557@@ -0,0 +1,98 @@
558+// Code generated by qtc from "gititemblob.qtpl". DO NOT EDIT.
559+// See https://github.com/valyala/quicktemplate for details.
560+
561+//line gititemblob.qtpl:1
562+package templates
563+
564+//line gititemblob.qtpl:1
565+import (
566+ qtio422016 "io"
567+
568+ qt422016 "github.com/valyala/quicktemplate"
569+)
570+
571+//line gititemblob.qtpl:1
572+var (
573+ _ = qtio422016.Copy
574+ _ = qt422016.AcquireByteBuffer
575+)
576+
577+//line gititemblob.qtpl:2
578+type GitItemBlobPage struct {
579+ File string
580+ Content []byte
581+}
582+
583+//line gititemblob.qtpl:8
584+func (g *GitItemBlobPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
585+//line gititemblob.qtpl:8
586+ StreamGitItemNav(qw422016, name, ref, Tree)
587+//line gititemblob.qtpl:8
588+}
589+
590+//line gititemblob.qtpl:8
591+func (g *GitItemBlobPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
592+//line gititemblob.qtpl:8
593+ qw422016 := qt422016.AcquireWriter(qq422016)
594+//line gititemblob.qtpl:8
595+ g.StreamNav(qw422016, name, ref)
596+//line gititemblob.qtpl:8
597+ qt422016.ReleaseWriter(qw422016)
598+//line gititemblob.qtpl:8
599+}
600+
601+//line gititemblob.qtpl:8
602+func (g *GitItemBlobPage) Nav(name, ref string) string {
603+//line gititemblob.qtpl:8
604+ qb422016 := qt422016.AcquireByteBuffer()
605+//line gititemblob.qtpl:8
606+ g.WriteNav(qb422016, name, ref)
607+//line gititemblob.qtpl:8
608+ qs422016 := string(qb422016.B)
609+//line gititemblob.qtpl:8
610+ qt422016.ReleaseByteBuffer(qb422016)
611+//line gititemblob.qtpl:8
612+ return qs422016
613+//line gititemblob.qtpl:8
614+}
615+
616+//line gititemblob.qtpl:10
617+func (g *GitItemBlobPage) StreamGitContent(qw422016 *qt422016.Writer) {
618+//line gititemblob.qtpl:10
619+ qw422016.N().S(`
620+<div class="code-view">
621+`)
622+//line gititemblob.qtpl:12
623+ qw422016.N().Z(g.Content)
624+//line gititemblob.qtpl:12
625+ qw422016.N().S(`
626+</div>
627+`)
628+//line gititemblob.qtpl:14
629+}
630+
631+//line gititemblob.qtpl:14
632+func (g *GitItemBlobPage) WriteGitContent(qq422016 qtio422016.Writer) {
633+//line gititemblob.qtpl:14
634+ qw422016 := qt422016.AcquireWriter(qq422016)
635+//line gititemblob.qtpl:14
636+ g.StreamGitContent(qw422016)
637+//line gititemblob.qtpl:14
638+ qt422016.ReleaseWriter(qw422016)
639+//line gititemblob.qtpl:14
640+}
641+
642+//line gititemblob.qtpl:14
643+func (g *GitItemBlobPage) GitContent() string {
644+//line gititemblob.qtpl:14
645+ qb422016 := qt422016.AcquireByteBuffer()
646+//line gititemblob.qtpl:14
647+ g.WriteGitContent(qb422016)
648+//line gititemblob.qtpl:14
649+ qs422016 := string(qb422016.B)
650+//line gititemblob.qtpl:14
651+ qt422016.ReleaseByteBuffer(qb422016)
652+//line gititemblob.qtpl:14
653+ return qs422016
654+//line gititemblob.qtpl:14
655+}
656diff --git a/templates/gititemtree.qtpl b/templates/gititemtree.qtpl
657index 5ace7b0ea7262684dcbb60ef67ce6f4249ff15e3..be7a27de050be204b7d90bac4fcffe073c44a921 100644
658--- a/templates/gititemtree.qtpl
659+++ b/templates/gititemtree.qtpl
660@@ -1,10 +1,28 @@
661+{% import "github.com/go-git/go-git/v5/plumbing/object" %}
662+
663 {% code
664 type GitItemTreePage struct {
665+ CurrentPath string
666+ Tree *object.Tree
667+
668+ // TODO: remove this since it can be passed by GitCommit
669+ Ref string
670+ Name string
671 }
672 %}
673
674 {% func (g *GitItemTreePage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Tree) %}{% endfunc %}
675
676 {% func (g *GitItemTreePage) GitContent() %}
677-<h4>Tree</h4>
678+{% for _, e := range g.Tree.Entries %}
679+<div class="row">
680+ <div class="col">{%s Ignore(e.Mode.ToOSFileMode()).String() %}</div>
681+ {% if e.Mode.IsFile() %}
682+ <div class="col-md"><a href="/{%s g.Name %}/blob/{%s g.Ref%}/{%s g.CurrentPath %}/{%s e.Name %}">{%s e.Name %}</a></div>
683+ {% else %}
684+ <div class="col-md"><a href="./{%s g.CurrentPath %}/{%s e.Name %}">{%s e.Name %}</a></div>
685+ {% endif %}
686+ <div class="col-md">{%dl Ignore(g.Tree.Size(e.Name))%} KiB</div>
687+</div>
688+{% endfor %}
689 {% endfunc %}
690diff --git a/templates/gititemtree.qtpl.go b/templates/gititemtree.qtpl.go
691index d8beb0e09acb90fabbe5c2bb75de765952ca11a3..cdc374fef67dd51aedbd48aad507ea3ff515e48f 100644
692--- a/templates/gititemtree.qtpl.go
693+++ b/templates/gititemtree.qtpl.go
694@@ -5,86 +5,165 @@ //line gititemtree.qtpl:1
695 package templates
696
697 //line gititemtree.qtpl:1
698+import "github.com/go-git/go-git/v5/plumbing/object"
699+
700+//line gititemtree.qtpl:3
701 import (
702 qtio422016 "io"
703
704 qt422016 "github.com/valyala/quicktemplate"
705 )
706
707-//line gititemtree.qtpl:1
708+//line gititemtree.qtpl:3
709 var (
710 _ = qtio422016.Copy
711 _ = qt422016.AcquireByteBuffer
712 )
713
714-//line gititemtree.qtpl:2
715+//line gititemtree.qtpl:4
716 type GitItemTreePage struct {
717+ CurrentPath string
718+ Tree *object.Tree
719+
720+ // TODO: remove this since it can be passed by GitCommit
721+ Ref string
722+ Name string
723 }
724
725-//line gititemtree.qtpl:6
726+//line gititemtree.qtpl:14
727 func (g *GitItemTreePage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
728-//line gititemtree.qtpl:6
729+//line gititemtree.qtpl:14
730 StreamGitItemNav(qw422016, name, ref, Tree)
731-//line gititemtree.qtpl:6
732+//line gititemtree.qtpl:14
733 }
734
735-//line gititemtree.qtpl:6
736+//line gititemtree.qtpl:14
737 func (g *GitItemTreePage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
738-//line gititemtree.qtpl:6
739+//line gititemtree.qtpl:14
740 qw422016 := qt422016.AcquireWriter(qq422016)
741-//line gititemtree.qtpl:6
742+//line gititemtree.qtpl:14
743 g.StreamNav(qw422016, name, ref)
744-//line gititemtree.qtpl:6
745+//line gititemtree.qtpl:14
746 qt422016.ReleaseWriter(qw422016)
747-//line gititemtree.qtpl:6
748+//line gititemtree.qtpl:14
749 }
750
751-//line gititemtree.qtpl:6
752+//line gititemtree.qtpl:14
753 func (g *GitItemTreePage) Nav(name, ref string) string {
754-//line gititemtree.qtpl:6
755+//line gititemtree.qtpl:14
756 qb422016 := qt422016.AcquireByteBuffer()
757-//line gititemtree.qtpl:6
758+//line gititemtree.qtpl:14
759 g.WriteNav(qb422016, name, ref)
760-//line gititemtree.qtpl:6
761+//line gititemtree.qtpl:14
762 qs422016 := string(qb422016.B)
763-//line gititemtree.qtpl:6
764+//line gititemtree.qtpl:14
765 qt422016.ReleaseByteBuffer(qb422016)
766-//line gititemtree.qtpl:6
767+//line gititemtree.qtpl:14
768 return qs422016
769-//line gititemtree.qtpl:6
770+//line gititemtree.qtpl:14
771 }
772
773-//line gititemtree.qtpl:8
774+//line gititemtree.qtpl:16
775 func (g *GitItemTreePage) StreamGitContent(qw422016 *qt422016.Writer) {
776-//line gititemtree.qtpl:8
777+//line gititemtree.qtpl:16
778+ qw422016.N().S(`
779+`)
780+//line gititemtree.qtpl:17
781+ for _, e := range g.Tree.Entries {
782+//line gititemtree.qtpl:17
783+ qw422016.N().S(`
784+<div class="row">
785+ <div class="col">`)
786+//line gititemtree.qtpl:19
787+ qw422016.E().S(Ignore(e.Mode.ToOSFileMode()).String())
788+//line gititemtree.qtpl:19
789+ qw422016.N().S(`</div>
790+ `)
791+//line gititemtree.qtpl:20
792+ if e.Mode.IsFile() {
793+//line gititemtree.qtpl:20
794+ qw422016.N().S(`
795+ <div class="col-md"><a href="/`)
796+//line gititemtree.qtpl:21
797+ qw422016.E().S(g.Name)
798+//line gititemtree.qtpl:21
799+ qw422016.N().S(`/blob/`)
800+//line gititemtree.qtpl:21
801+ qw422016.E().S(g.Ref)
802+//line gititemtree.qtpl:21
803+ qw422016.N().S(`/`)
804+//line gititemtree.qtpl:21
805+ qw422016.E().S(g.CurrentPath)
806+//line gititemtree.qtpl:21
807+ qw422016.N().S(`/`)
808+//line gititemtree.qtpl:21
809+ qw422016.E().S(e.Name)
810+//line gititemtree.qtpl:21
811+ qw422016.N().S(`">`)
812+//line gititemtree.qtpl:21
813+ qw422016.E().S(e.Name)
814+//line gititemtree.qtpl:21
815+ qw422016.N().S(`</a></div>
816+ `)
817+//line gititemtree.qtpl:22
818+ } else {
819+//line gititemtree.qtpl:22
820+ qw422016.N().S(`
821+ <div class="col-md"><a href="./`)
822+//line gititemtree.qtpl:23
823+ qw422016.E().S(g.CurrentPath)
824+//line gititemtree.qtpl:23
825+ qw422016.N().S(`/`)
826+//line gititemtree.qtpl:23
827+ qw422016.E().S(e.Name)
828+//line gititemtree.qtpl:23
829+ qw422016.N().S(`">`)
830+//line gititemtree.qtpl:23
831+ qw422016.E().S(e.Name)
832+//line gititemtree.qtpl:23
833+ qw422016.N().S(`</a></div>
834+ `)
835+//line gititemtree.qtpl:24
836+ }
837+//line gititemtree.qtpl:24
838+ qw422016.N().S(`
839+ <div class="col-md">`)
840+//line gititemtree.qtpl:25
841+ qw422016.N().DL(Ignore(g.Tree.Size(e.Name)))
842+//line gititemtree.qtpl:25
843+ qw422016.N().S(` KiB</div>
844+</div>
845+`)
846+//line gititemtree.qtpl:27
847+ }
848+//line gititemtree.qtpl:27
849 qw422016.N().S(`
850-<h4>Tree</h4>
851 `)
852-//line gititemtree.qtpl:10
853+//line gititemtree.qtpl:28
854 }
855
856-//line gititemtree.qtpl:10
857+//line gititemtree.qtpl:28
858 func (g *GitItemTreePage) WriteGitContent(qq422016 qtio422016.Writer) {
859-//line gititemtree.qtpl:10
860+//line gititemtree.qtpl:28
861 qw422016 := qt422016.AcquireWriter(qq422016)
862-//line gititemtree.qtpl:10
863+//line gititemtree.qtpl:28
864 g.StreamGitContent(qw422016)
865-//line gititemtree.qtpl:10
866+//line gititemtree.qtpl:28
867 qt422016.ReleaseWriter(qw422016)
868-//line gititemtree.qtpl:10
869+//line gititemtree.qtpl:28
870 }
871
872-//line gititemtree.qtpl:10
873+//line gititemtree.qtpl:28
874 func (g *GitItemTreePage) GitContent() string {
875-//line gititemtree.qtpl:10
876+//line gititemtree.qtpl:28
877 qb422016 := qt422016.AcquireByteBuffer()
878-//line gititemtree.qtpl:10
879+//line gititemtree.qtpl:28
880 g.WriteGitContent(qb422016)
881-//line gititemtree.qtpl:10
882+//line gititemtree.qtpl:28
883 qs422016 := string(qb422016.B)
884-//line gititemtree.qtpl:10
885+//line gititemtree.qtpl:28
886 qt422016.ReleaseByteBuffer(qb422016)
887-//line gititemtree.qtpl:10
888+//line gititemtree.qtpl:28
889 return qs422016
890-//line gititemtree.qtpl:10
891+//line gititemtree.qtpl:28
892 }
893diff --git a/templates/navbar.qtpl b/templates/navbar.qtpl
894index 775f496a4b52da8eef28656dedee80fe9995871d..9681fa4a5fd873e89621c1cdad5151f49661716b 100644
895--- a/templates/navbar.qtpl
896+++ b/templates/navbar.qtpl
897@@ -25,7 +25,10 @@ {% func Navbar (s Selection) %}
898 <nav class="container navbar navbar-expand">
899 <div class="navbar-nav">
900 <a class="nav-link{%= insertIfEqual(s, Git) %}" href="/">git</a>
901+{% comment %}
902+Add this back once needed
903 <a class="nav-link{%= insertIfEqual(s, List) %}" href="/list">list</a>
904+{% endcomment %}
905 <a class="nav-link{%= insertIfEqual(s, About) %}" href="/about">about</a>
906 <a class="nav-link{%= insertIfEqual(s, Config) %}" href="/config">config</a>
907 </div>
908diff --git a/templates/navbar.qtpl.go b/templates/navbar.qtpl.go
909index cddc6a6de17621590eb849a2ef2a27b84c661715..a2989db1381d0e7ff34c0499825bc27a2b303271 100644
910--- a/templates/navbar.qtpl.go
911+++ b/templates/navbar.qtpl.go
912@@ -86,167 +86,165 @@ //line navbar.qtpl:27
913 streaminsertIfEqual(qw422016, s, Git)
914 //line navbar.qtpl:27
915 qw422016.N().S(`" href="/">git</a>
916+`)
917+//line navbar.qtpl:31
918+ qw422016.N().S(`
919 <a class="nav-link`)
920-//line navbar.qtpl:28
921- streaminsertIfEqual(qw422016, s, List)
922-//line navbar.qtpl:28
923- qw422016.N().S(`" href="/list">list</a>
924- <a class="nav-link`)
925-//line navbar.qtpl:29
926+//line navbar.qtpl:32
927 streaminsertIfEqual(qw422016, s, About)
928-//line navbar.qtpl:29
929+//line navbar.qtpl:32
930 qw422016.N().S(`" href="/about">about</a>
931 <a class="nav-link`)
932-//line navbar.qtpl:30
933+//line navbar.qtpl:33
934 streaminsertIfEqual(qw422016, s, Config)
935-//line navbar.qtpl:30
936+//line navbar.qtpl:33
937 qw422016.N().S(`" href="/config">config</a>
938 </div>
939 </nav>
940 `)
941-//line navbar.qtpl:33
942+//line navbar.qtpl:36
943 }
944
945-//line navbar.qtpl:33
946+//line navbar.qtpl:36
947 func WriteNavbar(qq422016 qtio422016.Writer, s Selection) {
948-//line navbar.qtpl:33
949+//line navbar.qtpl:36
950 qw422016 := qt422016.AcquireWriter(qq422016)
951-//line navbar.qtpl:33
952+//line navbar.qtpl:36
953 StreamNavbar(qw422016, s)
954-//line navbar.qtpl:33
955+//line navbar.qtpl:36
956 qt422016.ReleaseWriter(qw422016)
957-//line navbar.qtpl:33
958+//line navbar.qtpl:36
959 }
960
961-//line navbar.qtpl:33
962+//line navbar.qtpl:36
963 func Navbar(s Selection) string {
964-//line navbar.qtpl:33
965+//line navbar.qtpl:36
966 qb422016 := qt422016.AcquireByteBuffer()
967-//line navbar.qtpl:33
968+//line navbar.qtpl:36
969 WriteNavbar(qb422016, s)
970-//line navbar.qtpl:33
971+//line navbar.qtpl:36
972 qs422016 := string(qb422016.B)
973-//line navbar.qtpl:33
974+//line navbar.qtpl:36
975 qt422016.ReleaseByteBuffer(qb422016)
976-//line navbar.qtpl:33
977+//line navbar.qtpl:36
978 return qs422016
979-//line navbar.qtpl:33
980+//line navbar.qtpl:36
981 }
982
983-//line navbar.qtpl:35
984+//line navbar.qtpl:38
985 func StreamGitItemNav(qw422016 *qt422016.Writer, name, ref string, s GitSelection) {
986-//line navbar.qtpl:35
987+//line navbar.qtpl:38
988 qw422016.N().S(`
989 <div class="row">
990 <h3>`)
991-//line navbar.qtpl:37
992+//line navbar.qtpl:40
993 qw422016.E().S(name)
994-//line navbar.qtpl:37
995+//line navbar.qtpl:40
996 qw422016.N().S(` `)
997-//line navbar.qtpl:37
998+//line navbar.qtpl:40
999 if ref != "" && (s == Log || s == Tree) {
1000-//line navbar.qtpl:37
1001+//line navbar.qtpl:40
1002 qw422016.N().S(`@ `)
1003-//line navbar.qtpl:37
1004+//line navbar.qtpl:40
1005 qw422016.E().S(ref)
1006-//line navbar.qtpl:37
1007+//line navbar.qtpl:40
1008 }
1009-//line navbar.qtpl:37
1010+//line navbar.qtpl:40
1011 qw422016.N().S(`</h3>
1012 </div>
1013 <div class="row">
1014 <ul class="nav">
1015 <li class="nav-item">
1016 <a class="nav-link`)
1017-//line navbar.qtpl:42
1018- streaminsertIfEqual(qw422016, s, Readme)
1019-//line navbar.qtpl:42
1020- qw422016.N().S(`" aria-current="page" href="/`)
1021-//line navbar.qtpl:42
1022- qw422016.E().S(name)
1023-//line navbar.qtpl:42
1024- qw422016.N().S(`/about">about</a>
1025- </li>
1026- <li class="nav-item">
1027- <a class="nav-link`)
1028 //line navbar.qtpl:45
1029- streaminsertIfEqual(qw422016, s, Log)
1030+ streaminsertIfEqual(qw422016, s, Readme)
1031 //line navbar.qtpl:45
1032 qw422016.N().S(`" aria-current="page" href="/`)
1033 //line navbar.qtpl:45
1034 qw422016.E().S(name)
1035 //line navbar.qtpl:45
1036- qw422016.N().S(`/log/`)
1037-//line navbar.qtpl:45
1038- qw422016.E().S(ref)
1039-//line navbar.qtpl:45
1040- qw422016.N().S(`">log</a>
1041+ qw422016.N().S(`/about">about</a>
1042 </li>
1043 <li class="nav-item">
1044 <a class="nav-link`)
1045 //line navbar.qtpl:48
1046- streaminsertIfEqual(qw422016, s, Summary)
1047+ streaminsertIfEqual(qw422016, s, Log)
1048 //line navbar.qtpl:48
1049 qw422016.N().S(`" aria-current="page" href="/`)
1050 //line navbar.qtpl:48
1051 qw422016.E().S(name)
1052 //line navbar.qtpl:48
1053- qw422016.N().S(`">summary</a>
1054+ qw422016.N().S(`/log/`)
1055+//line navbar.qtpl:48
1056+ qw422016.E().S(ref)
1057+//line navbar.qtpl:48
1058+ qw422016.N().S(`">log</a>
1059 </li>
1060 <li class="nav-item">
1061 <a class="nav-link`)
1062 //line navbar.qtpl:51
1063- streaminsertIfEqual(qw422016, s, Refs)
1064+ streaminsertIfEqual(qw422016, s, Summary)
1065 //line navbar.qtpl:51
1066 qw422016.N().S(`" aria-current="page" href="/`)
1067 //line navbar.qtpl:51
1068 qw422016.E().S(name)
1069 //line navbar.qtpl:51
1070- qw422016.N().S(`/refs">refs</a>
1071+ qw422016.N().S(`">summary</a>
1072 </li>
1073 <li class="nav-item">
1074 <a class="nav-link`)
1075 //line navbar.qtpl:54
1076- streaminsertIfEqual(qw422016, s, Tree)
1077+ streaminsertIfEqual(qw422016, s, Refs)
1078 //line navbar.qtpl:54
1079 qw422016.N().S(`" aria-current="page" href="/`)
1080 //line navbar.qtpl:54
1081 qw422016.E().S(name)
1082 //line navbar.qtpl:54
1083+ qw422016.N().S(`/refs">refs</a>
1084+ </li>
1085+ <li class="nav-item">
1086+ <a class="nav-link`)
1087+//line navbar.qtpl:57
1088+ streaminsertIfEqual(qw422016, s, Tree)
1089+//line navbar.qtpl:57
1090+ qw422016.N().S(`" aria-current="page" href="/`)
1091+//line navbar.qtpl:57
1092+ qw422016.E().S(name)
1093+//line navbar.qtpl:57
1094 qw422016.N().S(`/tree/`)
1095-//line navbar.qtpl:54
1096+//line navbar.qtpl:57
1097 qw422016.E().S(ref)
1098-//line navbar.qtpl:54
1099+//line navbar.qtpl:57
1100 qw422016.N().S(`">tree</a>
1101 </li>
1102 </ul>
1103 </div>
1104 `)
1105-//line navbar.qtpl:58
1106+//line navbar.qtpl:61
1107 }
1108
1109-//line navbar.qtpl:58
1110+//line navbar.qtpl:61
1111 func WriteGitItemNav(qq422016 qtio422016.Writer, name, ref string, s GitSelection) {
1112-//line navbar.qtpl:58
1113+//line navbar.qtpl:61
1114 qw422016 := qt422016.AcquireWriter(qq422016)
1115-//line navbar.qtpl:58
1116+//line navbar.qtpl:61
1117 StreamGitItemNav(qw422016, name, ref, s)
1118-//line navbar.qtpl:58
1119+//line navbar.qtpl:61
1120 qt422016.ReleaseWriter(qw422016)
1121-//line navbar.qtpl:58
1122+//line navbar.qtpl:61
1123 }
1124
1125-//line navbar.qtpl:58
1126+//line navbar.qtpl:61
1127 func GitItemNav(name, ref string, s GitSelection) string {
1128-//line navbar.qtpl:58
1129+//line navbar.qtpl:61
1130 qb422016 := qt422016.AcquireByteBuffer()
1131-//line navbar.qtpl:58
1132+//line navbar.qtpl:61
1133 WriteGitItemNav(qb422016, name, ref, s)
1134-//line navbar.qtpl:58
1135+//line navbar.qtpl:61
1136 qs422016 := string(qb422016.B)
1137-//line navbar.qtpl:58
1138+//line navbar.qtpl:61
1139 qt422016.ReleaseByteBuffer(qb422016)
1140-//line navbar.qtpl:58
1141+//line navbar.qtpl:61
1142 return qs422016
1143-//line navbar.qtpl:58
1144+//line navbar.qtpl:61
1145 }