Migration This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs. Contact me

internal/modules/blob.go

3a50036d96eb14462e96598fd169d1c79264ac4b · 1.9 KB · 86 lines raw

1 package modules
2
3 import (
4 "bytes"
5 "net/http"
6 "strings"
7 "unicode/utf8"
8
9 "gsg/internal/core"
10 )
11
12 type Blob struct {
13 Path string
14 Size int
15 Binary bool
16 Lines []Line
17 }
18
19 type Line struct {
20 N int
21 Text string
22 }
23
24 func init() { core.Register("blob", blobMod) }
25
26 // blob: file contents at Ctx.Path, split into numbered lines.
27 // Binary detection is git's own heuristic: a NUL in the first 8000 bytes.
28 func blobMod(c *core.Ctx, args ...string) (any, error) {
29 path := c.Path
30 if len(args) > 0 {
31 path = args[0]
32 }
33 if path == "" {
34 return nil, core.Errorf(http.StatusNotFound, "no path")
35 }
36 raw, err := c.Repo.Blob(c.Commit, path)
37 if err != nil {
38 return nil, core.Errorf(http.StatusNotFound, "no such file %q", path)
39 }
40 b := Blob{Path: path, Size: len(raw)}
41
42 head := raw
43 if len(head) > 8000 {
44 head = head[:8000]
45 }
46 if bytes.IndexByte(head, 0) >= 0 || !utf8.Valid(head) {
47 b.Binary = true
48 return b, nil
49 }
50 for i, t := range strings.Split(strings.TrimRight(string(raw), "\n"), "\n") {
51 b.Lines = append(b.Lines, Line{N: i + 1, Text: t})
52 }
53 return b, nil
54 }
55
56 // RawBlob is the unmodified object, for the /raw/ route. Kept separate from
57 // Blob so the line-split view and the byte stream cache independently.
58 type RawBlob struct {
59 Path string
60 Data []byte
61 Binary bool
62 }
63
64 func (r RawBlob) Bytes() []byte { return r.Data }
65 func (r RawBlob) IsBinary() bool { return r.Binary }
66
67 func init() { core.Register("blobraw", blobRawMod) }
68
69 func blobRawMod(c *core.Ctx, args ...string) (any, error) {
70 path := c.Path
71 if len(args) > 0 {
72 path = args[0]
73 }
74 if path == "" {
75 return nil, core.Errorf(http.StatusNotFound, "no path")
76 }
77 raw, err := c.Repo.Blob(c.Commit, path)
78 if err != nil {
79 return nil, core.Errorf(http.StatusNotFound, "no such file %q", path)
80 }
81 head := raw
82 if len(head) > 8000 {
83 head = head[:8000]
84 }
85 return RawBlob{Path: path, Data: raw, Binary: bytes.IndexByte(head, 0) >= 0}, nil
86 }