master
1package main
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strings"
8
9 "github.com/antonmedv/gitmal/pkg/git"
10 "github.com/antonmedv/gitmal/pkg/templates"
11)
12
13const dot = "ยท"
14
15func echo(a ...any) {
16 _, _ = fmt.Fprintln(os.Stderr, a...)
17}
18
19func breadcrumbs(rootName string, path string, isFile bool) []templates.Breadcrumb {
20 // Root list
21 if path == "" {
22 return []templates.Breadcrumb{
23 {
24 Name: rootName,
25 Href: "./index.html",
26 IsDir: true,
27 },
28 }
29 }
30
31 // Paths from git are already with '/'
32 parts := strings.Split(path, "/")
33
34 // Build breadcrumbs relative to the file location so links work in static output
35 // Example: for a/b/c.txt, at /blob/<ref>/a/b/c.txt.html
36 // - root: ../../index.html
37 // - a: ../index.html
38 // - b: index.html
39 // - c.txt: (no link)
40 d := len(parts)
41
42 // current directory depth relative to ref
43 if isFile {
44 d -= 1
45 }
46
47 crumbs := make([]templates.Breadcrumb, 0, len(parts))
48
49 // root
50 crumbs = append(crumbs, templates.Breadcrumb{
51 Name: rootName,
52 Href: "./" + strings.Repeat("../", d) + "index.html",
53 IsDir: true,
54 })
55
56 // intermediate directories
57 for i := 0; i < len(parts)-1; i++ {
58 name := parts[i]
59 // target directory depth t = i+1
60 up := d - (i + 1)
61 href := "./" + strings.Repeat("../", up) + "index.html"
62 crumbs = append(crumbs, templates.Breadcrumb{
63 Name: name,
64 Href: href,
65 IsDir: true,
66 })
67 }
68
69 // final file (no link)
70 crumbs = append(crumbs, templates.Breadcrumb{
71 Name: parts[len(parts)-1],
72 IsDir: !isFile,
73 })
74
75 return crumbs
76}
77
78func humanizeSize(size int64) string {
79 const unit = 1024
80 if size < unit {
81 return fmt.Sprintf("%d B", size)
82 }
83 div, exp := int64(unit), 0
84 for n := size / unit; n >= unit; n /= unit {
85 div *= unit
86 exp++
87 }
88 return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp])
89}
90
91func isMarkdown(path string) bool {
92 lower := strings.ToLower(path)
93 if strings.HasSuffix(lower, ".md") || strings.HasSuffix(lower, ".markdown") || strings.HasSuffix(lower, ".mdown") || strings.HasSuffix(lower, ".mkd") || strings.HasSuffix(lower, ".mkdown") {
94 return true
95 }
96 return false
97}
98
99func isImage(path string) bool {
100 switch filepath.Ext(path) {
101 case ".png", ".jpg", ".jpeg", ".gif", ".webp":
102 return true
103 default:
104 return false
105 }
106}
107
108func containsBranch(branches []git.Ref, branch string) bool {
109 for _, b := range branches {
110 if b.String() == branch {
111 return true
112 }
113 }
114 return false
115}
116
117func hasConflictingBranchNames(branches []git.Ref) (bool, git.Ref, git.Ref) {
118 uniq := make(map[string]git.Ref, len(branches))
119 for _, b := range branches {
120 if a, exists := uniq[b.DirName()]; exists {
121 return true, a, b
122 }
123 uniq[b.DirName()] = b
124 }
125 return false, git.Ref{}, git.Ref{}
126}