internal/httpd/filenav.go

0338e6ace3de199d5fc383852649919b68ef3e42
gitbay/internal/httpd/filenav.go history · blame · raw

72 lines · 1975 bytes

 1package httpd
 2
 3import (
 4	"path"
 5	"sort"
 6
 7	"gitbay.org/gitbay/internal/gitutil"
 8)
 9
10// fileNav is the column beside a file: its directory's entries, the file
11// marked, and a link up. It is the tree page's listing rendered as a
12// list, so reading a repository does not mean going back for each file.
13type fileNav struct {
14	Title   string // the directory, or the repository name at the root
15	Parent  string // URL of the parent tree; "" at the root
16	Entries []fileNavEntry
17}
18
19type fileNavEntry struct {
20	Name    string // directories carry a trailing slash
21	URL     string
22	Dir     bool
23	Current bool
24}
25
26// sortDirsFirst orders a listing by shape before name, stably, so each
27// group keeps the order git gave it. The tree page and the navigator
28// share it.
29func sortDirsFirst(entries []gitutil.TreeEntry) {
30	sort.SliceStable(entries, func(i, j int) bool {
31		return entries[i].Type == "tree" && entries[j].Type != "tree"
32	})
33}
34
35// navDir is the directory ListTree wants for filePath: "" at the root.
36func navDir(filePath string) string {
37	if d := path.Dir(filePath); d != "." {
38		return d
39	}
40	return ""
41}
42
43// fileNavFor builds the navigator for filePath from its directory's
44// entries. repoPath is owner/name.
45func fileNavFor(repoPath, ref, filePath string, entries []gitutil.TreeEntry) fileNav {
46	dir := path.Dir(filePath)
47	if dir == "." {
48		dir = ""
49	}
50	base := "/" + repoPath
51	nav := fileNav{Title: dir}
52	if dir == "" {
53		nav.Title = path.Base(repoPath)
54	} else if up := path.Dir(dir); up == "." {
55		nav.Parent = base + "/tree/" + ref
56	} else {
57		nav.Parent = base + "/tree/" + ref + "/" + up
58	}
59	sortDirsFirst(entries)
60	for _, e := range entries {
61		full := path.Join(dir, e.Name)
62		ent := fileNavEntry{Name: e.Name, Dir: e.Type == "tree", Current: full == filePath}
63		if ent.Dir {
64			ent.Name += "/"
65			ent.URL = base + "/tree/" + ref + "/" + full
66		} else {
67			ent.URL = base + "/blob/" + ref + "/" + full
68		}
69		nav.Entries = append(nav.Entries, ent)
70	}
71	return nav
72}