package main
import (
"html/template"
"sort"
"strings"
"time"
)
type RepoInfo struct {
Name string
Path string
GitDir string
Description string
Owner string
LastUpdated time.Time
Git *gitCLIBackend
}
type CommitInfo struct {
Hash string
ShortHash string
Subject string
Body string
Author string
AuthorEmail string
AuthorDate time.Time
Parents []string
}
type TreeEntryInfo struct {
Name string
IsDir bool
Size int64
Mode string
Hash string
}
type BlobInfo struct {
Name string
Size int64
IsBinary bool
Lines []string
Content string
}
type RefInfo struct {
Name string
Hash string
ShortHash string
Subject string
Author string
Date time.Time
IsTag bool
}
type DiffFile struct {
OldName string
NewName string
Status string
Hunks []DiffHunk
IsBinary bool
Stats DiffStats
}
func diffFileName(file DiffFile) string {
if file.NewName != "" {
return file.NewName
}
return file.OldName
}
type DiffStats struct {
Added int
Deleted int
}
type DiffHunk struct {
Header string
Lines []DiffLine
}
type DiffLine struct {
Type string // "context", "add", "del"
Content string
// Highlighted contains escaped, syntax-highlighted source.
Highlighted template.HTML
OldNum int
NewNum int
}
type TreeNode struct {
Name string
IsDir bool
Size int64
Path string
Depth int
IsOpen bool
IsActive bool
}
const maxBlobDisplaySize = 1 << 20 // 1MB
const diffContextLines = 5
const maxDiffFiles = 256 // max files rendered per commit
func sortTreeEntries(entries []TreeEntryInfo) {
sort.Slice(entries, func(i, j int) bool {
if entries[i].IsDir != entries[j].IsDir {
return entries[i].IsDir
}
return entries[i].Name < entries[j].Name
})
}
// collapseContext takes a flat list of diff lines and splits them into
// hunks, keeping only diffContextLines of context around add/del lines.
func collapseContext(lines []DiffLine) []DiffHunk {
if len(lines) == 0 {
return nil
}
// Mark which lines to keep: diffContextLines around each changed line.
keep := make([]bool, len(lines))
for i, l := range lines {
if l.Type == "add" || l.Type == "del" {
start := i - diffContextLines
if start < 0 {
start = 0
}
end := i + diffContextLines
if end >= len(lines) {
end = len(lines) - 1
}
for j := start; j <= end; j++ {
keep[j] = true
}
}
}
// Build hunks from contiguous kept ranges.
var hunks []DiffHunk
var current *DiffHunk
for i, l := range lines {
if keep[i] {
if current == nil {
current = &DiffHunk{}
}
current.Lines = append(current.Lines, l)
} else {
if current != nil {
hunks = append(hunks, *current)
current = nil
}
}
}
if current != nil {
hunks = append(hunks, *current)
}
return hunks
}
var mimeTypes = map[string]string{
".txt": "text/plain; charset=utf-8",
".md": "text/plain; charset=utf-8",
".go": "text/plain; charset=utf-8",
".rs": "text/plain; charset=utf-8",
".py": "text/plain; charset=utf-8",
".js": "text/plain; charset=utf-8",
".ts": "text/plain; charset=utf-8",
".c": "text/plain; charset=utf-8",
".h": "text/plain; charset=utf-8",
".css": "text/css; charset=utf-8",
".html": "text/html; charset=utf-8",
".json": "application/json",
".xml": "application/xml",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".pdf": "application/pdf",
}
func mimeFromPath(path string) string {
idx := strings.LastIndex(path, ".")
if idx < 0 {
return ""
}
ext := strings.ToLower(path[idx:])
if t, ok := mimeTypes[ext]; ok {
return t
}
return ""
}