cerrado @ 1b1460c8d4fa358433c51fd5293fd1c79f32aeff

feat: Add pathing to the tree tab
  1diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
  2index fd62e44b540b98d3f9dc04ab4d463215200deafa..5e5012263de12db42cb7457a21a2fad99ee50b89 100644
  3--- a/pkg/handler/git/handler.go
  4+++ b/pkg/handler/git/handler.go
  5@@ -233,6 +233,12 @@ 	ext.SetHTML(w)
  6 	name := r.PathValue("name")
  7 	ref := r.PathValue("ref")
  8 	rest := r.PathValue("rest")
  9+	paths := []string{}
 10+
 11+	// this is avoid Split from generating a len 1 array with empty string
 12+	if rest != "" {
 13+		paths = strings.Split(rest, "/")
 14+	}
 15 
 16 	tree, err := g.gitService.GetTree(name, ref, rest)
 17 	if err != nil {
 18@@ -243,8 +249,8 @@ 	gitList := &templates.GitItemPage{
 19 		Name: name,
 20 		Ref:  ref,
 21 		GitItemBase: &templates.GitItemTreePage{
 22-			CurrentPath: rest,
 23-			Tree:        tree,
 24+			Path: paths,
 25+			Tree: tree,
 26 		},
 27 	}
 28 	templates.WritePageTemplate(w, gitList)
 29@@ -256,6 +262,12 @@ 	ext.SetHTML(w)
 30 	name := r.PathValue("name")
 31 	ref := r.PathValue("ref")
 32 	rest := r.PathValue("rest")
 33+	paths := []string{}
 34+
 35+	// this is avoid Split from generating a len 1 array with empty string
 36+	if rest != "" {
 37+		paths = strings.Split(rest, "/")
 38+	}
 39 
 40 	isBin, err := g.gitService.IsBinary(name, ref, rest)
 41 	if err != nil {
 42@@ -268,7 +280,7 @@ 		gitList := &templates.GitItemPage{
 43 			Name: name,
 44 			Ref:  ref,
 45 			GitItemBase: &templates.GitItemBlobPage{
 46-				File:    rest,
 47+				Path:    paths,
 48 				Content: []byte("Binary file"),
 49 			},
 50 		}
 51@@ -303,7 +315,7 @@ 	gitList := &templates.GitItemPage{
 52 		Name: name,
 53 		Ref:  ref,
 54 		GitItemBase: &templates.GitItemBlobPage{
 55-			File:    rest,
 56+			Path:    paths,
 57 			Content: code.Bytes(),
 58 		},
 59 	}
 60diff --git a/pkg/u/file.go b/pkg/u/file.go
 61index cf86c7513b5e1d802fb9a7f0afc6d4442bae3ba4..fafe0fb00f4b30262594af5ab6b32873515301bb 100644
 62--- a/pkg/u/file.go
 63+++ b/pkg/u/file.go
 64@@ -4,6 +4,7 @@ import (
 65 	"errors"
 66 	"log/slog"
 67 	"os"
 68+	"path/filepath"
 69 )
 70 
 71 func FileExist(filename string) bool {
 72@@ -19,3 +20,23 @@ 		// report the file doest not exist
 73 		return false
 74 	}
 75 }
 76+
 77+// This is just a slin wraper to make easier to compose path in the template
 78+type Pathing string
 79+
 80+func Root() Pathing {
 81+	return "/"
 82+}
 83+
 84+func (s Pathing) AddPath(p string) Pathing {
 85+	return Pathing(filepath.Join(string(s), p))
 86+}
 87+
 88+func (s Pathing) AddPaths(p []string) Pathing {
 89+	f := filepath.Join(p...)
 90+	return Pathing(filepath.Join(string(s), f))
 91+}
 92+
 93+func (s Pathing) Done() string {
 94+	return string(s)
 95+}
 96diff --git a/pkg/u/list.go b/pkg/u/list.go
 97index 7271ef3783e892aad55ea49786515f491af30735..39d7b117fa7b9a509be2fa3f7946dc11945ce812 100644
 98--- a/pkg/u/list.go
 99+++ b/pkg/u/list.go
100@@ -16,12 +16,12 @@ 	}
101 	return v[0]
102 }
103 
104-func Map[T any, V any](ts []T, fun func(T) V) []V {
105-	rs := make([]V, len(ts))
106-	for i := range ts {
107-		rs[i] = fun(ts[i])
108+func LastOrZero[T any](v []T) T {
109+	if len(v) == 0 {
110+		var zero T
111+		return zero
112 	}
113-	return rs
114+	return v[len(v)-1]
115 }
116 
117 func ChunkBy[T any](items []T, chunkSize int) [][]T {
118diff --git a/pkg/u/list_test.go b/pkg/u/list_test.go
119index 3a856b961818256ffdd0842824879169af645f7b..805a2091b59ce4c644f748b4b6c49a28aec50cdb 100644
120--- a/pkg/u/list_test.go
121+++ b/pkg/u/list_test.go
122@@ -3,7 +3,6 @@
123 package u
124 
125 import (
126-	"strconv"
127 	"testing"
128 
129 	"github.com/google/go-cmp/cmp"
130@@ -130,32 +129,3 @@
131 		})
132 	}
133 }
134-
135-func TestMap(t *testing.T) {
136-	testCases := []struct {
137-		name string
138-		in   []int
139-		out  []string
140-	}{
141-		{
142-			name: "empty",
143-			in:   []int{},
144-			out:  []string{},
145-		},
146-		{
147-			name: "not empty",
148-			in:   []int{1, 2, 3},
149-			out:  []string{"1", "2", "3"},
150-		},
151-	}
152-
153-	for _, tc := range testCases {
154-		t.Run(tc.name, func(t *testing.T) {
155-			out := Map(tc.in, func(v int) string { return strconv.Itoa(v) })
156-
157-			if diff := cmp.Diff(tc.out, out); diff != "" {
158-				t.Errorf("Map error:\n%s", diff)
159-			}
160-		})
161-	}
162-}
163diff --git a/scss/main.scss b/scss/main.scss
164index 893e66c6a16cf2ed3b6b5f1ebcb2e3674efcc001..4a09925a0811d8a409385fa748543b9dc8ef199f 100644
165--- a/scss/main.scss
166+++ b/scss/main.scss
167@@ -122,6 +122,11 @@     display: grid;
168     overflow-x: auto;
169 }
170 
171+.pathing{
172+  margin-left: $spacer;
173+  display: inline-block
174+}
175+
176 pre {
177     display: grid;
178     overflow-x: auto;
179diff --git a/templates/gititemblob.qtpl b/templates/gititemblob.qtpl
180index f9bab3d53aa36fdc211bab7c9feea16b179b333f..ca3a1faaf12d3dc0cf337b42cecfa209ba6a1938 100644
181--- a/templates/gititemblob.qtpl
182+++ b/templates/gititemblob.qtpl
183@@ -1,6 +1,8 @@
184+{% import "git.gabrielgio.me/cerrado/pkg/u" %}
185+
186 {% code
187 type GitItemBlobPage struct {
188-    File string
189+    Path []string
190     Content []byte
191 }
192 %}
193@@ -8,6 +10,19 @@
194 {% func (g *GitItemBlobPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Tree) %}{% endfunc %}
195 
196 {% func (g *GitItemBlobPage) GitContent(name, ref string) %}
197+<div class="pathing">
198+    {% stripspace %}
199+    {% if len(g.Path) != 0 %}
200+    <a href="{%s url(name, Folder, ref, Root, []string{}) %}">root/</a>
201+    {% for i, e := range g.Path[:len(g.Path)-1] %}
202+    <a href="{%s url(name, Folder, ref, Root, g.Path[:1+i]) %}">{%s e %}/</a>
203+    {% endfor %}
204+    <a>{%s u.LastOrZero(g.Path) %}</a>
205+    {% else %}
206+    <a>root/</a>
207+    {% endif %}
208+    {% endstripspace %}
209+</div>
210 <div class="code-view">
211 {%z= g.Content %}
212 </div>
213diff --git a/templates/gititemblob.qtpl.go b/templates/gititemblob.qtpl.go
214index 05e0667c856d5ff46a2222d8a4979da2de1ea4ef..5d986b4928df2b4ee4fcb489179821ff7759fd90 100644
215--- a/templates/gititemblob.qtpl.go
216+++ b/templates/gititemblob.qtpl.go
217@@ -5,94 +5,136 @@ //line gititemblob.qtpl:1
218 package templates
219 
220 //line gititemblob.qtpl:1
221+import "git.gabrielgio.me/cerrado/pkg/u"
222+
223+//line gititemblob.qtpl:3
224 import (
225 	qtio422016 "io"
226 
227 	qt422016 "github.com/valyala/quicktemplate"
228 )
229 
230-//line gititemblob.qtpl:1
231+//line gititemblob.qtpl:3
232 var (
233 	_ = qtio422016.Copy
234 	_ = qt422016.AcquireByteBuffer
235 )
236 
237-//line gititemblob.qtpl:2
238+//line gititemblob.qtpl:4
239 type GitItemBlobPage struct {
240-	File    string
241+	Path    []string
242 	Content []byte
243 }
244 
245-//line gititemblob.qtpl:8
246+//line gititemblob.qtpl:10
247 func (g *GitItemBlobPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
248-//line gititemblob.qtpl:8
249+//line gititemblob.qtpl:10
250 	StreamGitItemNav(qw422016, name, ref, Tree)
251-//line gititemblob.qtpl:8
252+//line gititemblob.qtpl:10
253 }
254 
255-//line gititemblob.qtpl:8
256+//line gititemblob.qtpl:10
257 func (g *GitItemBlobPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
258-//line gititemblob.qtpl:8
259+//line gititemblob.qtpl:10
260 	qw422016 := qt422016.AcquireWriter(qq422016)
261-//line gititemblob.qtpl:8
262+//line gititemblob.qtpl:10
263 	g.StreamNav(qw422016, name, ref)
264-//line gititemblob.qtpl:8
265+//line gititemblob.qtpl:10
266 	qt422016.ReleaseWriter(qw422016)
267-//line gititemblob.qtpl:8
268+//line gititemblob.qtpl:10
269 }
270 
271-//line gititemblob.qtpl:8
272+//line gititemblob.qtpl:10
273 func (g *GitItemBlobPage) Nav(name, ref string) string {
274-//line gititemblob.qtpl:8
275+//line gititemblob.qtpl:10
276 	qb422016 := qt422016.AcquireByteBuffer()
277-//line gititemblob.qtpl:8
278+//line gititemblob.qtpl:10
279 	g.WriteNav(qb422016, name, ref)
280-//line gititemblob.qtpl:8
281+//line gititemblob.qtpl:10
282 	qs422016 := string(qb422016.B)
283-//line gititemblob.qtpl:8
284+//line gititemblob.qtpl:10
285 	qt422016.ReleaseByteBuffer(qb422016)
286-//line gititemblob.qtpl:8
287+//line gititemblob.qtpl:10
288 	return qs422016
289-//line gititemblob.qtpl:8
290+//line gititemblob.qtpl:10
291 }
292 
293-//line gititemblob.qtpl:10
294+//line gititemblob.qtpl:12
295 func (g *GitItemBlobPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
296-//line gititemblob.qtpl:10
297+//line gititemblob.qtpl:12
298 	qw422016.N().S(`
299+<div class="pathing">
300+    `)
301+//line gititemblob.qtpl:15
302+	if len(g.Path) != 0 {
303+//line gititemblob.qtpl:15
304+		qw422016.N().S(`<a href="`)
305+//line gititemblob.qtpl:16
306+		qw422016.E().S(url(name, Folder, ref, Root, []string{}))
307+//line gititemblob.qtpl:16
308+		qw422016.N().S(`">root/</a>`)
309+//line gititemblob.qtpl:17
310+		for i, e := range g.Path[:len(g.Path)-1] {
311+//line gititemblob.qtpl:17
312+			qw422016.N().S(`<a href="`)
313+//line gititemblob.qtpl:18
314+			qw422016.E().S(url(name, Folder, ref, Root, g.Path[:1+i]))
315+//line gititemblob.qtpl:18
316+			qw422016.N().S(`">`)
317+//line gititemblob.qtpl:18
318+			qw422016.E().S(e)
319+//line gititemblob.qtpl:18
320+			qw422016.N().S(`/</a>`)
321+//line gititemblob.qtpl:19
322+		}
323+//line gititemblob.qtpl:19
324+		qw422016.N().S(`<a>`)
325+//line gititemblob.qtpl:20
326+		qw422016.E().S(u.LastOrZero(g.Path))
327+//line gititemblob.qtpl:20
328+		qw422016.N().S(`</a>`)
329+//line gititemblob.qtpl:21
330+	} else {
331+//line gititemblob.qtpl:21
332+		qw422016.N().S(`<a>root/</a>`)
333+//line gititemblob.qtpl:23
334+	}
335+//line gititemblob.qtpl:24
336+	qw422016.N().S(`
337+</div>
338 <div class="code-view">
339 `)
340-//line gititemblob.qtpl:12
341+//line gititemblob.qtpl:27
342 	qw422016.N().Z(g.Content)
343-//line gititemblob.qtpl:12
344+//line gititemblob.qtpl:27
345 	qw422016.N().S(`
346 </div>
347 `)
348-//line gititemblob.qtpl:14
349+//line gititemblob.qtpl:29
350 }
351 
352-//line gititemblob.qtpl:14
353+//line gititemblob.qtpl:29
354 func (g *GitItemBlobPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
355-//line gititemblob.qtpl:14
356+//line gititemblob.qtpl:29
357 	qw422016 := qt422016.AcquireWriter(qq422016)
358-//line gititemblob.qtpl:14
359+//line gititemblob.qtpl:29
360 	g.StreamGitContent(qw422016, name, ref)
361-//line gititemblob.qtpl:14
362+//line gititemblob.qtpl:29
363 	qt422016.ReleaseWriter(qw422016)
364-//line gititemblob.qtpl:14
365+//line gititemblob.qtpl:29
366 }
367 
368-//line gititemblob.qtpl:14
369+//line gititemblob.qtpl:29
370 func (g *GitItemBlobPage) GitContent(name, ref string) string {
371-//line gititemblob.qtpl:14
372+//line gititemblob.qtpl:29
373 	qb422016 := qt422016.AcquireByteBuffer()
374-//line gititemblob.qtpl:14
375+//line gititemblob.qtpl:29
376 	g.WriteGitContent(qb422016, name, ref)
377-//line gititemblob.qtpl:14
378+//line gititemblob.qtpl:29
379 	qs422016 := string(qb422016.B)
380-//line gititemblob.qtpl:14
381+//line gititemblob.qtpl:29
382 	qt422016.ReleaseByteBuffer(qb422016)
383-//line gititemblob.qtpl:14
384+//line gititemblob.qtpl:29
385 	return qs422016
386-//line gititemblob.qtpl:14
387+//line gititemblob.qtpl:29
388 }
389diff --git a/templates/gititemtree.qtpl b/templates/gititemtree.qtpl
390index ffc063dff52d97495cdc7df57c686fa2e67b1e6a..86fb29cbac5c8aa52d98b729ca13e839ca839db8 100644
391--- a/templates/gititemtree.qtpl
392+++ b/templates/gititemtree.qtpl
393@@ -1,24 +1,62 @@
394+{% import "git.gabrielgio.me/cerrado/pkg/u" %}
395 {% import "github.com/go-git/go-git/v5/plumbing/object" %}
396 
397-{% code
398-type GitItemTreePage struct {
399-    CurrentPath string
400+{% code type GitItemTreePage struct {
401+    Path []string
402     Tree *object.Tree
403+}
404+%}
405+
406+{% code const (
407+    Folder = "tree"
408+    Blob = "blob"
409+    Root = ""
410+)
411+%}
412+
413+{% code func url(name, mode, ref, filename string, path []string) string {
414+    return u.Root().
415+        AddPath(name).
416+        AddPath(mode).
417+        AddPath(ref).
418+        AddPaths(path).
419+        AddPath(filename).
420+        Done()
421 }
422 %}
423 
424 {% func (g *GitItemTreePage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Tree) %}{% endfunc %}
425 
426 {% func (g *GitItemTreePage) GitContent(name, ref string) %}
427+<div class="pathing">
428+    {% stripspace %}
429+    {% if len(g.Path) != 0 %}
430+    <a href="{%s url(name, Folder, ref, Root, []string{}) %}">root/</a>
431+    {% for i, e := range g.Path[:len(g.Path)-1] %}
432+    <a href="{%s url(name, Folder, ref, Root, g.Path[:1+i]) %}">{%s e %}/</a>
433+    {% endfor %}
434+    <a>{%s u.LastOrZero(g.Path) %}</a>
435+    {% else %}
436+    <a>root/</a>
437+    {% endif %}
438+    {% endstripspace %}
439+</div>
440 <div class="row">
441   <div class="col-md-12">
442     <div class="tree-list">
443+      {% if len(g.Path) != 0 %}
444+          <div class="mode"><a href="{%s url(name, Folder, ref, g.Path[len(g.Path)-1], g.Path[:len(g.Path)-1]) %}">..</a></div>
445+          <div class="name tree"></div>
446+          <div class="commit"></div>
447+          <div class="date"></div>
448+          <div class="size"></div>
449+      {% endif %}
450       {% for _, e := range g.Tree.Entries %}
451           <div class="mode">{%s Ignore(e.Mode.ToOSFileMode()).String() %}</div>
452           {% if e.Mode.IsFile() %}
453-          <div class="name blob"><a href="/{%s name %}/blob/{%s ref%}/{%s g.CurrentPath %}/{%s e.Name %}">{%s e.Name %}</a></div>
454+          <div class="name blob"><a href="{%s url(name, Blob, ref, e.Name, g.Path) %}">{%s e.Name %}</a></div>
455           {% else %}
456-          <div class="name tree"><a href="./{%s g.CurrentPath %}/{%s e.Name %}">{%s e.Name %}</a></div>
457+          <div class="name tree"><a href="{%s url(name, Folder, ref, e.Name, g.Path) %}">{%s e.Name %}</a></div>
458           {% endif %}
459           <div class="commit"></div>
460           <div class="date"></div>
461diff --git a/templates/gititemtree.qtpl.go b/templates/gititemtree.qtpl.go
462index 0e9b09e05723a383d173474668cea00b3f680793..c0fc3a7787bc21e5a1755a73a878af40c1531c8c 100644
463--- a/templates/gititemtree.qtpl.go
464+++ b/templates/gititemtree.qtpl.go
465@@ -5,16 +5,19 @@ //line gititemtree.qtpl:1
466 package templates
467 
468 //line gititemtree.qtpl:1
469+import "git.gabrielgio.me/cerrado/pkg/u"
470+
471+//line gititemtree.qtpl:2
472 import "github.com/go-git/go-git/v5/plumbing/object"
473 
474-//line gititemtree.qtpl:3
475+//line gititemtree.qtpl:4
476 import (
477 	qtio422016 "io"
478 
479 	qt422016 "github.com/valyala/quicktemplate"
480 )
481 
482-//line gititemtree.qtpl:3
483+//line gititemtree.qtpl:4
484 var (
485 	_ = qtio422016.Copy
486 	_ = qt422016.AcquireByteBuffer
487@@ -22,150 +25,210 @@ )
488 
489 //line gititemtree.qtpl:4
490 type GitItemTreePage struct {
491-	CurrentPath string
492-	Tree        *object.Tree
493+	Path []string
494+	Tree *object.Tree
495 }
496 
497 //line gititemtree.qtpl:10
498+const (
499+	Folder = "tree"
500+	Blob   = "blob"
501+	Root   = ""
502+)
503+
504+//line gititemtree.qtpl:17
505+func url(name, mode, ref, filename string, path []string) string {
506+	return u.Root().
507+		AddPath(name).
508+		AddPath(mode).
509+		AddPath(ref).
510+		AddPaths(path).
511+		AddPath(filename).
512+		Done()
513+}
514+
515+//line gititemtree.qtpl:28
516 func (g *GitItemTreePage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
517-//line gititemtree.qtpl:10
518+//line gititemtree.qtpl:28
519 	StreamGitItemNav(qw422016, name, ref, Tree)
520-//line gititemtree.qtpl:10
521+//line gititemtree.qtpl:28
522 }
523 
524-//line gititemtree.qtpl:10
525+//line gititemtree.qtpl:28
526 func (g *GitItemTreePage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
527-//line gititemtree.qtpl:10
528+//line gititemtree.qtpl:28
529 	qw422016 := qt422016.AcquireWriter(qq422016)
530-//line gititemtree.qtpl:10
531+//line gititemtree.qtpl:28
532 	g.StreamNav(qw422016, name, ref)
533-//line gititemtree.qtpl:10
534+//line gititemtree.qtpl:28
535 	qt422016.ReleaseWriter(qw422016)
536-//line gititemtree.qtpl:10
537+//line gititemtree.qtpl:28
538 }
539 
540-//line gititemtree.qtpl:10
541+//line gititemtree.qtpl:28
542 func (g *GitItemTreePage) Nav(name, ref string) string {
543-//line gititemtree.qtpl:10
544+//line gititemtree.qtpl:28
545 	qb422016 := qt422016.AcquireByteBuffer()
546-//line gititemtree.qtpl:10
547+//line gititemtree.qtpl:28
548 	g.WriteNav(qb422016, name, ref)
549-//line gititemtree.qtpl:10
550+//line gititemtree.qtpl:28
551 	qs422016 := string(qb422016.B)
552-//line gititemtree.qtpl:10
553+//line gititemtree.qtpl:28
554 	qt422016.ReleaseByteBuffer(qb422016)
555-//line gititemtree.qtpl:10
556+//line gititemtree.qtpl:28
557 	return qs422016
558-//line gititemtree.qtpl:10
559+//line gititemtree.qtpl:28
560 }
561 
562-//line gititemtree.qtpl:12
563+//line gititemtree.qtpl:30
564 func (g *GitItemTreePage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
565-//line gititemtree.qtpl:12
566+//line gititemtree.qtpl:30
567+	qw422016.N().S(`
568+<div class="pathing">
569+    `)
570+//line gititemtree.qtpl:33
571+	if len(g.Path) != 0 {
572+//line gititemtree.qtpl:33
573+		qw422016.N().S(`<a href="`)
574+//line gititemtree.qtpl:34
575+		qw422016.E().S(url(name, Folder, ref, Root, []string{}))
576+//line gititemtree.qtpl:34
577+		qw422016.N().S(`">root/</a>`)
578+//line gititemtree.qtpl:35
579+		for i, e := range g.Path[:len(g.Path)-1] {
580+//line gititemtree.qtpl:35
581+			qw422016.N().S(`<a href="`)
582+//line gititemtree.qtpl:36
583+			qw422016.E().S(url(name, Folder, ref, Root, g.Path[:1+i]))
584+//line gititemtree.qtpl:36
585+			qw422016.N().S(`">`)
586+//line gititemtree.qtpl:36
587+			qw422016.E().S(e)
588+//line gititemtree.qtpl:36
589+			qw422016.N().S(`/</a>`)
590+//line gititemtree.qtpl:37
591+		}
592+//line gititemtree.qtpl:37
593+		qw422016.N().S(`<a>`)
594+//line gititemtree.qtpl:38
595+		qw422016.E().S(u.LastOrZero(g.Path))
596+//line gititemtree.qtpl:38
597+		qw422016.N().S(`</a>`)
598+//line gititemtree.qtpl:39
599+	} else {
600+//line gititemtree.qtpl:39
601+		qw422016.N().S(`<a>root/</a>`)
602+//line gititemtree.qtpl:41
603+	}
604+//line gititemtree.qtpl:42
605 	qw422016.N().S(`
606+</div>
607 <div class="row">
608   <div class="col-md-12">
609     <div class="tree-list">
610       `)
611-//line gititemtree.qtpl:16
612+//line gititemtree.qtpl:47
613+	if len(g.Path) != 0 {
614+//line gititemtree.qtpl:47
615+		qw422016.N().S(`
616+          <div class="mode"><a href="`)
617+//line gititemtree.qtpl:48
618+		qw422016.E().S(url(name, Folder, ref, g.Path[len(g.Path)-1], g.Path[:len(g.Path)-1]))
619+//line gititemtree.qtpl:48
620+		qw422016.N().S(`">..</a></div>
621+          <div class="name tree"></div>
622+          <div class="commit"></div>
623+          <div class="date"></div>
624+          <div class="size"></div>
625+      `)
626+//line gititemtree.qtpl:53
627+	}
628+//line gititemtree.qtpl:53
629+	qw422016.N().S(`
630+      `)
631+//line gititemtree.qtpl:54
632 	for _, e := range g.Tree.Entries {
633-//line gititemtree.qtpl:16
634+//line gititemtree.qtpl:54
635 		qw422016.N().S(`
636           <div class="mode">`)
637-//line gititemtree.qtpl:17
638+//line gititemtree.qtpl:55
639 		qw422016.E().S(Ignore(e.Mode.ToOSFileMode()).String())
640-//line gititemtree.qtpl:17
641+//line gititemtree.qtpl:55
642 		qw422016.N().S(`</div>
643           `)
644-//line gititemtree.qtpl:18
645+//line gititemtree.qtpl:56
646 		if e.Mode.IsFile() {
647-//line gititemtree.qtpl:18
648+//line gititemtree.qtpl:56
649 			qw422016.N().S(`
650-          <div class="name blob"><a href="/`)
651-//line gititemtree.qtpl:19
652-			qw422016.E().S(name)
653-//line gititemtree.qtpl:19
654-			qw422016.N().S(`/blob/`)
655-//line gititemtree.qtpl:19
656-			qw422016.E().S(ref)
657-//line gititemtree.qtpl:19
658-			qw422016.N().S(`/`)
659-//line gititemtree.qtpl:19
660-			qw422016.E().S(g.CurrentPath)
661-//line gititemtree.qtpl:19
662-			qw422016.N().S(`/`)
663-//line gititemtree.qtpl:19
664-			qw422016.E().S(e.Name)
665-//line gititemtree.qtpl:19
666+          <div class="name blob"><a href="`)
667+//line gititemtree.qtpl:57
668+			qw422016.E().S(url(name, Blob, ref, e.Name, g.Path))
669+//line gititemtree.qtpl:57
670 			qw422016.N().S(`">`)
671-//line gititemtree.qtpl:19
672+//line gititemtree.qtpl:57
673 			qw422016.E().S(e.Name)
674-//line gititemtree.qtpl:19
675+//line gititemtree.qtpl:57
676 			qw422016.N().S(`</a></div>
677           `)
678-//line gititemtree.qtpl:20
679+//line gititemtree.qtpl:58
680 		} else {
681-//line gititemtree.qtpl:20
682+//line gititemtree.qtpl:58
683 			qw422016.N().S(`
684-          <div class="name tree"><a href="./`)
685-//line gititemtree.qtpl:21
686-			qw422016.E().S(g.CurrentPath)
687-//line gititemtree.qtpl:21
688-			qw422016.N().S(`/`)
689-//line gititemtree.qtpl:21
690-			qw422016.E().S(e.Name)
691-//line gititemtree.qtpl:21
692+          <div class="name tree"><a href="`)
693+//line gititemtree.qtpl:59
694+			qw422016.E().S(url(name, Folder, ref, e.Name, g.Path))
695+//line gititemtree.qtpl:59
696 			qw422016.N().S(`">`)
697-//line gititemtree.qtpl:21
698+//line gititemtree.qtpl:59
699 			qw422016.E().S(e.Name)
700-//line gititemtree.qtpl:21
701+//line gititemtree.qtpl:59
702 			qw422016.N().S(`</a></div>
703           `)
704-//line gititemtree.qtpl:22
705+//line gititemtree.qtpl:60
706 		}
707-//line gititemtree.qtpl:22
708+//line gititemtree.qtpl:60
709 		qw422016.N().S(`
710           <div class="commit"></div>
711           <div class="date"></div>
712           <div class="size">`)
713-//line gititemtree.qtpl:25
714+//line gititemtree.qtpl:63
715 		qw422016.N().DL(Ignore(g.Tree.Size(e.Name)))
716-//line gititemtree.qtpl:25
717+//line gititemtree.qtpl:63
718 		qw422016.N().S(` KiB</div>
719       `)
720-//line gititemtree.qtpl:26
721+//line gititemtree.qtpl:64
722 	}
723-//line gititemtree.qtpl:26
724+//line gititemtree.qtpl:64
725 	qw422016.N().S(`
726     </div>
727   </div>
728 </div>
729 `)
730-//line gititemtree.qtpl:30
731+//line gititemtree.qtpl:68
732 }
733 
734-//line gititemtree.qtpl:30
735+//line gititemtree.qtpl:68
736 func (g *GitItemTreePage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
737-//line gititemtree.qtpl:30
738+//line gititemtree.qtpl:68
739 	qw422016 := qt422016.AcquireWriter(qq422016)
740-//line gititemtree.qtpl:30
741+//line gititemtree.qtpl:68
742 	g.StreamGitContent(qw422016, name, ref)
743-//line gititemtree.qtpl:30
744+//line gititemtree.qtpl:68
745 	qt422016.ReleaseWriter(qw422016)
746-//line gititemtree.qtpl:30
747+//line gititemtree.qtpl:68
748 }
749 
750-//line gititemtree.qtpl:30
751+//line gititemtree.qtpl:68
752 func (g *GitItemTreePage) GitContent(name, ref string) string {
753-//line gititemtree.qtpl:30
754+//line gititemtree.qtpl:68
755 	qb422016 := qt422016.AcquireByteBuffer()
756-//line gititemtree.qtpl:30
757+//line gititemtree.qtpl:68
758 	g.WriteGitContent(qb422016, name, ref)
759-//line gititemtree.qtpl:30
760+//line gititemtree.qtpl:68
761 	qs422016 := string(qb422016.B)
762-//line gititemtree.qtpl:30
763+//line gititemtree.qtpl:68
764 	qt422016.ReleaseByteBuffer(qb422016)
765-//line gititemtree.qtpl:30
766+//line gititemtree.qtpl:68
767 	return qs422016
768-//line gititemtree.qtpl:30
769+//line gititemtree.qtpl:68
770 }