+24
.air.toml
+24
.air.toml
···
···
1
+
root = "."
2
+
testdata_dir = "testdata"
3
+
tmp_dir = "tmp"
4
+
5
+
[build]
6
+
bin = "./ugitd"
7
+
cmd = "go build ./cmd/ugitd"
8
+
delay = 1000
9
+
exclude_file = ["internal/html/tailwind.go"]
10
+
exclude_regex = ["_test.go"]
11
+
exclude_unchanged = true
12
+
include_ext = ["go"]
13
+
pre_cmd = ["go generate ./..."]
14
+
15
+
[misc]
16
+
clean_on_exit = true
17
+
18
+
[proxy]
19
+
app_port = 8449
20
+
enabled = true
21
+
proxy_port = 8450
22
+
23
+
[screen]
24
+
clear_on_rebuild = true
-5
.helix/languages.toml
-5
.helix/languages.toml
+6
-5
README.md
+6
-5
README.md
···
2
<picture>
3
<img alt="ugit logo" width="250" src="./assets/ugit.svg" />
4
</picture>
5
-
<h3 align="center">ugit</h3>
6
</p>
7
8
Minimal git server
9
10
-
ugit allows cloning via HTTPS/SSH, but can only be pushed to via SSH.
11
12
-
There are no plans to directly support issues or PR workflows, although webhooks are planned and auxillary software may be created to facilitate these things.
13
-
For now, if you wish to collaborate, please send me patches at [ugit@jolheiser.com](mailto:git@jolheiser.com).
14
15
-
Currently all HTML is allowed in markdown, ugit is intended to be run by/for a trusted user.
16
17
## Getting your public SSH keys from another forge
18
···
2
<picture>
3
<img alt="ugit logo" width="250" src="./assets/ugit.svg" />
4
</picture>
5
+
<h3 align="center">ยตgit</h3>
6
</p>
7
8
Minimal git server
9
10
+
ยตgit allows cloning via HTTPS/SSH, but can only be pushed to via SSH.
11
12
+
There are no plans to directly support issues or PR workflows.
13
+
If you wish to collaborate, please send me patches via [github](https://github.com/jolheiser/ugit) or [tangled](https://tangled.org/@jolheiser.com/ugit).
14
+
For issue/bug-tracking, I recommend [git-bug](https://github.com/git-bug/git-bug).
15
16
+
Currently all HTML is allowed in markdown, ยตgit is intended to be run by/for a trusted user.
17
18
## Getting your public SSH keys from another forge
19
+1
-1
assets/ugit.svg
+1
-1
assets/ugit.svg
···
1
<?xml version="1.0" encoding="UTF-8"?>
2
<svg viewBox="0 0 24 24" stroke="#de4c36" fill="#de4c36" stroke-width="1" xmlns="http://www.w3.org/2000/svg">
3
-
<title>ugit icon</title>
4
<rect fill="none" x="1" y="1" rx="1" ry="1" width="22" height="22"></rect>
5
<ellipse cx="6" cy="6" rx="2" ry="2"></ellipse>
6
<ellipse cx="18" cy="6" rx="2" ry="2"></ellipse>
···
1
<?xml version="1.0" encoding="UTF-8"?>
2
<svg viewBox="0 0 24 24" stroke="#de4c36" fill="#de4c36" stroke-width="1" xmlns="http://www.w3.org/2000/svg">
3
+
<title>ยตgit icon</title>
4
<rect fill="none" x="1" y="1" rx="1" ry="1" width="22" height="22"></rect>
5
<ellipse cx="6" cy="6" rx="2" ry="2"></ellipse>
6
<ellipse cx="18" cy="6" rx="2" ry="2"></ellipse>
+29
-12
cmd/ugitd/args.go
+29
-12
cmd/ugitd/args.go
···
3
import (
4
"flag"
5
"fmt"
6
"strings"
7
8
-
"github.com/charmbracelet/log"
9
"github.com/peterbourgon/ff/v3"
10
"github.com/peterbourgon/ff/v3/ffyaml"
11
)
12
13
type cliArgs struct {
14
-
RepoDir string
15
-
SSH sshArgs
16
-
HTTP httpArgs
17
-
Meta metaArgs
18
-
Profile profileArgs
19
-
Log logArgs
20
}
21
22
type sshArgs struct {
23
AuthorizedKeys string
24
CloneURL string
25
Port int
···
27
}
28
29
type httpArgs struct {
30
CloneURL string
31
Port int
32
}
···
48
}
49
50
type logArgs struct {
51
-
Level log.Level
52
JSON bool
53
}
54
···
59
c = cliArgs{
60
RepoDir: ".ugit",
61
SSH: sshArgs{
62
AuthorizedKeys: ".ssh/authorized_keys",
63
CloneURL: "ssh://localhost:8448",
64
Port: 8448,
65
HostKey: ".ssh/ugit_ed25519",
66
},
67
HTTP: httpArgs{
68
CloneURL: "http://localhost:8449",
69
Port: 8449,
70
},
···
73
Description: "Minimal git server",
74
},
75
Log: logArgs{
76
-
Level: log.InfoLevel,
77
},
78
}
79
80
fs.Func("log.level", "Logging level", func(s string) error {
81
-
lvl, err := log.ParseLevel(s)
82
-
if err != nil {
83
-
return err
84
}
85
c.Log.Level = lvl
86
return nil
87
})
88
fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format")
89
fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories")
90
fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys")
91
fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base")
92
fs.IntVar(&c.SSH.Port, "ssh.port", c.SSH.Port, "SSH port")
93
fs.StringVar(&c.SSH.HostKey, "ssh.host-key", c.SSH.HostKey, "SSH host key (created if it doesn't exist)")
94
fs.StringVar(&c.HTTP.CloneURL, "http.clone-url", c.HTTP.CloneURL, "HTTP clone URL base")
95
fs.IntVar(&c.HTTP.Port, "http.port", c.HTTP.Port, "HTTP port")
96
fs.StringVar(&c.Meta.Title, "meta.title", c.Meta.Title, "App title")
···
3
import (
4
"flag"
5
"fmt"
6
+
"log/slog"
7
"strings"
8
9
"github.com/peterbourgon/ff/v3"
10
"github.com/peterbourgon/ff/v3/ffyaml"
11
)
12
13
type cliArgs struct {
14
+
RepoDir string
15
+
SSH sshArgs
16
+
HTTP httpArgs
17
+
Meta metaArgs
18
+
Profile profileArgs
19
+
Log logArgs
20
+
ShowPrivate bool
21
}
22
23
type sshArgs struct {
24
+
Enable bool
25
AuthorizedKeys string
26
CloneURL string
27
Port int
···
29
}
30
31
type httpArgs struct {
32
+
Enable bool
33
CloneURL string
34
Port int
35
}
···
51
}
52
53
type logArgs struct {
54
+
Level slog.Level
55
JSON bool
56
}
57
···
62
c = cliArgs{
63
RepoDir: ".ugit",
64
SSH: sshArgs{
65
+
Enable: true,
66
AuthorizedKeys: ".ssh/authorized_keys",
67
CloneURL: "ssh://localhost:8448",
68
Port: 8448,
69
HostKey: ".ssh/ugit_ed25519",
70
},
71
HTTP: httpArgs{
72
+
Enable: true,
73
CloneURL: "http://localhost:8449",
74
Port: 8449,
75
},
···
78
Description: "Minimal git server",
79
},
80
Log: logArgs{
81
+
Level: slog.LevelError,
82
},
83
}
84
85
fs.Func("log.level", "Logging level", func(s string) error {
86
+
var lvl slog.Level
87
+
switch strings.ToLower(s) {
88
+
case "debug":
89
+
lvl = slog.LevelDebug
90
+
case "info":
91
+
lvl = slog.LevelInfo
92
+
case "warn", "warning":
93
+
lvl = slog.LevelWarn
94
+
case "error":
95
+
lvl = slog.LevelError
96
+
default:
97
+
return fmt.Errorf("unknown log level %q: options are [debug, info, warn, error]", s)
98
}
99
c.Log.Level = lvl
100
return nil
101
})
102
fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format")
103
fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories")
104
+
fs.BoolVar(&c.ShowPrivate, "show-private", c.ShowPrivate, "Show private repos in web interface")
105
+
fs.BoolVar(&c.SSH.Enable, "ssh.enable", c.SSH.Enable, "Enable SSH server")
106
fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys")
107
fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base")
108
fs.IntVar(&c.SSH.Port, "ssh.port", c.SSH.Port, "SSH port")
109
fs.StringVar(&c.SSH.HostKey, "ssh.host-key", c.SSH.HostKey, "SSH host key (created if it doesn't exist)")
110
+
fs.BoolVar(&c.HTTP.Enable, "http.enable", c.HTTP.Enable, "Enable HTTP server")
111
fs.StringVar(&c.HTTP.CloneURL, "http.clone-url", c.HTTP.CloneURL, "HTTP clone URL base")
112
fs.IntVar(&c.HTTP.Port, "http.port", c.HTTP.Port, "HTTP port")
113
fs.StringVar(&c.Meta.Title, "meta.title", c.Meta.Title, "App title")
+46
-31
cmd/ugitd/main.go
+46
-31
cmd/ugitd/main.go
···
4
"errors"
5
"flag"
6
"fmt"
7
"log/slog"
8
"os"
9
"os/signal"
10
"path/filepath"
11
"strconv"
12
"strings"
13
14
-
"github.com/charmbracelet/log"
15
"github.com/go-chi/chi/v5/middleware"
16
"github.com/go-chi/httplog/v2"
17
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
···
39
panic(err)
40
}
41
42
-
log.SetLevel(args.Log.Level)
43
middleware.DefaultLogger = httplog.RequestLogger(httplog.NewLogger("ugit", httplog.Options{
44
JSON: args.Log.JSON,
45
LogLevel: slog.Level(args.Log.Level),
46
-
Concise: args.Log.Level != log.DebugLevel,
47
}))
48
49
-
if args.Log.Level == log.DebugLevel {
50
trace.SetTarget(trace.Packet)
51
} else {
52
middleware.DefaultLogger = http.NoopLogger
···
54
}
55
56
if args.Log.JSON {
57
-
log.SetFormatter(log.JSONFormatter)
58
}
59
60
if err := requiredFS(args.RepoDir); err != nil {
61
panic(err)
62
}
63
64
-
sshSettings := ssh.Settings{
65
-
AuthorizedKeys: args.SSH.AuthorizedKeys,
66
-
CloneURL: args.SSH.CloneURL,
67
-
Port: args.SSH.Port,
68
-
HostKey: args.SSH.HostKey,
69
-
RepoDir: args.RepoDir,
70
-
}
71
-
sshSrv, err := ssh.New(sshSettings)
72
-
if err != nil {
73
-
panic(err)
74
-
}
75
-
go func() {
76
-
log.Debugf("SSH listening on ssh://localhost:%d\n", sshSettings.Port)
77
-
if err := sshSrv.ListenAndServe(); err != nil {
78
panic(err)
79
}
80
-
}()
81
82
httpSettings := http.Settings{
83
Title: args.Meta.Title,
···
89
Username: args.Profile.Username,
90
Email: args.Profile.Email,
91
},
92
}
93
for _, link := range args.Profile.Links {
94
httpSettings.Profile.Links = append(httpSettings.Profile.Links, http.Link{
···
96
URL: link.URL,
97
})
98
}
99
-
httpSrv := http.New(httpSettings)
100
-
go func() {
101
-
log.Debugf("HTTP listening on http://localhost:%d\n", httpSettings.Port)
102
-
if err := httpSrv.ListenAndServe(); err != nil {
103
-
panic(err)
104
-
}
105
-
}()
106
107
ch := make(chan os.Signal, 1)
108
-
signal.Notify(ch, os.Kill, os.Interrupt)
109
<-ch
110
}
111
···
128
}
129
fp = filepath.Join(fp, "pre-receive")
130
131
fi, err := os.Create(fp)
132
if err != nil {
133
return err
134
}
135
-
fi.WriteString("#!/usr/bin/env bash\n")
136
-
fi.WriteString(fmt.Sprintf("%s pre-receive-hook\n", bin))
137
fi.Close()
138
139
return os.Chmod(fp, 0o755)
···
147
148
opts := make([]*packp.Option, 0)
149
if pushCount, err := strconv.Atoi(os.Getenv("GIT_PUSH_OPTION_COUNT")); err == nil {
150
-
for idx := 0; idx < pushCount; idx++ {
151
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
152
kv := strings.SplitN(opt, "=", 2)
153
if len(kv) == 2 {
···
4
"errors"
5
"flag"
6
"fmt"
7
+
"log"
8
"log/slog"
9
"os"
10
"os/signal"
11
"path/filepath"
12
"strconv"
13
"strings"
14
+
"syscall"
15
16
"github.com/go-chi/chi/v5/middleware"
17
"github.com/go-chi/httplog/v2"
18
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
···
40
panic(err)
41
}
42
43
+
slog.SetLogLoggerLevel(args.Log.Level)
44
middleware.DefaultLogger = httplog.RequestLogger(httplog.NewLogger("ugit", httplog.Options{
45
JSON: args.Log.JSON,
46
LogLevel: slog.Level(args.Log.Level),
47
+
Concise: args.Log.Level != slog.LevelDebug,
48
}))
49
50
+
if args.Log.Level == slog.LevelDebug {
51
trace.SetTarget(trace.Packet)
52
} else {
53
middleware.DefaultLogger = http.NoopLogger
···
55
}
56
57
if args.Log.JSON {
58
+
logger := slog.New(slog.NewJSONHandler(os.Stderr, nil))
59
+
slog.SetDefault(logger)
60
}
61
62
if err := requiredFS(args.RepoDir); err != nil {
63
panic(err)
64
}
65
66
+
if args.SSH.Enable {
67
+
sshSettings := ssh.Settings{
68
+
AuthorizedKeys: args.SSH.AuthorizedKeys,
69
+
CloneURL: args.SSH.CloneURL,
70
+
Port: args.SSH.Port,
71
+
HostKey: args.SSH.HostKey,
72
+
RepoDir: args.RepoDir,
73
+
}
74
+
sshSrv, err := ssh.New(sshSettings)
75
+
if err != nil {
76
panic(err)
77
}
78
+
go func() {
79
+
log.Printf("SSH listening on ssh://localhost:%d\n", sshSettings.Port)
80
+
if err := sshSrv.ListenAndServe(); err != nil {
81
+
panic(err)
82
+
}
83
+
}()
84
+
}
85
86
httpSettings := http.Settings{
87
Title: args.Meta.Title,
···
93
Username: args.Profile.Username,
94
Email: args.Profile.Email,
95
},
96
+
ShowPrivate: args.ShowPrivate,
97
}
98
for _, link := range args.Profile.Links {
99
httpSettings.Profile.Links = append(httpSettings.Profile.Links, http.Link{
···
101
URL: link.URL,
102
})
103
}
104
+
if args.HTTP.Enable {
105
+
httpSrv := http.New(httpSettings)
106
+
go func() {
107
+
log.Printf("HTTP listening on http://localhost:%d\n", httpSettings.Port)
108
+
if err := httpSrv.ListenAndServe(); err != nil {
109
+
panic(err)
110
+
}
111
+
}()
112
+
}
113
114
ch := make(chan os.Signal, 1)
115
+
signal.Notify(ch, syscall.SIGTERM, os.Interrupt)
116
<-ch
117
}
118
···
135
}
136
fp = filepath.Join(fp, "pre-receive")
137
138
+
if err := os.MkdirAll(fp+".d", os.ModePerm); err != nil {
139
+
return err
140
+
}
141
+
142
fi, err := os.Create(fp)
143
if err != nil {
144
return err
145
}
146
+
fmt.Fprintln(fi, "#!/usr/bin/env bash")
147
+
fmt.Fprintf(fi, "%s pre-receive-hook\n", bin)
148
+
fmt.Fprintf(fi, `for hook in %s.d/*; do
149
+
test -x "${hook}" && test -f "${hook}" || continue
150
+
"${hook}"
151
+
done`, fp)
152
fi.Close()
153
154
return os.Chmod(fp, 0o755)
···
162
163
opts := make([]*packp.Option, 0)
164
if pushCount, err := strconv.Atoi(os.Getenv("GIT_PUSH_OPTION_COUNT")); err == nil {
165
+
for idx := range pushCount {
166
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
167
kv := strings.SplitN(opt, "=", 2)
168
if len(kv) == 2 {
+3
-9
contrib/layout.kdl
+3
-9
contrib/layout.kdl
···
5
command "nix"
6
args "develop"
7
size "90%"
8
-
start_suspended true
9
}
10
pane split_direction="vertical" {
11
pane {
12
-
name "run"
13
-
command "go"
14
-
args "run" "./cmd/ugitd"
15
-
start_suspended true
16
-
}
17
-
pane {
18
-
name "watch"
19
command "nix"
20
-
args "develop" "--command" "nu" "-c" "watch --glob *.templ ./internal/html/ {|| go generate ./...}"
21
}
22
}
23
}
+7
-62
flake.lock
+7
-62
flake.lock
···
1
{
2
"nodes": {
3
-
"flake-utils": {
4
-
"inputs": {
5
-
"systems": "systems"
6
-
},
7
-
"locked": {
8
-
"lastModified": 1694529238,
9
-
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
10
-
"owner": "numtide",
11
-
"repo": "flake-utils",
12
-
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
13
-
"type": "github"
14
-
},
15
-
"original": {
16
-
"owner": "numtide",
17
-
"repo": "flake-utils",
18
-
"type": "github"
19
-
}
20
-
},
21
-
"gomod2nix": {
22
-
"inputs": {
23
-
"flake-utils": "flake-utils",
24
-
"nixpkgs": [
25
-
"nixpkgs"
26
-
]
27
-
},
28
-
"locked": {
29
-
"lastModified": 1717050755,
30
-
"narHash": "sha256-C9IEHABulv2zEDFA+Bf0E1nmfN4y6MIUe5eM2RCrDC0=",
31
-
"owner": "nix-community",
32
-
"repo": "gomod2nix",
33
-
"rev": "31b6d2e40b36456e792cd6cf50d5a8ddd2fa59a1",
34
-
"type": "github"
35
-
},
36
-
"original": {
37
-
"owner": "nix-community",
38
-
"repo": "gomod2nix",
39
-
"type": "github"
40
-
}
41
-
},
42
"nixpkgs": {
43
"locked": {
44
-
"lastModified": 1719379843,
45
-
"narHash": "sha256-u+D+IOAMMl70+CJ9NKB+RMrASjInuIWMHzjLWQjPZ6c=",
46
"owner": "nixos",
47
"repo": "nixpkgs",
48
-
"rev": "b3f3c1b13fb08f3828442ee86630362e81136bbc",
49
"type": "github"
50
},
51
"original": {
···
57
},
58
"root": {
59
"inputs": {
60
-
"gomod2nix": "gomod2nix",
61
"nixpkgs": "nixpkgs",
62
"tailwind-ctp": "tailwind-ctp",
63
"tailwind-ctp-lsp": "tailwind-ctp-lsp"
64
}
65
},
66
-
"systems": {
67
-
"locked": {
68
-
"lastModified": 1681028828,
69
-
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
70
-
"owner": "nix-systems",
71
-
"repo": "default",
72
-
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
73
-
"type": "github"
74
-
},
75
-
"original": {
76
-
"owner": "nix-systems",
77
-
"repo": "default",
78
-
"type": "github"
79
-
}
80
-
},
81
"tailwind-ctp": {
82
"inputs": {
83
"nixpkgs": [
···
85
]
86
},
87
"locked": {
88
-
"lastModified": 1695841587,
89
-
"narHash": "sha256-fgiZd5AV+hi8Ne0bJ8SyAx5nppseW4aXJQEIDSr0VNA=",
90
"ref": "refs/heads/main",
91
-
"rev": "afca060674b20e0ccecde2d6fe88c887790219a5",
92
-
"revCount": 1,
93
"type": "git",
94
"url": "https://git.jolheiser.com/tailwind-ctp"
95
},
···
1
{
2
"nodes": {
3
"nixpkgs": {
4
"locked": {
5
+
"lastModified": 1755205935,
6
+
"narHash": "sha256-EQ6qHuJWguaoBZyxdqsgJqyEdS77k+2CnlKrfFxlkRY=",
7
"owner": "nixos",
8
"repo": "nixpkgs",
9
+
"rev": "c5e2e42c112de623adfd662b3e51f0805bf9ff83",
10
"type": "github"
11
},
12
"original": {
···
18
},
19
"root": {
20
"inputs": {
21
"nixpkgs": "nixpkgs",
22
"tailwind-ctp": "tailwind-ctp",
23
"tailwind-ctp-lsp": "tailwind-ctp-lsp"
24
}
25
},
26
"tailwind-ctp": {
27
"inputs": {
28
"nixpkgs": [
···
30
]
31
},
32
"locked": {
33
+
"lastModified": 1753803577,
34
+
"narHash": "sha256-sE5IgsHacXmfsWJjVVPvb7Aa6oHElt+nfP6+3Pqa414=",
35
"ref": "refs/heads/main",
36
+
"rev": "4ce9431cbb4e9e5dceadfbc413fbd34e7305fe8e",
37
+
"revCount": 3,
38
"type": "git",
39
"url": "https://git.jolheiser.com/tailwind-ctp"
40
},
+67
-153
flake.nix
+67
-153
flake.nix
···
3
4
inputs = {
5
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
6
-
gomod2nix = {
7
-
url = "github:nix-community/gomod2nix";
8
-
inputs.nixpkgs.follows = "nixpkgs";
9
-
};
10
tailwind-ctp = {
11
url = "git+https://git.jolheiser.com/tailwind-ctp";
12
inputs.nixpkgs.follows = "nixpkgs";
···
17
};
18
};
19
20
-
outputs = {
21
-
self,
22
-
nixpkgs,
23
-
gomod2nix,
24
-
tailwind-ctp,
25
-
tailwind-ctp-lsp,
26
-
} @ inputs: let
27
-
system = "x86_64-linux";
28
-
pkgs = nixpkgs.legacyPackages.${system};
29
-
tailwind-ctp = inputs.tailwind-ctp.packages.${system}.default;
30
-
tailwind-ctp-lsp = inputs.tailwind-ctp-lsp.packages.${system}.default;
31
-
ugit = gomod2nix.legacyPackages.${system}.buildGoApplication rec {
32
-
name = "ugitd";
33
-
src = pkgs.nix-gitignore.gitignoreSource [] (builtins.path {
34
-
inherit name;
35
-
path = ./.;
36
-
});
37
-
pwd = ./.;
38
-
subPackages = ["cmd/ugitd"];
39
-
CGO_ENABLED = 0;
40
-
flags = [
41
-
"-trimpath"
42
-
];
43
-
ldflags = [
44
-
"-s"
45
-
"-w"
46
-
"-extldflags -static"
47
-
];
48
-
meta = with pkgs.lib; {
49
-
description = "Minimal git server";
50
-
homepage = "https://git.jolheiser.com/ugit";
51
-
maintainers = with maintainers; [jolheiser];
52
-
mainProgram = "ugitd";
53
-
};
54
-
};
55
-
in {
56
-
packages.${system}.default = ugit;
57
-
devShells.${system}.default = pkgs.mkShell {
58
-
nativeBuildInputs = with pkgs; [
59
-
go
60
-
gopls
61
-
gomod2nix.legacyPackages.${system}.gomod2nix
62
-
templ
63
-
tailwind-ctp
64
-
tailwind-ctp-lsp
65
-
vscode-langservers-extracted
66
];
67
-
};
68
-
nixosModules.default = {
69
-
pkgs,
70
-
lib,
71
-
config,
72
-
...
73
-
}: let
74
-
cfg = config.services.ugit;
75
-
yamlFormat = pkgs.formats.yaml {};
76
-
configFile = pkgs.writeText "ugit.yaml" (builtins.readFile (yamlFormat.generate "ugit-yaml" cfg.config));
77
-
authorizedKeysFile = pkgs.writeText "ugit_keys" (builtins.concatStringsSep "\n" cfg.authorizedKeys);
78
-
in {
79
-
options = with lib; {
80
-
services.ugit = {
81
-
enable = mkEnableOption "Enable ugit";
82
-
83
-
package = mkOption {
84
-
type = types.package;
85
-
description = "ugit package to use";
86
-
default = ugit;
87
-
};
88
-
89
-
repoDir = mkOption {
90
-
type = types.str;
91
-
description = "where ugit stores repositories";
92
-
default = "/var/lib/ugit/repos";
93
-
};
94
-
95
-
authorizedKeys = mkOption {
96
-
type = types.listOf types.str;
97
-
description = "list of keys to use for authorized_keys";
98
-
default = [];
99
-
};
100
-
101
-
authorizedKeysFile = mkOption {
102
-
type = types.str;
103
-
description = "path to authorized_keys file ugit uses for auth";
104
-
default = "/var/lib/ugit/authorized_keys";
105
-
};
106
-
107
-
hostKeyFile = mkOption {
108
-
type = types.str;
109
-
description = "path to host key file (will be created if it doesn't exist)";
110
-
default = "/var/lib/ugit/ugit_ed25519";
111
-
};
112
-
113
-
config = mkOption {
114
-
type = types.attrs;
115
-
default = {};
116
-
description = "config.yaml contents";
117
};
118
-
119
-
user = mkOption {
120
-
type = types.str;
121
-
default = "ugit";
122
-
description = "User account under which ugit runs";
123
-
};
124
-
125
-
group = mkOption {
126
-
type = types.str;
127
-
default = "ugit";
128
-
description = "Group account under which ugit runs";
129
-
};
130
-
131
-
openFirewall = mkOption {
132
-
type = types.bool;
133
-
default = false;
134
-
};
135
-
};
136
};
137
-
config = lib.mkIf cfg.enable {
138
-
users.users."${cfg.user}" = {
139
-
home = "/var/lib/ugit";
140
-
createHome = true;
141
-
group = "${cfg.group}";
142
-
isSystemUser = true;
143
-
isNormalUser = false;
144
-
description = "user for ugit service";
145
-
};
146
-
users.groups."${cfg.group}" = {};
147
-
networking.firewall = lib.mkIf cfg.openFirewall {
148
-
allowedTCPPorts = [8448 8449];
149
-
};
150
-
151
-
systemd.services.ugit = {
152
-
enable = true;
153
-
script = let
154
-
authorizedKeysPath =
155
-
if (builtins.length cfg.authorizedKeys) > 0
156
-
then authorizedKeysFile
157
-
else cfg.authorizedKeysFile;
158
-
args = ["--config=${configFile}" "--repo-dir=${cfg.repoDir}" "--ssh.authorized-keys=${authorizedKeysPath}" "--ssh.host-key=${cfg.hostKeyFile}"];
159
-
in "${cfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
160
-
wantedBy = ["multi-user.target"];
161
-
after = ["network.target"];
162
-
path = [cfg.package pkgs.git pkgs.bash];
163
-
serviceConfig = {
164
-
User = cfg.user;
165
-
Group = cfg.group;
166
-
Restart = "always";
167
-
RestartSec = "15";
168
-
WorkingDirectory = "/var/lib/ugit";
169
};
170
-
};
171
-
};
172
};
173
-
};
174
}
···
3
4
inputs = {
5
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
6
tailwind-ctp = {
7
url = "git+https://git.jolheiser.com/tailwind-ctp";
8
inputs.nixpkgs.follows = "nixpkgs";
···
13
};
14
};
15
16
+
outputs =
17
+
{
18
+
self,
19
+
nixpkgs,
20
+
tailwind-ctp,
21
+
tailwind-ctp-lsp,
22
+
}:
23
+
let
24
+
systems = [
25
+
"x86_64-linux"
26
+
"i686-linux"
27
+
"x86_64-darwin"
28
+
"aarch64-linux"
29
+
"armv6l-linux"
30
+
"armv7l-linux"
31
];
32
+
forAllSystems = f: nixpkgs.lib.genAttrs systems f;
33
+
tctp = forAllSystems (system: tailwind-ctp.packages.${system}.default);
34
+
tctpl = forAllSystems (system: tailwind-ctp-lsp.packages.${system}.default);
35
+
in
36
+
{
37
+
packages = forAllSystems (system: import ./nix { pkgs = nixpkgs.legacyPackages.${system}; });
38
+
devShells = forAllSystems (
39
+
system:
40
+
let
41
+
pkgs = nixpkgs.legacyPackages.${system};
42
+
in
43
+
{
44
+
default = pkgs.mkShell {
45
+
nativeBuildInputs = with pkgs; [
46
+
go
47
+
gopls
48
+
air
49
+
tctp.${system}
50
+
#tctpl.${system}
51
+
#vscode-langservers-extracted
52
+
];
53
};
54
+
}
55
+
);
56
+
nixosModules.default = import ./nix/module.nix;
57
+
nixosConfigurations.ugitVM = nixpkgs.lib.nixosSystem {
58
+
system = "x86_64-linux";
59
+
modules = [
60
+
./nix/vm.nix
61
+
{
62
+
virtualisation.vmVariant.virtualisation = {
63
+
cores = 2;
64
+
memorySize = 2048;
65
+
graphics = false;
66
+
};
67
+
system.stateVersion = "23.11";
68
+
}
69
+
];
70
};
71
+
apps = forAllSystems (
72
+
system:
73
+
let
74
+
pkgs = import nixpkgs { inherit system; };
75
+
in
76
+
{
77
+
vm = {
78
+
type = "app";
79
+
program = "${pkgs.writeShellScript "vm" ''
80
+
nixos-rebuild build-vm --flake .#ugitVM
81
+
./result/bin/run-nixos-vm
82
+
rm nixos.qcow2
83
+
''}";
84
};
85
+
}
86
+
);
87
};
88
}
+73
-56
go.mod
+73
-56
go.mod
···
1
module go.jolheiser.com/ugit
2
3
-
go 1.21
4
-
5
-
toolchain go1.21.5
6
7
require (
8
-
github.com/a-h/templ v0.2.543
9
-
github.com/alecthomas/chroma/v2 v2.12.0
10
-
github.com/charmbracelet/log v0.3.1
11
-
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560
12
-
github.com/charmbracelet/wish v1.3.0
13
github.com/dustin/go-humanize v1.0.1
14
-
github.com/go-chi/chi/v5 v5.0.11
15
github.com/go-chi/httplog/v2 v2.1.1
16
-
github.com/go-git/go-billy/v5 v5.5.0
17
-
github.com/go-git/go-git/v5 v5.11.0
18
github.com/peterbourgon/ff/v3 v3.4.0
19
-
github.com/yuin/goldmark v1.6.0
20
-
github.com/yuin/goldmark-emoji v1.0.2
21
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
22
-
golang.org/x/net v0.25.0
23
)
24
25
require (
26
-
dario.cat/mergo v1.0.0 // indirect
27
-
github.com/Microsoft/go-winio v0.6.1 // indirect
28
-
github.com/ProtonMail/go-crypto v1.0.0 // indirect
29
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
30
-
github.com/atotto/clipboard v0.1.4 // indirect
31
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
32
-
github.com/catppuccin/go v0.2.0 // indirect
33
-
github.com/charmbracelet/bubbles v0.18.0 // indirect
34
-
github.com/charmbracelet/bubbletea v0.26.4 // indirect
35
-
github.com/charmbracelet/huh v0.5.1 // indirect
36
-
github.com/charmbracelet/keygen v0.5.0 // indirect
37
-
github.com/charmbracelet/lipgloss v0.11.0 // indirect
38
-
github.com/charmbracelet/x/ansi v0.1.2 // indirect
39
-
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 // indirect
40
-
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 // indirect
41
-
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a // indirect
42
-
github.com/charmbracelet/x/input v0.1.2 // indirect
43
-
github.com/charmbracelet/x/term v0.1.1 // indirect
44
-
github.com/charmbracelet/x/windows v0.1.2 // indirect
45
-
github.com/cloudflare/circl v1.3.7 // indirect
46
-
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 // indirect
47
-
github.com/creack/pty v1.1.21 // indirect
48
-
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
49
-
github.com/dlclark/regexp2 v1.10.0 // indirect
50
github.com/emirpasic/gods v1.18.1 // indirect
51
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
52
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
53
-
github.com/go-logfmt/logfmt v0.6.0 // indirect
54
-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
55
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
56
-
github.com/kevinburke/ssh_config v1.2.0 // indirect
57
-
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
58
github.com/mattn/go-isatty v0.0.20 // indirect
59
github.com/mattn/go-localereader v0.0.1 // indirect
60
-
github.com/mattn/go-runewidth v0.0.15 // indirect
61
-
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
62
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
63
github.com/muesli/cancelreader v0.2.2 // indirect
64
-
github.com/muesli/reflow v0.3.0 // indirect
65
-
github.com/muesli/termenv v0.15.2 // indirect
66
-
github.com/pjbgf/sha1cd v0.3.0 // indirect
67
github.com/rivo/uniseg v0.4.7 // indirect
68
-
github.com/sergi/go-diff v1.3.1 // indirect
69
-
github.com/skeema/knownhosts v1.2.1 // indirect
70
-
github.com/u-root/u-root v0.12.0 // indirect
71
github.com/xanzy/ssh-agent v0.3.3 // indirect
72
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
73
-
golang.org/x/crypto v0.23.0 // indirect
74
-
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
75
-
golang.org/x/mod v0.17.0 // indirect
76
-
golang.org/x/sync v0.7.0 // indirect
77
-
golang.org/x/sys v0.21.0 // indirect
78
-
golang.org/x/term v0.20.0 // indirect
79
-
golang.org/x/text v0.16.0 // indirect
80
-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
81
gopkg.in/warnings.v0 v0.1.2 // indirect
82
gopkg.in/yaml.v2 v2.4.0 // indirect
83
)
···
1
module go.jolheiser.com/ugit
2
3
+
go 1.24.0
4
5
require (
6
+
github.com/a-h/templ v0.3.960
7
+
github.com/alecthomas/assert/v2 v2.11.0
8
+
github.com/alecthomas/chroma/v2 v2.20.0
9
+
github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309
10
+
github.com/charmbracelet/wish v1.4.7
11
github.com/dustin/go-humanize v1.0.1
12
+
github.com/go-chi/chi/v5 v5.2.3
13
github.com/go-chi/httplog/v2 v2.1.1
14
+
github.com/go-git/go-billy/v5 v5.6.2
15
+
github.com/go-git/go-git/v5 v5.16.3
16
github.com/peterbourgon/ff/v3 v3.4.0
17
+
github.com/yuin/goldmark v1.7.13
18
+
github.com/yuin/goldmark-emoji v1.0.6
19
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
20
+
golang.org/x/net v0.46.0
21
)
22
23
require (
24
+
dario.cat/mergo v1.0.2 // indirect
25
+
github.com/Microsoft/go-winio v0.6.2 // indirect
26
+
github.com/ProtonMail/go-crypto v1.3.0 // indirect
27
+
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect
28
+
github.com/alecthomas/repr v0.5.1 // indirect
29
+
github.com/andybalholm/brotli v1.1.0 // indirect
30
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
31
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
32
+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
33
+
github.com/charmbracelet/bubbletea v1.3.10 // indirect
34
+
github.com/charmbracelet/colorprofile v0.3.2 // indirect
35
+
github.com/charmbracelet/keygen v0.5.4 // indirect
36
+
github.com/charmbracelet/lipgloss v1.1.0 // indirect
37
+
github.com/charmbracelet/log v0.4.2 // indirect
38
+
github.com/charmbracelet/x/ansi v0.10.2 // indirect
39
+
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
40
+
github.com/charmbracelet/x/conpty v0.1.1 // indirect
41
+
github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df // indirect
42
+
github.com/charmbracelet/x/term v0.2.1 // indirect
43
+
github.com/charmbracelet/x/termios v0.1.1 // indirect
44
+
github.com/cli/browser v1.3.0 // indirect
45
+
github.com/clipperhouse/stringish v0.1.1 // indirect
46
+
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
47
+
github.com/cloudflare/circl v1.6.1 // indirect
48
+
github.com/creack/pty v1.1.24 // indirect
49
+
github.com/cyphar/filepath-securejoin v0.5.0 // indirect
50
+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
51
+
github.com/dlclark/regexp2 v1.11.5 // indirect
52
github.com/emirpasic/gods v1.18.1 // indirect
53
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
54
+
github.com/fatih/color v1.16.0 // indirect
55
+
github.com/fsnotify/fsnotify v1.7.0 // indirect
56
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
57
+
github.com/go-logfmt/logfmt v0.6.1 // indirect
58
+
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
59
+
github.com/hexops/gotextdiff v1.0.3 // indirect
60
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
61
+
github.com/kevinburke/ssh_config v1.4.0 // indirect
62
+
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
63
+
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
64
+
github.com/mattn/go-colorable v0.1.13 // indirect
65
github.com/mattn/go-isatty v0.0.20 // indirect
66
github.com/mattn/go-localereader v0.0.1 // indirect
67
+
github.com/mattn/go-runewidth v0.0.19 // indirect
68
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
69
github.com/muesli/cancelreader v0.2.2 // indirect
70
+
github.com/muesli/termenv v0.16.0 // indirect
71
+
github.com/natefinch/atomic v1.0.1 // indirect
72
+
github.com/pjbgf/sha1cd v0.5.0 // indirect
73
+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
74
github.com/rivo/uniseg v0.4.7 // indirect
75
+
github.com/sergi/go-diff v1.4.0 // indirect
76
+
github.com/skeema/knownhosts v1.3.2 // indirect
77
github.com/xanzy/ssh-agent v0.3.3 // indirect
78
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
79
+
golang.org/x/crypto v0.43.0 // indirect
80
+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
81
+
golang.org/x/mod v0.29.0 // indirect
82
+
golang.org/x/sync v0.17.0 // indirect
83
+
golang.org/x/sys v0.37.0 // indirect
84
+
golang.org/x/text v0.30.0 // indirect
85
+
golang.org/x/tools v0.38.0 // indirect
86
gopkg.in/warnings.v0 v0.1.2 // indirect
87
gopkg.in/yaml.v2 v2.4.0 // indirect
88
)
89
+
90
+
tool (
91
+
github.com/a-h/templ/cmd/templ
92
+
go.jolheiser.com/ugit/assets
93
+
go.jolheiser.com/ugit/cmd/ugitd
94
+
go.jolheiser.com/ugit/internal/git
95
+
go.jolheiser.com/ugit/internal/html
96
+
go.jolheiser.com/ugit/internal/html/markup
97
+
go.jolheiser.com/ugit/internal/http
98
+
go.jolheiser.com/ugit/internal/http/httperr
99
+
go.jolheiser.com/ugit/internal/ssh
100
+
)
+1
-1
go.mod.sri
+1
-1
go.mod.sri
+134
-193
go.sum
+134
-193
go.sum
···
1
-
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
2
-
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
4
-
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
5
-
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
6
-
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
7
-
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
8
-
github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk=
9
-
github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA=
10
-
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
11
-
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
12
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
13
-
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
14
-
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
15
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
16
-
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
17
-
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
18
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
19
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
20
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
21
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
22
-
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
23
-
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
24
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
25
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
26
-
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
27
-
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
28
-
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
29
-
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
30
-
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
31
-
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
32
-
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
33
-
github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40=
34
-
github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0=
35
-
github.com/charmbracelet/huh v0.5.1 h1:t5j6g9sMjAE2a9AQuc4lNL7pf/0X4WdHiiMGkL8v/aM=
36
-
github.com/charmbracelet/huh v0.5.1/go.mod h1:gs7b2brpzXkY0PBWUqJrlzvOowTCL0vNAR6OTItc+kA=
37
-
github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc=
38
-
github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8=
39
-
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
40
-
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
41
-
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
42
-
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
43
-
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
44
-
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
45
-
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560 h1:kUYiDRF04AsyJvWi4HrklXXSU7+S7qjExusfDnYbVGg=
46
-
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560/go.mod h1:IHy7o73i1MrQ5lmyJjjJ0g7y4+V+g69cm+Y7JCiZWPo=
47
-
github.com/charmbracelet/wish v1.3.0 h1:SYV5TIlzDb6WaxjkkYXxv2WZsTu/QZGwfGVc0UB5M48=
48
-
github.com/charmbracelet/wish v1.3.0/go.mod h1:1U/bI7zX+IE26ThD5gxtLgeRzctVhSrTpjucPqw4Pos=
49
-
github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY=
50
-
github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
51
-
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 h1:u0XFhTN81zvoGwyQWOYjjkrimEQj5L2DPECCX5cBsRw=
52
-
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
53
-
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 h1:VZIQzjwFE0EamzG2v8HfemeisB8X02Tl0BZBnJ0PeU8=
54
-
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
55
-
github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60 h1:IV19YKUZVf6ATrhiPSCirZ4Bs7EsenYwOWcUHngV+q0=
56
-
github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:kOOxxyxgAFQVcR5yQJWTuLjzt5dR2pcgwy3WaLEudjE=
57
-
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE=
58
-
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU=
59
-
github.com/charmbracelet/x/input v0.1.2 h1:QJAZr33eOhDowkkEQ24rsJy4Llxlm+fRDf/cQrmqJa0=
60
-
github.com/charmbracelet/x/input v0.1.2/go.mod h1:LGBim0maUY4Pitjn/4fHnuXb4KirU3DODsyuHuXdOyA=
61
-
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
62
-
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
63
-
github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
64
-
github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
65
-
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
66
-
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
67
-
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
68
-
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 h1:Ig+OPkE3XQrrl+SKsOqAjlkrBN/zrr+Qpw7rCuDjRCE=
69
-
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
70
-
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
71
-
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
72
-
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
73
-
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
74
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
75
-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
76
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
77
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
78
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
79
-
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
80
-
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
81
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
82
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
83
-
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
84
-
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
85
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
86
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
87
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
88
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
89
-
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
90
-
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
91
-
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
92
-
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
93
github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk=
94
github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE=
95
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
96
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
97
-
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
98
-
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
99
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
100
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
101
-
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
102
-
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
103
-
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
104
-
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
105
-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
106
-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
107
-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
108
-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
109
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
110
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
111
-
github.com/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f h1:ov45/OzrJG8EKbGjn7jJZQJTN7Z1t73sFYNIRd64YlI=
112
-
github.com/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f/go.mod h1:JoDrYMZpDPYo6uH9/f6Peqms3zNNWT2XiGgioMOIGuI=
113
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
114
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
115
-
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
116
-
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
117
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
118
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
119
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
···
121
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
122
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
123
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
124
-
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
125
-
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
126
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
127
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
128
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
129
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
130
-
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
131
-
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
132
-
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
133
-
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
134
-
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
135
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
136
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
137
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
138
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
139
-
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
140
-
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
141
-
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
142
-
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
143
-
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
144
-
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
145
github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc=
146
github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
147
-
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
148
-
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
149
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
150
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
151
-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
152
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
153
-
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
154
-
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
155
-
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
156
-
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
157
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
158
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
159
-
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
160
-
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
161
-
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
162
-
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
163
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
164
-
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
165
-
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
166
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
167
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
168
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
169
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
170
-
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
171
-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
172
-
github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa h1:unMPGGK/CRzfg923allsikmvk2l7beBeFPUNC4RVX/8=
173
-
github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa/go.mod h1:Zj4Tt22fJVn/nz/y6Ergm1SahR9dio1Zm/D2/S0TmXM=
174
-
github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs=
175
-
github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI=
176
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
177
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
178
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
179
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
180
-
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
181
-
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
182
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
183
-
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
184
-
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
185
-
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
186
-
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
187
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
188
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
189
-
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
190
-
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
191
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
192
-
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
193
-
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
194
-
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
195
-
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
196
-
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
197
-
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
198
-
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
199
-
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
200
-
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
201
-
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
202
-
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
203
-
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
204
-
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
205
-
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
206
-
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
207
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
208
-
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
209
-
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
210
-
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
211
-
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
212
-
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
213
-
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
214
-
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
215
-
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
216
-
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
217
-
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
218
-
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
219
-
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
220
-
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
221
-
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
222
-
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
223
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
224
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
225
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
226
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
227
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
228
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
229
-
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
230
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
231
-
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
232
-
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
233
-
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
234
-
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
235
-
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
236
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
237
-
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
238
-
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
239
-
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
240
-
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
241
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
242
-
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
243
-
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
244
-
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
245
-
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
246
-
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
247
-
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
248
-
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
249
-
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
250
-
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
251
-
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
252
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
253
-
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
254
-
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
255
-
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
256
-
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
257
-
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
258
-
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
259
-
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
260
-
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
261
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
262
-
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
263
-
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
264
-
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
265
-
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
266
-
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
267
-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
268
-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
269
-
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
270
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
271
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
272
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
···
1
+
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
2
+
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
3
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
4
+
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
5
+
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
6
+
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
7
+
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
8
+
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
9
+
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
10
+
github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM=
11
+
github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
12
+
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
13
+
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
14
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
15
+
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
16
+
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
17
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
18
+
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
19
+
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
20
+
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
21
+
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
22
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
23
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
24
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
25
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
26
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
27
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
28
+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
29
+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
30
+
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
31
+
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
32
+
github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI=
33
+
github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI=
34
+
github.com/charmbracelet/keygen v0.5.4 h1:XQYgf6UEaTGgQSSmiPpIQ78WfseNQp4Pz8N/c1OsrdA=
35
+
github.com/charmbracelet/keygen v0.5.4/go.mod h1:t4oBRr41bvK7FaJsAaAQhhkUuHslzFXVjOBwA55CZNM=
36
+
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
37
+
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
38
+
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
39
+
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
40
+
github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 h1:dCVbCRRtg9+tsfiTXTp0WupDlHruAXyp+YoxGVofHHc=
41
+
github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309/go.mod h1:R9cISUs5kAH4Cq/rguNbSwcR+slE5Dfm8FEs//uoIGE=
42
+
github.com/charmbracelet/wish v1.4.7 h1:O+jdLac3s6GaqkOHHSwezejNK04vl6VjO1A+hl8J8Yc=
43
+
github.com/charmbracelet/wish v1.4.7/go.mod h1:OBZ8vC62JC5cvbxJLh+bIWtG7Ctmct+ewziuUWK+G14=
44
+
github.com/charmbracelet/x/ansi v0.10.2 h1:ith2ArZS0CJG30cIUfID1LXN7ZFXRCww6RUvAPA+Pzw=
45
+
github.com/charmbracelet/x/ansi v0.10.2/go.mod h1:HbLdJjQH4UH4AqA2HpRWuWNluRE6zxJH/yteYEYCFa8=
46
+
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
47
+
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
48
+
github.com/charmbracelet/x/conpty v0.1.1 h1:s1bUxjoi7EpqiXysVtC+a8RrvPPNcNvAjfi4jxsAuEs=
49
+
github.com/charmbracelet/x/conpty v0.1.1/go.mod h1:OmtR77VODEFbiTzGE9G1XiRJAga6011PIm4u5fTNZpk=
50
+
github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df h1:6zTS1yAzaSDINNXDQRtayOHL4Zde4LVmnbjRPdxV84g=
51
+
github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df/go.mod h1:O2BTD/aMVQDmrvqroIO3fB6zXUuU07ZpVt21QTmZjRg=
52
+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
53
+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
54
+
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
55
+
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
56
+
github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=
57
+
github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=
58
+
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
59
+
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
60
+
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
61
+
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
62
+
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
63
+
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
64
+
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
65
+
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
66
+
github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw=
67
+
github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
68
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
69
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
70
+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
71
+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
72
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
73
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
74
+
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
75
+
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
76
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
77
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
78
+
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
79
+
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
80
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
81
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
82
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
83
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
84
+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
85
+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
86
+
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
87
+
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
88
+
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
89
+
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
90
+
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
91
+
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
92
github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk=
93
github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE=
94
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
95
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
96
+
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
97
+
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
98
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
99
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
100
+
github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8=
101
+
github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
102
+
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
103
+
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
104
+
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
105
+
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
106
+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
107
+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
108
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
109
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
110
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
111
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
112
+
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
113
+
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
114
+
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
115
+
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
116
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
117
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
118
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
···
120
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
121
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
122
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
123
+
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
124
+
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
125
+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
126
+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
127
+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
128
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
129
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
130
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
131
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
132
+
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
133
+
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
134
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
135
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
136
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
137
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
138
+
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
139
+
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
140
+
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
141
+
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
142
+
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
143
+
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
144
github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc=
145
github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
146
+
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
147
+
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
148
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
149
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
150
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
151
+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
152
+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
153
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
154
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
155
+
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
156
+
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
157
+
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
158
+
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
159
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
160
+
github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
161
+
github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
162
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
163
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
164
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
165
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
166
+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
167
+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
168
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
169
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
170
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
171
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
172
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
173
+
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
174
+
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
175
+
github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9HTHs=
176
+
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
177
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
178
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
179
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
180
+
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
181
+
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
182
+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
183
+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
184
+
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
185
+
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
186
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
187
+
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
188
+
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
189
+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
190
+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
191
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
192
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
193
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
194
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
195
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
196
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
197
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
198
+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
199
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
200
+
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
201
+
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
202
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
203
+
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
204
+
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
205
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
206
+
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
207
+
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
208
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
209
+
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
210
+
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
211
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
212
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
213
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-180
gomod2nix.toml
-180
gomod2nix.toml
···
1
-
schema = 3
2
-
3
-
[mod]
4
-
[mod."dario.cat/mergo"]
5
-
version = "v1.0.0"
6
-
hash = "sha256-jlpc8dDj+DmiOU4gEawBu8poJJj9My0s9Mvuk9oS8ww="
7
-
[mod."github.com/Microsoft/go-winio"]
8
-
version = "v0.6.1"
9
-
hash = "sha256-BL0BVaHtmPKQts/711W59AbHXjGKqFS4ZTal0RYnR9I="
10
-
[mod."github.com/ProtonMail/go-crypto"]
11
-
version = "v1.0.0"
12
-
hash = "sha256-Gflazvyv+457FpUTtPafJ+SdolYSalpsU0tragTxNi8="
13
-
[mod."github.com/a-h/templ"]
14
-
version = "v0.2.543"
15
-
hash = "sha256-1BvIj9UPZJp8SOXMPIGdHyZLIvjORHg2UY3pRZJM01s="
16
-
[mod."github.com/alecthomas/chroma/v2"]
17
-
version = "v2.12.0"
18
-
hash = "sha256-w3gKGPwsoayknuU4ifPaF0JOMNqnKjIEutbIkR9c2Ag="
19
-
[mod."github.com/anmitsu/go-shlex"]
20
-
version = "v0.0.0-20200514113438-38f4b401e2be"
21
-
hash = "sha256-L3Ak4X2z7WXq7vMKuiHCOJ29nlpajUQ08Sfb9T0yP54="
22
-
[mod."github.com/aymanbagabas/go-osc52/v2"]
23
-
version = "v2.0.1"
24
-
hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg="
25
-
[mod."github.com/charmbracelet/bubbletea"]
26
-
version = "v0.25.0"
27
-
hash = "sha256-A0WjFRFAUhwO3m7uvCOeefPPIM8ReU+xTtIRxG0aH+Y="
28
-
[mod."github.com/charmbracelet/keygen"]
29
-
version = "v0.5.0"
30
-
hash = "sha256-JFD2SdFL7tq3oVhnBEgiBTrJvjqdUtIuodAJuSFcJoA="
31
-
[mod."github.com/charmbracelet/lipgloss"]
32
-
version = "v0.9.1"
33
-
hash = "sha256-AHbabOymgDRIXsMBgJHS25/GgBWT54oGbd15EBWKeZc="
34
-
[mod."github.com/charmbracelet/log"]
35
-
version = "v0.3.1"
36
-
hash = "sha256-Er60POPID2eNrRZnBHxoI4yHn0mIKnXYftGKSslbXx0="
37
-
[mod."github.com/charmbracelet/ssh"]
38
-
version = "v0.0.0-20240201134204-3f297de25560"
39
-
hash = "sha256-r4h4bym47rs3C2us+sCgVfwAl4TCbm3bDCTsXKYREz8="
40
-
[mod."github.com/charmbracelet/wish"]
41
-
version = "v1.3.0"
42
-
hash = "sha256-3Uq1PDu5DMoWgJykFx/roGk20x8jdb7o5JFPpmEtX/c="
43
-
[mod."github.com/charmbracelet/x/errors"]
44
-
version = "v0.0.0-20240130180102-bafe6fbaee60"
45
-
hash = "sha256-GO8hf0lhVtl00C+xoTzvBtPU2cO0PymSLc2szBRUNtE="
46
-
[mod."github.com/charmbracelet/x/exp/term"]
47
-
version = "v0.0.0-20240130180102-bafe6fbaee60"
48
-
hash = "sha256-hEj/Gj1U1ahk5EFVZVAL52yrdBNO47yXykpiehJICbc="
49
-
[mod."github.com/cloudflare/circl"]
50
-
version = "v1.3.7"
51
-
hash = "sha256-AkOpcZ+evLxLJStvvr01+TLeWDqcLxY3e/AhGggzh40="
52
-
[mod."github.com/containerd/console"]
53
-
version = "v1.0.4-0.20230706203907-8f6c4e4faef5"
54
-
hash = "sha256-mxRERsgS6TmI5I0UYblhzl2FZlbtkJhUkfF1x6mZINw="
55
-
[mod."github.com/creack/pty"]
56
-
version = "v1.1.21"
57
-
hash = "sha256-pjGw6wQlrVhN65XaIxZueNJqnXThGu00u24rKOLzxS0="
58
-
[mod."github.com/cyphar/filepath-securejoin"]
59
-
version = "v0.2.4"
60
-
hash = "sha256-heCD0xMxlwnHCHcRBgTjVexHOLyWI2zRW3E8NFKoLzk="
61
-
[mod."github.com/dlclark/regexp2"]
62
-
version = "v1.10.0"
63
-
hash = "sha256-Jxzj/O/Q9tIWBOOgCkCibhrgJBzzfVIxYDsabt7O8ow="
64
-
[mod."github.com/dustin/go-humanize"]
65
-
version = "v1.0.1"
66
-
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
67
-
[mod."github.com/emirpasic/gods"]
68
-
version = "v1.18.1"
69
-
hash = "sha256-hGDKddjLj+5dn2woHtXKUdd49/3xdsqnhx7VEdCu1m4="
70
-
[mod."github.com/go-chi/chi/v5"]
71
-
version = "v5.0.11"
72
-
hash = "sha256-95LKg/OVzhik2HUz6cirHH3eAT4qbHSg52bSvkc+XOY="
73
-
[mod."github.com/go-git/gcfg"]
74
-
version = "v1.5.1-0.20230307220236-3a3c6141e376"
75
-
hash = "sha256-f4k0gSYuo0/q3WOoTxl2eFaj7WZpdz29ih6CKc8Ude8="
76
-
[mod."github.com/go-git/go-billy/v5"]
77
-
version = "v5.5.0"
78
-
hash = "sha256-4XUoD2bOCMCdu83egb/y8kY/Fm0s1rWgPMtiahh38OQ="
79
-
[mod."github.com/go-git/go-git/v5"]
80
-
version = "v5.11.0"
81
-
hash = "sha256-2yUM/FlV+nYxacVynJCnDZeMub4Iu8JL2WBHmlnwOkE="
82
-
[mod."github.com/go-logfmt/logfmt"]
83
-
version = "v0.6.0"
84
-
hash = "sha256-RtIG2qARd5sT10WQ7F3LR8YJhS8exs+KiuUiVf75bWg="
85
-
[mod."github.com/golang/groupcache"]
86
-
version = "v0.0.0-20210331224755-41bb18bfe9da"
87
-
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0="
88
-
[mod."github.com/jbenet/go-context"]
89
-
version = "v0.0.0-20150711004518-d14ea06fba99"
90
-
hash = "sha256-VANNCWNNpARH/ILQV9sCQsBWgyL2iFT+4AHZREpxIWE="
91
-
[mod."github.com/kevinburke/ssh_config"]
92
-
version = "v1.2.0"
93
-
hash = "sha256-Ta7ZOmyX8gG5tzWbY2oES70EJPfI90U7CIJS9EAce0s="
94
-
[mod."github.com/lucasb-eyer/go-colorful"]
95
-
version = "v1.2.0"
96
-
hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE="
97
-
[mod."github.com/mattn/go-isatty"]
98
-
version = "v0.0.20"
99
-
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
100
-
[mod."github.com/mattn/go-localereader"]
101
-
version = "v0.0.1"
102
-
hash = "sha256-JlWckeGaWG+bXK8l8WEdZqmSiTwCA8b1qbmBKa/Fj3E="
103
-
[mod."github.com/mattn/go-runewidth"]
104
-
version = "v0.0.15"
105
-
hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0="
106
-
[mod."github.com/muesli/ansi"]
107
-
version = "v0.0.0-20230316100256-276c6243b2f6"
108
-
hash = "sha256-qRKn0Bh2yvP0QxeEMeZe11Vz0BPFIkVcleKsPeybKMs="
109
-
[mod."github.com/muesli/cancelreader"]
110
-
version = "v0.2.2"
111
-
hash = "sha256-uEPpzwRJBJsQWBw6M71FDfgJuR7n55d/7IV8MO+rpwQ="
112
-
[mod."github.com/muesli/reflow"]
113
-
version = "v0.3.0"
114
-
hash = "sha256-Pou2ybE9SFSZG6YfZLVV1Eyfm+X4FuVpDPLxhpn47Cc="
115
-
[mod."github.com/muesli/termenv"]
116
-
version = "v0.15.2"
117
-
hash = "sha256-Eum/SpyytcNIchANPkG4bYGBgcezLgej7j/+6IhqoMU="
118
-
[mod."github.com/peterbourgon/ff/v3"]
119
-
version = "v3.4.0"
120
-
hash = "sha256-rmRl4GSmc2atnMbw6hTs6jwxW5lO4ivYuF2VN3jacZM="
121
-
[mod."github.com/pjbgf/sha1cd"]
122
-
version = "v0.3.0"
123
-
hash = "sha256-kX9BdLh2dxtGNaDvc24NORO+C0AZ7JzbrXrtecCdB7w="
124
-
[mod."github.com/rivo/uniseg"]
125
-
version = "v0.4.6"
126
-
hash = "sha256-zGfzO8FWj03POzo47SzrK1B4yLMKJ7iic6ium76ZLzI="
127
-
[mod."github.com/sergi/go-diff"]
128
-
version = "v1.3.1"
129
-
hash = "sha256-XLA/BLIPuUU76yikXqIeRSXr7T7A3Uz6I27+mDxGj7w="
130
-
[mod."github.com/skeema/knownhosts"]
131
-
version = "v1.2.1"
132
-
hash = "sha256-u0jB6ahTdGa+SvcIvPNRLnbSHvgmW9X/ThRq0nWQrJs="
133
-
[mod."github.com/u-root/u-root"]
134
-
version = "v0.12.0"
135
-
hash = "sha256-B9Qoq1S0l0W6twET54uxiWjh2ulxN/zMLAeWJX4cXW0="
136
-
[mod."github.com/xanzy/ssh-agent"]
137
-
version = "v0.3.3"
138
-
hash = "sha256-l3pGB6IdzcPA/HLk93sSN6NM2pKPy+bVOoacR5RC2+c="
139
-
[mod."github.com/yuin/goldmark"]
140
-
version = "v1.6.0"
141
-
hash = "sha256-0PeGjGxxM7lUSx2dn8yPUBpilPQzEN9nkgf3s+5zGTY="
142
-
[mod."github.com/yuin/goldmark-emoji"]
143
-
version = "v1.0.2"
144
-
hash = "sha256-RvzhNXlF98fu9SD/Rve9JMtR4bcRh7rN56Twhh/kmt4="
145
-
[mod."github.com/yuin/goldmark-highlighting/v2"]
146
-
version = "v2.0.0-20230729083705-37449abec8cc"
147
-
hash = "sha256-HpiwU7jIeDUAg2zOpTIiviQir8dpRPuXYh2nqFFccpg="
148
-
[mod."golang.org/x/crypto"]
149
-
version = "v0.18.0"
150
-
hash = "sha256-BuMVUxOIyfLo8MOhqYt+uQ8NDN6P2KdblKyfPxINzQ4="
151
-
[mod."golang.org/x/exp"]
152
-
version = "v0.0.0-20240119083558-1b970713d09a"
153
-
hash = "sha256-JQ3JLywTjgboNhs12blhOkS3ty7m8sUa/zaWv1k/X28="
154
-
[mod."golang.org/x/mod"]
155
-
version = "v0.14.0"
156
-
hash = "sha256-sx3hWp5l99DBfIrn821ohfoBwvaITSHMWbzPvX0btLM="
157
-
[mod."golang.org/x/net"]
158
-
version = "v0.20.0"
159
-
hash = "sha256-PCttIsWSBQd6fDXL49jepszUAMLnAGAKR//5EDO3XDk="
160
-
[mod."golang.org/x/sync"]
161
-
version = "v0.6.0"
162
-
hash = "sha256-LLims/wjDZtIqlYCVHREewcUOX4hwRwplEuZKPOJ/HI="
163
-
[mod."golang.org/x/sys"]
164
-
version = "v0.16.0"
165
-
hash = "sha256-ZkGclbp2S7NQYhbuGji6XokCn2Qi1BJy8dwyAOTV8sY="
166
-
[mod."golang.org/x/term"]
167
-
version = "v0.16.0"
168
-
hash = "sha256-9qlHcsCI1sa7ZI4Q+fJbOp3mG5Y+uV16e+pGmG+MQe0="
169
-
[mod."golang.org/x/text"]
170
-
version = "v0.14.0"
171
-
hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg="
172
-
[mod."golang.org/x/tools"]
173
-
version = "v0.17.0"
174
-
hash = "sha256-CxuHfKKtUkn3VjA7D9WQjzvV1EUbyI/xMNhb5CxO6IQ="
175
-
[mod."gopkg.in/warnings.v0"]
176
-
version = "v0.1.2"
177
-
hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8="
178
-
[mod."gopkg.in/yaml.v2"]
179
-
version = "v2.4.0"
180
-
hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0="
···
+20
-2
internal/git/git.go
+20
-2
internal/git/git.go
···
98
}
99
}
100
101
-
fis := make([]FileInfo, 0)
102
for _, entry := range t.Entries {
103
fm, err := entry.Mode.ToOSFileMode()
104
if err != nil {
···
118
sort.Slice(fis, func(i, j int) bool {
119
fi1 := fis[i]
120
fi2 := fis[j]
121
-
return (fi1.IsDir && !fi2.IsDir) || fi1.Name() < fi2.Name()
122
})
123
124
return fis, nil
125
}
126
127
// FileContent returns the content of a file in the git tree at a given ref/rev
···
98
}
99
}
100
101
+
fis := make([]FileInfo, 0, len(t.Entries))
102
for _, entry := range t.Entries {
103
fm, err := entry.Mode.ToOSFileMode()
104
if err != nil {
···
118
sort.Slice(fis, func(i, j int) bool {
119
fi1 := fis[i]
120
fi2 := fis[j]
121
+
if fi1.IsDir != fi2.IsDir {
122
+
return fi1.IsDir
123
+
}
124
+
return fi1.Name() < fi2.Name()
125
})
126
127
return fis, nil
128
+
}
129
+
130
+
// GetCommitFromRef returns the commit object for a given ref
131
+
func (r Repo) GetCommitFromRef(ref string) (*object.Commit, error) {
132
+
g, err := r.Git()
133
+
if err != nil {
134
+
return nil, err
135
+
}
136
+
137
+
hash, err := g.ResolveRevision(plumbing.Revision(ref))
138
+
if err != nil {
139
+
return nil, err
140
+
}
141
+
142
+
return g.CommitObject(*hash)
143
}
144
145
// FileContent returns the content of a file in the git tree at a given ref/rev
+276
internal/git/git_test.go
+276
internal/git/git_test.go
···
···
1
+
package git_test
2
+
3
+
import (
4
+
"path/filepath"
5
+
"testing"
6
+
"time"
7
+
8
+
"github.com/alecthomas/assert/v2"
9
+
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
10
+
"go.jolheiser.com/ugit/internal/git"
11
+
)
12
+
13
+
func TestEnsureRepo(t *testing.T) {
14
+
tmp := t.TempDir()
15
+
16
+
ok, err := git.PathExists(filepath.Join(tmp, "test"))
17
+
assert.False(t, ok, "repo should not exist yet")
18
+
assert.NoError(t, err, "PathExists should not error when repo doesn't exist")
19
+
20
+
err = git.EnsureRepo(tmp, "test")
21
+
assert.NoError(t, err, "repo should be created")
22
+
23
+
ok, err = git.PathExists(filepath.Join(tmp, "test"))
24
+
assert.True(t, ok, "repo should exist")
25
+
assert.NoError(t, err, "EnsureRepo should not error when path exists")
26
+
27
+
err = git.EnsureRepo(tmp, "test")
28
+
assert.NoError(t, err, "repo should already exist")
29
+
}
30
+
31
+
func TestRepo(t *testing.T) {
32
+
tmp := t.TempDir()
33
+
err := git.EnsureRepo(tmp, "test.git")
34
+
assert.NoError(t, err, "should create repo")
35
+
36
+
repo, err := git.NewRepo(tmp, "test")
37
+
assert.NoError(t, err, "should init new repo")
38
+
assert.True(t, repo.Meta.Private, "repo should default to private")
39
+
40
+
repo.Meta.Private = false
41
+
err = repo.SaveMeta()
42
+
assert.NoError(t, err, "should save repo meta")
43
+
44
+
repo, err = git.NewRepo(tmp, "test")
45
+
assert.NoError(t, err, "should not error when getting existing repo")
46
+
assert.False(t, repo.Meta.Private, "repo should be public after saving meta")
47
+
}
48
+
49
+
func TestPathExists(t *testing.T) {
50
+
tmp := t.TempDir()
51
+
exists, err := git.PathExists(tmp)
52
+
assert.NoError(t, err)
53
+
assert.True(t, exists)
54
+
55
+
doesNotExist := filepath.Join(tmp, "does-not-exist")
56
+
exists, err = git.PathExists(doesNotExist)
57
+
assert.NoError(t, err)
58
+
assert.False(t, exists)
59
+
}
60
+
61
+
func TestRepoMetaUpdate(t *testing.T) {
62
+
original := git.RepoMeta{
63
+
Description: "Original description",
64
+
Private: true,
65
+
Tags: git.TagSet{"tag1": struct{}{}, "tag2": struct{}{}},
66
+
}
67
+
68
+
update := git.RepoMeta{
69
+
Description: "Updated description",
70
+
Private: false,
71
+
Tags: git.TagSet{"tag3": struct{}{}},
72
+
}
73
+
74
+
err := original.Update(update)
75
+
assert.NoError(t, err)
76
+
77
+
assert.Equal(t, "Updated description", original.Description)
78
+
assert.False(t, original.Private)
79
+
assert.Equal(t, []string{"tag1", "tag2", "tag3"}, original.Tags.Slice())
80
+
}
81
+
82
+
func TestFileInfoName(t *testing.T) {
83
+
testCases := []struct {
84
+
path string
85
+
expected string
86
+
}{
87
+
{path: "file.txt", expected: "file.txt"},
88
+
{path: "dir/file.txt", expected: "file.txt"},
89
+
{path: "nested/path/to/file.go", expected: "file.go"},
90
+
{path: "README.md", expected: "README.md"},
91
+
}
92
+
93
+
for _, tc := range testCases {
94
+
t.Run(tc.path, func(t *testing.T) {
95
+
fi := git.FileInfo{Path: tc.path}
96
+
assert.Equal(t, tc.expected, fi.Name())
97
+
})
98
+
}
99
+
}
100
+
101
+
func TestCommitSummaryAndDetails(t *testing.T) {
102
+
testCases := []struct {
103
+
message string
104
+
expectedSummary string
105
+
expectedDetails string
106
+
}{
107
+
{
108
+
message: "Simple commit message",
109
+
expectedSummary: "Simple commit message",
110
+
expectedDetails: "",
111
+
},
112
+
{
113
+
message: "Add feature X\n\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
114
+
expectedSummary: "Add feature X",
115
+
expectedDetails: "\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
116
+
},
117
+
{
118
+
message: "Fix bug\n\nDetailed explanation",
119
+
expectedSummary: "Fix bug",
120
+
expectedDetails: "\nDetailed explanation",
121
+
},
122
+
}
123
+
124
+
for _, tc := range testCases {
125
+
t.Run(tc.message, func(t *testing.T) {
126
+
commit := git.Commit{
127
+
SHA: "abcdef1234567890",
128
+
Message: tc.message,
129
+
Signature: "",
130
+
Author: "Test User",
131
+
Email: "test@example.com",
132
+
When: time.Now(),
133
+
}
134
+
135
+
assert.Equal(t, tc.expectedSummary, commit.Summary())
136
+
assert.Equal(t, tc.expectedDetails, commit.Details())
137
+
})
138
+
}
139
+
}
140
+
141
+
func TestCommitShort(t *testing.T) {
142
+
commit := git.Commit{
143
+
SHA: "abcdef1234567890abcdef1234567890",
144
+
}
145
+
146
+
assert.Equal(t, "abcdef12", commit.Short())
147
+
}
148
+
149
+
func TestCommitFilePath(t *testing.T) {
150
+
testCases := []struct {
151
+
name string
152
+
fromPath string
153
+
toPath string
154
+
expected string
155
+
}{
156
+
{
157
+
name: "to path preferred",
158
+
fromPath: "old/path.txt",
159
+
toPath: "new/path.txt",
160
+
expected: "new/path.txt",
161
+
},
162
+
{
163
+
name: "fallback to from path",
164
+
fromPath: "deleted/file.txt",
165
+
toPath: "",
166
+
expected: "deleted/file.txt",
167
+
},
168
+
{
169
+
name: "both paths empty",
170
+
fromPath: "",
171
+
toPath: "",
172
+
expected: "",
173
+
},
174
+
}
175
+
176
+
for _, tc := range testCases {
177
+
t.Run(tc.name, func(t *testing.T) {
178
+
cf := git.CommitFile{
179
+
From: git.CommitFileEntry{Path: tc.fromPath},
180
+
To: git.CommitFileEntry{Path: tc.toPath},
181
+
}
182
+
assert.Equal(t, tc.expected, cf.Path())
183
+
})
184
+
}
185
+
}
186
+
187
+
func TestRepoName(t *testing.T) {
188
+
tmp := t.TempDir()
189
+
190
+
repoName := "testrepo"
191
+
err := git.EnsureRepo(tmp, repoName+".git")
192
+
assert.NoError(t, err)
193
+
194
+
repo, err := git.NewRepo(tmp, repoName)
195
+
assert.NoError(t, err)
196
+
assert.Equal(t, repoName, repo.Name())
197
+
198
+
repoName2 := "test-repo-with-hyphens"
199
+
err = git.EnsureRepo(tmp, repoName2+".git")
200
+
assert.NoError(t, err)
201
+
202
+
repo2, err := git.NewRepo(tmp, repoName2)
203
+
assert.NoError(t, err)
204
+
assert.Equal(t, repoName2, repo2.Name())
205
+
}
206
+
207
+
func TestHandlePushOptions(t *testing.T) {
208
+
tmp := t.TempDir()
209
+
err := git.EnsureRepo(tmp, "test.git")
210
+
assert.NoError(t, err)
211
+
212
+
repo, err := git.NewRepo(tmp, "test")
213
+
assert.NoError(t, err)
214
+
215
+
opts := []*packp.Option{
216
+
{Key: "description", Value: "New description"},
217
+
}
218
+
err = git.HandlePushOptions(repo, opts)
219
+
assert.NoError(t, err)
220
+
assert.Equal(t, "New description", repo.Meta.Description)
221
+
222
+
opts = []*packp.Option{
223
+
{Key: "private", Value: "false"},
224
+
}
225
+
err = git.HandlePushOptions(repo, opts)
226
+
assert.NoError(t, err)
227
+
assert.False(t, repo.Meta.Private)
228
+
229
+
repo.Meta.Private = true
230
+
opts = []*packp.Option{
231
+
{Key: "private", Value: "invalid"},
232
+
}
233
+
err = git.HandlePushOptions(repo, opts)
234
+
assert.NoError(t, err)
235
+
assert.True(t, repo.Meta.Private)
236
+
237
+
opts = []*packp.Option{
238
+
{Key: "tags", Value: "tag1,tag2"},
239
+
}
240
+
err = git.HandlePushOptions(repo, opts)
241
+
assert.NoError(t, err)
242
+
243
+
opts = []*packp.Option{
244
+
{Key: "description", Value: "Combined update"},
245
+
{Key: "private", Value: "true"},
246
+
}
247
+
err = git.HandlePushOptions(repo, opts)
248
+
assert.NoError(t, err)
249
+
assert.Equal(t, "Combined update", repo.Meta.Description)
250
+
assert.True(t, repo.Meta.Private)
251
+
}
252
+
253
+
func TestRepoPath(t *testing.T) {
254
+
tmp := t.TempDir()
255
+
err := git.EnsureRepo(tmp, "test.git")
256
+
assert.NoError(t, err)
257
+
258
+
repo, err := git.NewRepo(tmp, "test")
259
+
assert.NoError(t, err)
260
+
261
+
expected := filepath.Join(tmp, "test.git")
262
+
assert.Equal(t, expected, repo.Path())
263
+
}
264
+
265
+
func TestEnsureJSONFile(t *testing.T) {
266
+
tmp := t.TempDir()
267
+
err := git.EnsureRepo(tmp, "test.git")
268
+
assert.NoError(t, err)
269
+
270
+
repo, err := git.NewRepo(tmp, "test")
271
+
assert.NoError(t, err)
272
+
273
+
assert.True(t, repo.Meta.Private, "default repo should be private")
274
+
assert.Equal(t, "", repo.Meta.Description, "default description should be empty")
275
+
assert.Equal(t, 0, len(repo.Meta.Tags), "default tags should be empty")
276
+
}
+4
-2
internal/git/grep.go
+4
-2
internal/git/grep.go
···
18
19
// Grep performs a naive "code search" via git grep
20
func (r Repo) Grep(search string) ([]GrepResult, error) {
21
+
if after, ok := strings.CutPrefix(search, "="); ok {
22
+
search = regexp.QuoteMeta(after)
23
+
}
24
+
re, err := regexp.Compile(search)
25
if err != nil {
26
return nil, err
27
}
+66
-4
internal/git/meta.go
+66
-4
internal/git/meta.go
···
3
import (
4
"encoding/json"
5
"errors"
6
"io/fs"
7
"os"
8
"path/filepath"
9
)
10
11
// RepoMeta is the meta information a Repo can have
12
type RepoMeta struct {
13
-
Description string `json:"description"`
14
-
Private bool `json:"private"`
15
-
Tags []string `json:"tags"`
16
}
17
18
// Update updates meta given another RepoMeta
···
46
return json.NewEncoder(fi).Encode(r.Meta)
47
}
48
49
func ensureJSONFile(path string) error {
50
_, err := os.Stat(path)
51
if err == nil {
···
59
return err
60
}
61
defer fi.Close()
62
-
if _, err := fi.WriteString(`{"private":true}`); err != nil {
63
return err
64
}
65
return nil
···
3
import (
4
"encoding/json"
5
"errors"
6
+
"fmt"
7
"io/fs"
8
"os"
9
"path/filepath"
10
+
"slices"
11
)
12
13
// RepoMeta is the meta information a Repo can have
14
type RepoMeta struct {
15
+
Description string `json:"description"`
16
+
Private bool `json:"private"`
17
+
Tags TagSet `json:"tags"`
18
+
}
19
+
20
+
// TagSet is a Set of tags
21
+
type TagSet map[string]struct{}
22
+
23
+
// Add adds a tag to the set
24
+
func (t TagSet) Add(tag string) {
25
+
t[tag] = struct{}{}
26
+
}
27
+
28
+
// Remove removes a tag from the set
29
+
func (t TagSet) Remove(tag string) {
30
+
delete(t, tag)
31
+
}
32
+
33
+
// Contains checks if a tag is in the set
34
+
func (t TagSet) Contains(tag string) bool {
35
+
_, ok := t[tag]
36
+
return ok
37
+
}
38
+
39
+
// Slice returns the set as a (sorted) slice
40
+
func (t TagSet) Slice() []string {
41
+
s := make([]string, 0, len(t))
42
+
for k := range t {
43
+
s = append(s, k)
44
+
}
45
+
slices.Sort(s)
46
+
return s
47
+
}
48
+
49
+
// MarshalJSON implements [json.Marshaler]
50
+
func (t TagSet) MarshalJSON() ([]byte, error) {
51
+
return json.Marshal(t.Slice())
52
+
}
53
+
54
+
// UnmarshalJSON implements [json.Unmarshaler]
55
+
func (t *TagSet) UnmarshalJSON(b []byte) error {
56
+
if *t == nil {
57
+
ts := make(TagSet)
58
+
t = &ts
59
+
}
60
+
var s []string
61
+
if err := json.Unmarshal(b, &s); err != nil {
62
+
return err
63
+
}
64
+
for _, ss := range s {
65
+
t.Add(ss)
66
+
}
67
+
return nil
68
}
69
70
// Update updates meta given another RepoMeta
···
98
return json.NewEncoder(fi).Encode(r.Meta)
99
}
100
101
+
var defaultMeta = func() []byte {
102
+
b, err := json.Marshal(RepoMeta{
103
+
Private: true,
104
+
})
105
+
if err != nil {
106
+
panic(fmt.Sprintf("could not init default meta: %v", err))
107
+
}
108
+
return b
109
+
}()
110
+
111
func ensureJSONFile(path string) error {
112
_, err := os.Stat(path)
113
if err == nil {
···
121
return err
122
}
123
defer fi.Close()
124
+
if _, err := fi.Write(defaultMeta); err != nil {
125
return err
126
}
127
return nil
+53
internal/git/meta_test.go
+53
internal/git/meta_test.go
···
···
1
+
package git
2
+
3
+
import (
4
+
"encoding/json"
5
+
"testing"
6
+
7
+
"github.com/alecthomas/assert/v2"
8
+
)
9
+
10
+
func TestTagSet(t *testing.T) {
11
+
set := make(TagSet)
12
+
assert.Equal(t, 0, len(set))
13
+
assert.Equal(t, 0, len(set.Slice()))
14
+
15
+
set.Add("foo")
16
+
assert.Equal(t, 1, len(set))
17
+
assert.Equal(t, 1, len(set.Slice()))
18
+
assert.True(t, set.Contains("foo"))
19
+
20
+
set.Add("bar")
21
+
assert.Equal(t, 2, len(set))
22
+
assert.Equal(t, 2, len(set.Slice()))
23
+
assert.True(t, set.Contains("foo"))
24
+
assert.True(t, set.Contains("bar"))
25
+
26
+
set.Add("bar")
27
+
assert.Equal(t, 2, len(set))
28
+
assert.Equal(t, 2, len(set.Slice()))
29
+
assert.True(t, set.Contains("foo"))
30
+
assert.True(t, set.Contains("bar"))
31
+
32
+
set.Remove("foo")
33
+
assert.Equal(t, 1, len(set))
34
+
assert.Equal(t, 1, len(set.Slice()))
35
+
assert.False(t, set.Contains("foo"))
36
+
assert.True(t, set.Contains("bar"))
37
+
38
+
set.Add("foo")
39
+
set.Add("baz")
40
+
j, err := json.Marshal(set)
41
+
assert.NoError(t, err)
42
+
assert.Equal(t, `["bar","baz","foo"]`, string(j))
43
+
44
+
set = make(TagSet)
45
+
b := []byte(`["foo","bar","baz"]`)
46
+
err = json.Unmarshal(b, &set)
47
+
assert.NoError(t, err)
48
+
assert.Equal(t, 3, len(set))
49
+
assert.Equal(t, 3, len(set.Slice()))
50
+
assert.True(t, set.Contains("foo"))
51
+
assert.True(t, set.Contains("bar"))
52
+
assert.True(t, set.Contains("baz"))
53
+
}
+5
-9
internal/git/protocol.go
+5
-9
internal/git/protocol.go
···
58
remove = true
59
tagValue = strings.TrimPrefix(tagValue, "-")
60
}
61
-
for idx, tag := range repo.Meta.Tags {
62
-
if strings.EqualFold(tag, tagValue) {
63
-
if remove {
64
-
repo.Meta.Tags = append(repo.Meta.Tags[:idx], repo.Meta.Tags[idx+1:]...)
65
-
} else {
66
-
repo.Meta.Tags = append(repo.Meta.Tags, strings.ToLower(tagValue))
67
-
}
68
-
break
69
-
}
70
}
71
}
72
}
-1
internal/git/protocol_git.go
-1
internal/git/protocol_git.go
+11
internal/git/repo.go
+11
internal/git/repo.go
···
57
if err := json.NewDecoder(fi).Decode(&r.Meta); err != nil {
58
return nil, err
59
}
60
+
if r.Meta.Tags == nil {
61
+
r.Meta.Tags = make(TagSet)
62
+
}
63
64
return r, nil
65
}
···
135
type CommitFileEntry struct {
136
Path string
137
Commit string
138
+
}
139
+
140
+
// Path returns either the To or From path, in order of preference
141
+
func (c CommitFile) Path() string {
142
+
if c.To.Path != "" {
143
+
return c.To.Path
144
+
}
145
+
return c.From.Path
146
}
147
148
// Short returns the first eight characters of the SHA
+3
-1
internal/html/base.templ
+3
-1
internal/html/base.templ
···
18
<meta property="og:description" content={ bc.Description }/>
19
</head>
20
<body class="latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10">
21
-
<h2 class="text-text text-xl mb-3"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href="/">Home</a></h2>
22
{ children... }
23
</body>
24
</html>
···
18
<meta property="og:description" content={ bc.Description }/>
19
</head>
20
<body class="latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10">
21
+
<h2 class="text-text text-xl mb-3">
22
+
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href="/">Home</a>
23
+
</h2>
24
{ children... }
25
</body>
26
</html>
+22
-17
internal/html/base_templ.go
+22
-17
internal/html/base_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
type BaseContext struct {
14
Title string
···
16
}
17
18
func base(bc BaseContext) templ.Component {
19
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
20
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
21
if !templ_7745c5c3_IsBuffer {
22
-
templ_7745c5c3_Buffer = templ.GetBuffer()
23
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
24
}
25
ctx = templ.InitializeContext(ctx)
26
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
28
templ_7745c5c3_Var1 = templ.NopComponent
29
}
30
ctx = templ.ClearChildren(ctx)
31
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>")
32
if templ_7745c5c3_Err != nil {
33
return templ_7745c5c3_Err
34
}
···
41
if templ_7745c5c3_Err != nil {
42
return templ_7745c5c3_Err
43
}
44
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title><link rel=\"icon\" href=\"/_/favicon.svg\"><link rel=\"stylesheet\" href=\"/_/tailwind.css\"><meta property=\"og:title\" content=\"")
45
if templ_7745c5c3_Err != nil {
46
return templ_7745c5c3_Err
47
}
···
54
if templ_7745c5c3_Err != nil {
55
return templ_7745c5c3_Err
56
}
57
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><meta property=\"og:description\" content=\"")
58
if templ_7745c5c3_Err != nil {
59
return templ_7745c5c3_Err
60
}
···
67
if templ_7745c5c3_Err != nil {
68
return templ_7745c5c3_Err
69
}
70
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></head><body class=\"latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10\"><h2 class=\"text-text text-xl mb-3\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"/\">Home</a></h2>")
71
if templ_7745c5c3_Err != nil {
72
return templ_7745c5c3_Err
73
}
···
75
if templ_7745c5c3_Err != nil {
76
return templ_7745c5c3_Err
77
}
78
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>")
79
if templ_7745c5c3_Err != nil {
80
return templ_7745c5c3_Err
81
}
82
-
if !templ_7745c5c3_IsBuffer {
83
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
84
-
}
85
-
return templ_7745c5c3_Err
86
})
87
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
type BaseContext struct {
12
Title string
···
14
}
15
16
func base(bc BaseContext) templ.Component {
17
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
18
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
19
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
20
+
return templ_7745c5c3_CtxErr
21
+
}
22
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
23
if !templ_7745c5c3_IsBuffer {
24
+
defer func() {
25
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
26
+
if templ_7745c5c3_Err == nil {
27
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
28
+
}
29
+
}()
30
}
31
ctx = templ.InitializeContext(ctx)
32
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
34
templ_7745c5c3_Var1 = templ.NopComponent
35
}
36
ctx = templ.ClearChildren(ctx)
37
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>")
38
if templ_7745c5c3_Err != nil {
39
return templ_7745c5c3_Err
40
}
···
47
if templ_7745c5c3_Err != nil {
48
return templ_7745c5c3_Err
49
}
50
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><link rel=\"icon\" href=\"/_/favicon.svg\"><link rel=\"stylesheet\" href=\"/_/tailwind.css\"><meta property=\"og:title\" content=\"")
51
if templ_7745c5c3_Err != nil {
52
return templ_7745c5c3_Err
53
}
···
60
if templ_7745c5c3_Err != nil {
61
return templ_7745c5c3_Err
62
}
63
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta property=\"og:description\" content=\"")
64
if templ_7745c5c3_Err != nil {
65
return templ_7745c5c3_Err
66
}
···
73
if templ_7745c5c3_Err != nil {
74
return templ_7745c5c3_Err
75
}
76
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"></head><body class=\"latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10\"><h2 class=\"text-text text-xl mb-3\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"/\">Home</a></h2>")
77
if templ_7745c5c3_Err != nil {
78
return templ_7745c5c3_Err
79
}
···
81
if templ_7745c5c3_Err != nil {
82
return templ_7745c5c3_Err
83
}
84
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>")
85
if templ_7745c5c3_Err != nil {
86
return templ_7745c5c3_Err
87
}
88
+
return nil
89
})
90
}
91
+
92
+
var _ = templruntime.GeneratedTemplate
-4
internal/html/generate.css
-4
internal/html/generate.css
+7
-5
internal/html/generate.go
+7
-5
internal/html/generate.go
···
12
13
"go.jolheiser.com/ugit/internal/html/markup"
14
15
"github.com/alecthomas/chroma/v2/styles"
16
)
17
···
25
otherCSS string
26
)
27
28
-
//go:generate templ generate
29
//go:generate go run generate.go
30
func main() {
31
if err := tailwind(); err != nil {
···
33
}
34
}
35
36
-
// Generate tailwind code from templ templates and combine with other misc CSS
37
func tailwind() error {
38
fmt.Println("generating tailwind...")
39
···
47
}
48
49
fmt.Println("generating chroma styles...")
50
51
latte := styles.Get("catppuccin-latte")
52
-
if err := markup.Formatter.WriteCSS(tmp, latte); err != nil {
53
return err
54
}
55
56
tmp.WriteString("@media (prefers-color-scheme: dark) {")
57
mocha := styles.Get("catppuccin-mocha")
58
-
if err := markup.Formatter.WriteCSS(tmp, mocha); err != nil {
59
return err
60
}
61
tmp.WriteString("}")
···
71
defer styles.Close()
72
73
var buf bytes.Buffer
74
-
cmd := exec.Command("tailwind-ctp", "-i", tmp.Name(), "--minify")
75
cmd.Stdout = &buf
76
if err := cmd.Run(); err != nil {
77
return err
···
12
13
"go.jolheiser.com/ugit/internal/html/markup"
14
15
+
"github.com/alecthomas/chroma/v2/formatters/html"
16
"github.com/alecthomas/chroma/v2/styles"
17
)
18
···
26
otherCSS string
27
)
28
29
+
//go:generate go tool templ generate
30
//go:generate go run generate.go
31
func main() {
32
if err := tailwind(); err != nil {
···
34
}
35
}
36
37
+
// Generate tailwind code from templates and combine with other misc CSS
38
func tailwind() error {
39
fmt.Println("generating tailwind...")
40
···
48
}
49
50
fmt.Println("generating chroma styles...")
51
+
formatter := html.New(markup.Options("")...)
52
53
latte := styles.Get("catppuccin-latte")
54
+
if err := formatter.WriteCSS(tmp, latte); err != nil {
55
return err
56
}
57
58
tmp.WriteString("@media (prefers-color-scheme: dark) {")
59
mocha := styles.Get("catppuccin-mocha")
60
+
if err := formatter.WriteCSS(tmp, mocha); err != nil {
61
return err
62
}
63
tmp.WriteString("}")
···
73
defer styles.Close()
74
75
var buf bytes.Buffer
76
+
cmd := exec.Command("tailwind-ctp_3", "-i", tmp.Name(), "--minify")
77
cmd.Stdout = &buf
78
if err := cmd.Run(); err != nil {
79
return err
+28
-8
internal/html/index.templ
+28
-8
internal/html/index.templ
···
1
package html
2
3
-
import "go.jolheiser.com/ugit/internal/git"
4
-
import "github.com/dustin/go-humanize"
5
-
import "go.jolheiser.com/ugit/assets"
6
7
type IndexContext struct {
8
BaseContext
···
21
URL string
22
}
23
24
-
func lastCommit(repo *git.Repo, human bool) string {
25
c, err := repo.LastCommit()
26
if err != nil {
27
return ""
···
32
return c.When.Format("01/02/2006 03:04:05 PM")
33
}
34
35
templ Index(ic IndexContext) {
36
@base(ic.BaseContext) {
37
<header>
···
62
</div>
63
}
64
</div>
65
-
<div class="grid sm:grid-cols-8 gap-2 mt-5">
66
for _, repo := range ic.Repos {
67
<div class="sm:col-span-2 text-blue dark:text-lavender"><a class="underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ templ.URL("/" + repo.Name()) }>{ repo.Name() }</a></div>
68
-
<div class="sm:col-span-4 text-subtext0">{ repo.Meta.Description }</div>
69
<div class="sm:col-span-1 text-subtext0">
70
-
for _, tag := range repo.Meta.Tags {
71
<a href={ templ.SafeURL("?tag=" + tag) } class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</a>
72
}
73
</div>
74
-
<div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommit(repo, false) }>{ lastCommit(repo, true) }</div>
75
}
76
</div>
77
</main>
···
1
package html
2
3
+
import (
4
+
"fmt"
5
+
"github.com/dustin/go-humanize"
6
+
"go.jolheiser.com/ugit/assets"
7
+
"go.jolheiser.com/ugit/internal/git"
8
+
)
9
10
type IndexContext struct {
11
BaseContext
···
24
URL string
25
}
26
27
+
func lastCommitTime(repo *git.Repo, human bool) string {
28
c, err := repo.LastCommit()
29
if err != nil {
30
return ""
···
35
return c.When.Format("01/02/2006 03:04:05 PM")
36
}
37
38
+
func lastCommit(repo *git.Repo) *git.Commit {
39
+
c, err := repo.LastCommit()
40
+
if err != nil {
41
+
return nil
42
+
}
43
+
return &c
44
+
}
45
+
46
templ Index(ic IndexContext) {
47
@base(ic.BaseContext) {
48
<header>
···
73
</div>
74
}
75
</div>
76
+
<div class="grid sm:grid-cols-10 gap-2 mt-5">
77
for _, repo := range ic.Repos {
78
+
{{ commit := lastCommit(repo) }}
79
<div class="sm:col-span-2 text-blue dark:text-lavender"><a class="underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ templ.URL("/" + repo.Name()) }>{ repo.Name() }</a></div>
80
+
<div class="sm:col-span-3 text-subtext0">{ repo.Meta.Description }</div>
81
+
<div class="sm:col-span-3 text-subtext0">
82
+
if commit != nil {
83
+
<div title={ commit.Message }>
84
+
<a class="underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA) }>{ commit.Short() }</a>
85
+
{ ": " + commit.Summary() }
86
+
</div>
87
+
}
88
+
</div>
89
<div class="sm:col-span-1 text-subtext0">
90
+
for _, tag := range repo.Meta.Tags.Slice() {
91
<a href={ templ.SafeURL("?tag=" + tag) } class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</a>
92
}
93
</div>
94
+
<div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommitTime(repo, false) }>{ lastCommitTime(repo, true) }</div>
95
}
96
</div>
97
</main>
+175
-77
internal/html/index_templ.go
+175
-77
internal/html/index_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
-
import "go.jolheiser.com/ugit/internal/git"
14
-
import "github.com/dustin/go-humanize"
15
-
import "go.jolheiser.com/ugit/assets"
16
17
type IndexContext struct {
18
BaseContext
···
31
URL string
32
}
33
34
-
func lastCommit(repo *git.Repo, human bool) string {
35
c, err := repo.LastCommit()
36
if err != nil {
37
return ""
···
42
return c.When.Format("01/02/2006 03:04:05 PM")
43
}
44
45
func Index(ic IndexContext) templ.Component {
46
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
47
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
48
if !templ_7745c5c3_IsBuffer {
49
-
templ_7745c5c3_Buffer = templ.GetBuffer()
50
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
51
}
52
ctx = templ.InitializeContext(ctx)
53
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
55
templ_7745c5c3_Var1 = templ.NopComponent
56
}
57
ctx = templ.ClearChildren(ctx)
58
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
59
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
60
if !templ_7745c5c3_IsBuffer {
61
-
templ_7745c5c3_Buffer = templ.GetBuffer()
62
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
63
}
64
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header><h1 class=\"text-text text-xl font-bold\">")
65
if templ_7745c5c3_Err != nil {
66
return templ_7745c5c3_Err
67
}
68
var templ_7745c5c3_Var3 string
69
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Title)
70
if templ_7745c5c3_Err != nil {
71
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 38, Col: 53}
72
}
73
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
74
if templ_7745c5c3_Err != nil {
75
return templ_7745c5c3_Err
76
}
77
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><h2 class=\"text-subtext1 text-lg\">")
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
81
var templ_7745c5c3_Var4 string
82
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Description)
83
if templ_7745c5c3_Err != nil {
84
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 39, Col: 53}
85
}
86
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
87
if templ_7745c5c3_Err != nil {
88
return templ_7745c5c3_Err
89
}
90
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2></header><main class=\"mt-5\"><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
91
if templ_7745c5c3_Err != nil {
92
return templ_7745c5c3_Err
93
}
94
if ic.Profile.Username != "" {
95
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve\">")
96
if templ_7745c5c3_Err != nil {
97
return templ_7745c5c3_Err
98
}
99
var templ_7745c5c3_Var5 string
100
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(`@` + ic.Profile.Username)
101
if templ_7745c5c3_Err != nil {
102
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 44, Col: 56}
103
}
104
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
105
if templ_7745c5c3_Err != nil {
106
return templ_7745c5c3_Err
107
}
108
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
109
if templ_7745c5c3_Err != nil {
110
return templ_7745c5c3_Err
111
}
112
}
113
if ic.Profile.Email != "" {
114
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve col-span-2\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
115
if templ_7745c5c3_Err != nil {
116
return templ_7745c5c3_Err
117
}
···
119
if templ_7745c5c3_Err != nil {
120
return templ_7745c5c3_Err
121
}
122
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"")
123
if templ_7745c5c3_Err != nil {
124
return templ_7745c5c3_Err
125
}
126
-
var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL("mailto:" + ic.Profile.Email)
127
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6)))
128
if templ_7745c5c3_Err != nil {
129
return templ_7745c5c3_Err
130
}
131
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
132
if templ_7745c5c3_Err != nil {
133
return templ_7745c5c3_Err
134
}
135
var templ_7745c5c3_Var7 string
136
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Profile.Email)
137
if templ_7745c5c3_Err != nil {
138
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 51, Col: 159}
139
}
140
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
141
if templ_7745c5c3_Err != nil {
142
return templ_7745c5c3_Err
143
}
144
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
145
if templ_7745c5c3_Err != nil {
146
return templ_7745c5c3_Err
147
}
148
}
149
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
150
if templ_7745c5c3_Err != nil {
151
return templ_7745c5c3_Err
152
}
153
for _, link := range ic.Profile.Links {
154
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
155
if templ_7745c5c3_Err != nil {
156
return templ_7745c5c3_Err
157
}
···
159
if templ_7745c5c3_Err != nil {
160
return templ_7745c5c3_Err
161
}
162
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" rel=\"me\" href=\"")
163
if templ_7745c5c3_Err != nil {
164
return templ_7745c5c3_Err
165
}
166
-
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(link.URL)
167
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
168
if templ_7745c5c3_Err != nil {
169
return templ_7745c5c3_Err
170
}
171
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
172
if templ_7745c5c3_Err != nil {
173
return templ_7745c5c3_Err
174
}
175
var templ_7745c5c3_Var9 string
176
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name)
177
if templ_7745c5c3_Err != nil {
178
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 61, Col: 141}
179
}
180
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
181
if templ_7745c5c3_Err != nil {
182
return templ_7745c5c3_Err
183
}
184
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
185
if templ_7745c5c3_Err != nil {
186
return templ_7745c5c3_Err
187
}
188
}
189
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid sm:grid-cols-8 gap-2 mt-5\">")
190
if templ_7745c5c3_Err != nil {
191
return templ_7745c5c3_Err
192
}
193
for _, repo := range ic.Repos {
194
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-2 text-blue dark:text-lavender\"><a class=\"underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"")
195
if templ_7745c5c3_Err != nil {
196
return templ_7745c5c3_Err
197
}
198
-
var templ_7745c5c3_Var10 templ.SafeURL = templ.URL("/" + repo.Name())
199
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
200
if templ_7745c5c3_Err != nil {
201
return templ_7745c5c3_Err
202
}
203
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
204
if templ_7745c5c3_Err != nil {
205
return templ_7745c5c3_Err
206
}
207
var templ_7745c5c3_Var11 string
208
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Name())
209
if templ_7745c5c3_Err != nil {
210
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 67, Col: 221}
211
}
212
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
213
if templ_7745c5c3_Err != nil {
214
return templ_7745c5c3_Err
215
}
216
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"sm:col-span-4 text-subtext0\">")
217
if templ_7745c5c3_Err != nil {
218
return templ_7745c5c3_Err
219
}
220
var templ_7745c5c3_Var12 string
221
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Meta.Description)
222
if templ_7745c5c3_Err != nil {
223
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 68, Col: 69}
224
}
225
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
226
if templ_7745c5c3_Err != nil {
227
return templ_7745c5c3_Err
228
}
229
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-subtext0\">")
230
if templ_7745c5c3_Err != nil {
231
return templ_7745c5c3_Err
232
}
233
-
for _, tag := range repo.Meta.Tags {
234
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a href=\"")
235
if templ_7745c5c3_Err != nil {
236
return templ_7745c5c3_Err
237
}
238
-
var templ_7745c5c3_Var13 templ.SafeURL = templ.SafeURL("?tag=" + tag)
239
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var13)))
240
if templ_7745c5c3_Err != nil {
241
return templ_7745c5c3_Err
242
}
243
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
244
if templ_7745c5c3_Err != nil {
245
return templ_7745c5c3_Err
246
}
247
-
var templ_7745c5c3_Var14 string
248
-
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(tag)
249
if templ_7745c5c3_Err != nil {
250
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 71, Col: 141}
251
}
252
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
253
if templ_7745c5c3_Err != nil {
254
return templ_7745c5c3_Err
255
}
256
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
257
if templ_7745c5c3_Err != nil {
258
return templ_7745c5c3_Err
259
}
260
}
261
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"")
262
if templ_7745c5c3_Err != nil {
263
return templ_7745c5c3_Err
264
}
265
-
var templ_7745c5c3_Var15 string
266
-
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, false))
267
if templ_7745c5c3_Err != nil {
268
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 89}
269
}
270
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
271
if templ_7745c5c3_Err != nil {
272
return templ_7745c5c3_Err
273
}
274
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
275
if templ_7745c5c3_Err != nil {
276
return templ_7745c5c3_Err
277
}
278
-
var templ_7745c5c3_Var16 string
279
-
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, true))
280
if templ_7745c5c3_Err != nil {
281
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 116}
282
}
283
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
284
if templ_7745c5c3_Err != nil {
285
return templ_7745c5c3_Err
286
}
287
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
288
if templ_7745c5c3_Err != nil {
289
return templ_7745c5c3_Err
290
}
291
}
292
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></main>")
293
if templ_7745c5c3_Err != nil {
294
return templ_7745c5c3_Err
295
}
296
-
if !templ_7745c5c3_IsBuffer {
297
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
298
-
}
299
-
return templ_7745c5c3_Err
300
})
301
templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
302
if templ_7745c5c3_Err != nil {
303
return templ_7745c5c3_Err
304
}
305
-
if !templ_7745c5c3_IsBuffer {
306
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
307
-
}
308
-
return templ_7745c5c3_Err
309
})
310
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
+
import (
12
+
"fmt"
13
+
"github.com/dustin/go-humanize"
14
+
"go.jolheiser.com/ugit/assets"
15
+
"go.jolheiser.com/ugit/internal/git"
16
+
)
17
18
type IndexContext struct {
19
BaseContext
···
32
URL string
33
}
34
35
+
func lastCommitTime(repo *git.Repo, human bool) string {
36
c, err := repo.LastCommit()
37
if err != nil {
38
return ""
···
43
return c.When.Format("01/02/2006 03:04:05 PM")
44
}
45
46
+
func lastCommit(repo *git.Repo) *git.Commit {
47
+
c, err := repo.LastCommit()
48
+
if err != nil {
49
+
return nil
50
+
}
51
+
return &c
52
+
}
53
+
54
func Index(ic IndexContext) templ.Component {
55
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
56
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
57
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
58
+
return templ_7745c5c3_CtxErr
59
+
}
60
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
61
if !templ_7745c5c3_IsBuffer {
62
+
defer func() {
63
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
64
+
if templ_7745c5c3_Err == nil {
65
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
66
+
}
67
+
}()
68
}
69
ctx = templ.InitializeContext(ctx)
70
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
72
templ_7745c5c3_Var1 = templ.NopComponent
73
}
74
ctx = templ.ClearChildren(ctx)
75
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
76
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
77
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
78
if !templ_7745c5c3_IsBuffer {
79
+
defer func() {
80
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
81
+
if templ_7745c5c3_Err == nil {
82
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
83
+
}
84
+
}()
85
}
86
+
ctx = templ.InitializeContext(ctx)
87
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<header><h1 class=\"text-text text-xl font-bold\">")
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
var templ_7745c5c3_Var3 string
92
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Title)
93
if templ_7745c5c3_Err != nil {
94
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 49, Col: 53}
95
}
96
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
97
if templ_7745c5c3_Err != nil {
98
return templ_7745c5c3_Err
99
}
100
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</h1><h2 class=\"text-subtext1 text-lg\">")
101
if templ_7745c5c3_Err != nil {
102
return templ_7745c5c3_Err
103
}
104
var templ_7745c5c3_Var4 string
105
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Description)
106
if templ_7745c5c3_Err != nil {
107
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 50, Col: 53}
108
}
109
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
110
if templ_7745c5c3_Err != nil {
111
return templ_7745c5c3_Err
112
}
113
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h2></header><main class=\"mt-5\"><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
114
if templ_7745c5c3_Err != nil {
115
return templ_7745c5c3_Err
116
}
117
if ic.Profile.Username != "" {
118
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"text-mauve\">")
119
if templ_7745c5c3_Err != nil {
120
return templ_7745c5c3_Err
121
}
122
var templ_7745c5c3_Var5 string
123
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(`@` + ic.Profile.Username)
124
if templ_7745c5c3_Err != nil {
125
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 55, Col: 56}
126
}
127
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
128
if templ_7745c5c3_Err != nil {
129
return templ_7745c5c3_Err
130
}
131
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div>")
132
if templ_7745c5c3_Err != nil {
133
return templ_7745c5c3_Err
134
}
135
}
136
if ic.Profile.Email != "" {
137
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"text-mauve col-span-2\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
138
if templ_7745c5c3_Err != nil {
139
return templ_7745c5c3_Err
140
}
···
142
if templ_7745c5c3_Err != nil {
143
return templ_7745c5c3_Err
144
}
145
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"")
146
if templ_7745c5c3_Err != nil {
147
return templ_7745c5c3_Err
148
}
149
+
var templ_7745c5c3_Var6 templ.SafeURL
150
+
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("mailto:" + ic.Profile.Email))
151
+
if templ_7745c5c3_Err != nil {
152
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 62, Col: 138}
153
+
}
154
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
155
if templ_7745c5c3_Err != nil {
156
return templ_7745c5c3_Err
157
}
158
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">")
159
if templ_7745c5c3_Err != nil {
160
return templ_7745c5c3_Err
161
}
162
var templ_7745c5c3_Var7 string
163
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Profile.Email)
164
if templ_7745c5c3_Err != nil {
165
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 62, Col: 159}
166
}
167
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
168
if templ_7745c5c3_Err != nil {
169
return templ_7745c5c3_Err
170
}
171
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</a></div>")
172
if templ_7745c5c3_Err != nil {
173
return templ_7745c5c3_Err
174
}
175
}
176
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
177
if templ_7745c5c3_Err != nil {
178
return templ_7745c5c3_Err
179
}
180
for _, link := range ic.Profile.Links {
181
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"text-mauve\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
182
if templ_7745c5c3_Err != nil {
183
return templ_7745c5c3_Err
184
}
···
186
if templ_7745c5c3_Err != nil {
187
return templ_7745c5c3_Err
188
}
189
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" rel=\"me\" href=\"")
190
if templ_7745c5c3_Err != nil {
191
return templ_7745c5c3_Err
192
}
193
+
var templ_7745c5c3_Var8 templ.SafeURL
194
+
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(link.URL))
195
+
if templ_7745c5c3_Err != nil {
196
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 127}
197
+
}
198
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
199
if templ_7745c5c3_Err != nil {
200
return templ_7745c5c3_Err
201
}
202
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
203
if templ_7745c5c3_Err != nil {
204
return templ_7745c5c3_Err
205
}
206
var templ_7745c5c3_Var9 string
207
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name)
208
if templ_7745c5c3_Err != nil {
209
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 141}
210
}
211
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
212
if templ_7745c5c3_Err != nil {
213
return templ_7745c5c3_Err
214
}
215
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a></div>")
216
if templ_7745c5c3_Err != nil {
217
return templ_7745c5c3_Err
218
}
219
}
220
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div><div class=\"grid sm:grid-cols-10 gap-2 mt-5\">")
221
if templ_7745c5c3_Err != nil {
222
return templ_7745c5c3_Err
223
}
224
for _, repo := range ic.Repos {
225
+
commit := lastCommit(repo)
226
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<div class=\"sm:col-span-2 text-blue dark:text-lavender\"><a class=\"underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"")
227
if templ_7745c5c3_Err != nil {
228
return templ_7745c5c3_Err
229
}
230
+
var templ_7745c5c3_Var10 templ.SafeURL
231
+
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/" + repo.Name()))
232
+
if templ_7745c5c3_Err != nil {
233
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 205}
234
+
}
235
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
236
if templ_7745c5c3_Err != nil {
237
return templ_7745c5c3_Err
238
}
239
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">")
240
if templ_7745c5c3_Err != nil {
241
return templ_7745c5c3_Err
242
}
243
var templ_7745c5c3_Var11 string
244
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Name())
245
if templ_7745c5c3_Err != nil {
246
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 221}
247
}
248
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
249
if templ_7745c5c3_Err != nil {
250
return templ_7745c5c3_Err
251
}
252
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</a></div><div class=\"sm:col-span-3 text-subtext0\">")
253
if templ_7745c5c3_Err != nil {
254
return templ_7745c5c3_Err
255
}
256
var templ_7745c5c3_Var12 string
257
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Meta.Description)
258
if templ_7745c5c3_Err != nil {
259
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 80, Col: 69}
260
}
261
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
262
if templ_7745c5c3_Err != nil {
263
return templ_7745c5c3_Err
264
}
265
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div><div class=\"sm:col-span-3 text-subtext0\">")
266
if templ_7745c5c3_Err != nil {
267
return templ_7745c5c3_Err
268
}
269
+
if commit != nil {
270
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div title=\"")
271
if templ_7745c5c3_Err != nil {
272
return templ_7745c5c3_Err
273
}
274
+
var templ_7745c5c3_Var13 string
275
+
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message)
276
+
if templ_7745c5c3_Err != nil {
277
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 34}
278
+
}
279
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
280
if templ_7745c5c3_Err != nil {
281
return templ_7745c5c3_Err
282
}
283
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\"><a class=\"underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"")
284
if templ_7745c5c3_Err != nil {
285
return templ_7745c5c3_Err
286
}
287
+
var templ_7745c5c3_Var14 templ.SafeURL
288
+
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinURLErrs(fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA))
289
if templ_7745c5c3_Err != nil {
290
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 206}
291
}
292
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
293
if templ_7745c5c3_Err != nil {
294
return templ_7745c5c3_Err
295
}
296
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">")
297
+
if templ_7745c5c3_Err != nil {
298
+
return templ_7745c5c3_Err
299
+
}
300
+
var templ_7745c5c3_Var15 string
301
+
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short())
302
+
if templ_7745c5c3_Err != nil {
303
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 225}
304
+
}
305
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
306
+
if templ_7745c5c3_Err != nil {
307
+
return templ_7745c5c3_Err
308
+
}
309
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</a> ")
310
+
if templ_7745c5c3_Err != nil {
311
+
return templ_7745c5c3_Err
312
+
}
313
+
var templ_7745c5c3_Var16 string
314
+
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(": " + commit.Summary())
315
+
if templ_7745c5c3_Err != nil {
316
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 85, Col: 33}
317
+
}
318
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
319
+
if templ_7745c5c3_Err != nil {
320
+
return templ_7745c5c3_Err
321
+
}
322
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div>")
323
if templ_7745c5c3_Err != nil {
324
return templ_7745c5c3_Err
325
}
326
}
327
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</div><div class=\"sm:col-span-1 text-subtext0\">")
328
if templ_7745c5c3_Err != nil {
329
return templ_7745c5c3_Err
330
}
331
+
for _, tag := range repo.Meta.Tags.Slice() {
332
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"")
333
+
if templ_7745c5c3_Err != nil {
334
+
return templ_7745c5c3_Err
335
+
}
336
+
var templ_7745c5c3_Var17 templ.SafeURL
337
+
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?tag=" + tag))
338
+
if templ_7745c5c3_Err != nil {
339
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 45}
340
+
}
341
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
342
+
if templ_7745c5c3_Err != nil {
343
+
return templ_7745c5c3_Err
344
+
}
345
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
346
+
if templ_7745c5c3_Err != nil {
347
+
return templ_7745c5c3_Err
348
+
}
349
+
var templ_7745c5c3_Var18 string
350
+
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(tag)
351
+
if templ_7745c5c3_Err != nil {
352
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 141}
353
+
}
354
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
355
+
if templ_7745c5c3_Err != nil {
356
+
return templ_7745c5c3_Err
357
+
}
358
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a>")
359
+
if templ_7745c5c3_Err != nil {
360
+
return templ_7745c5c3_Err
361
+
}
362
+
}
363
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"")
364
if templ_7745c5c3_Err != nil {
365
+
return templ_7745c5c3_Err
366
+
}
367
+
var templ_7745c5c3_Var19 string
368
+
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, false))
369
+
if templ_7745c5c3_Err != nil {
370
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 93}
371
}
372
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
373
if templ_7745c5c3_Err != nil {
374
return templ_7745c5c3_Err
375
}
376
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\">")
377
if templ_7745c5c3_Err != nil {
378
return templ_7745c5c3_Err
379
}
380
+
var templ_7745c5c3_Var20 string
381
+
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, true))
382
if templ_7745c5c3_Err != nil {
383
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 124}
384
}
385
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
386
if templ_7745c5c3_Err != nil {
387
return templ_7745c5c3_Err
388
}
389
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</div>")
390
if templ_7745c5c3_Err != nil {
391
return templ_7745c5c3_Err
392
}
393
}
394
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</div></main>")
395
if templ_7745c5c3_Err != nil {
396
return templ_7745c5c3_Err
397
}
398
+
return nil
399
})
400
templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
401
if templ_7745c5c3_Err != nil {
402
return templ_7745c5c3_Err
403
}
404
+
return nil
405
})
406
}
407
+
408
+
var _ = templruntime.GeneratedTemplate
+16
-24
internal/html/markup/chroma.go
+16
-24
internal/html/markup/chroma.go
···
2
3
import (
4
"io"
5
6
"github.com/alecthomas/chroma/v2"
7
"github.com/alecthomas/chroma/v2/formatters/html"
···
9
"github.com/alecthomas/chroma/v2/styles"
10
)
11
12
-
var (
13
-
// Formatter is the default formatter
14
-
Formatter = html.New(
15
html.WithLineNumbers(true),
16
-
html.WithLinkableLineNumbers(true, "L"),
17
html.WithClasses(true),
18
html.LineNumbersInTable(true),
19
-
)
20
-
basicFormatter = html.New(
21
-
html.WithClasses(true),
22
-
)
23
-
// Code is the entrypoint for formatting
24
-
Code = code{}
25
-
)
26
-
27
-
type code struct{}
28
29
func setup(source []byte, fileName string) (chroma.Iterator, *chroma.Style, error) {
30
lexer := lexers.Match(fileName)
31
if lexer == nil {
32
lexer = lexers.Fallback
33
}
34
lexer = chroma.Coalesce(lexer)
35
···
46
return iter, style, nil
47
}
48
49
-
// Basic formats code without any extras
50
-
func (c code) Basic(source []byte, fileName string, writer io.Writer) error {
51
-
iter, style, err := setup(source, fileName)
52
-
if err != nil {
53
-
return err
54
-
}
55
-
return basicFormatter.Format(writer, style, iter)
56
-
}
57
-
58
// Convert formats code with line numbers, links, etc.
59
-
func (c code) Convert(source []byte, fileName string, writer io.Writer) error {
60
iter, style, err := setup(source, fileName)
61
if err != nil {
62
return err
63
}
64
-
return Formatter.Format(writer, style, iter)
65
}
66
67
// Snippet formats code with line numbers starting at a specific line
···
2
3
import (
4
"io"
5
+
"path/filepath"
6
7
"github.com/alecthomas/chroma/v2"
8
"github.com/alecthomas/chroma/v2/formatters/html"
···
10
"github.com/alecthomas/chroma/v2/styles"
11
)
12
13
+
var customReg = map[string]string{
14
+
".hujson": "json",
15
+
}
16
+
17
+
// Options are the default set of formatting options
18
+
func Options(linePrefix string) []html.Option {
19
+
return []html.Option{
20
html.WithLineNumbers(true),
21
+
html.WithLinkableLineNumbers(true, linePrefix),
22
html.WithClasses(true),
23
html.LineNumbersInTable(true),
24
+
}
25
+
}
26
27
func setup(source []byte, fileName string) (chroma.Iterator, *chroma.Style, error) {
28
lexer := lexers.Match(fileName)
29
if lexer == nil {
30
lexer = lexers.Fallback
31
+
if name, ok := customReg[filepath.Ext(fileName)]; ok {
32
+
lexer = lexers.Get(name)
33
+
}
34
}
35
lexer = chroma.Coalesce(lexer)
36
···
47
return iter, style, nil
48
}
49
50
// Convert formats code with line numbers, links, etc.
51
+
func Convert(source []byte, fileName, linePrefix string, writer io.Writer) error {
52
iter, style, err := setup(source, fileName)
53
if err != nil {
54
return err
55
}
56
+
return html.New(Options(linePrefix)...).Format(writer, style, iter)
57
}
58
59
// Snippet formats code with line numbers starting at a specific line
+1
internal/html/markup/markdown.go
+1
internal/html/markup/markdown.go
+4
-3
internal/html/readme.templ
+4
-3
internal/html/readme.templ
+19
-14
internal/html/readme_templ.go
+19
-14
internal/html/readme_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
type ReadmeComponentContext struct {
14
Markdown string
15
}
16
17
func readmeComponent(rcc ReadmeComponentContext) templ.Component {
18
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
19
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
20
if !templ_7745c5c3_IsBuffer {
21
-
templ_7745c5c3_Buffer = templ.GetBuffer()
22
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
23
}
24
ctx = templ.InitializeContext(ctx)
25
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
28
}
29
ctx = templ.ClearChildren(ctx)
30
if rcc.Markdown != "" {
31
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-base dark:bg-base/50 p-5 mt-5 rounded markdown\">")
32
if templ_7745c5c3_Err != nil {
33
return templ_7745c5c3_Err
34
}
···
36
if templ_7745c5c3_Err != nil {
37
return templ_7745c5c3_Err
38
}
39
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
40
if templ_7745c5c3_Err != nil {
41
return templ_7745c5c3_Err
42
}
43
}
44
-
if !templ_7745c5c3_IsBuffer {
45
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
46
-
}
47
-
return templ_7745c5c3_Err
48
})
49
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
type ReadmeComponentContext struct {
12
Markdown string
13
}
14
15
func readmeComponent(rcc ReadmeComponentContext) templ.Component {
16
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
17
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
18
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
19
+
return templ_7745c5c3_CtxErr
20
+
}
21
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
22
if !templ_7745c5c3_IsBuffer {
23
+
defer func() {
24
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
25
+
if templ_7745c5c3_Err == nil {
26
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
27
+
}
28
+
}()
29
}
30
ctx = templ.InitializeContext(ctx)
31
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
34
}
35
ctx = templ.ClearChildren(ctx)
36
if rcc.Markdown != "" {
37
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"bg-base dark:bg-base/50 p-5 mt-5 rounded markdown\">")
38
if templ_7745c5c3_Err != nil {
39
return templ_7745c5c3_Err
40
}
···
42
if templ_7745c5c3_Err != nil {
43
return templ_7745c5c3_Err
44
}
45
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div>")
46
if templ_7745c5c3_Err != nil {
47
return templ_7745c5c3_Err
48
}
49
}
50
+
return nil
51
})
52
}
53
+
54
+
var _ = templruntime.GeneratedTemplate
+16
-8
internal/html/repo_commit.templ
+16
-8
internal/html/repo_commit.templ
···
4
import "github.com/dustin/go-humanize"
5
import "go.jolheiser.com/ugit/internal/git"
6
7
-
type RepoCommitContext struct{
8
-
BaseContext
9
-
RepoHeaderComponentContext
10
-
Commit git.Commit
11
}
12
13
templ RepoCommit(rcc RepoCommitContext) {
···
25
<div>{ rcc.Commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)) }>{ fmt.Sprintf("<%s>", rcc.Commit.Email) }</a></div>
26
<div title={ rcc.Commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(rcc.Commit.When) }</div>
27
</div>
28
-
<div class="text-text mt-5">{ fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions) }</div>
29
for _, file := range rcc.Commit.Files {
30
-
<div class="text-text mt-5">
31
<span class="text-text/80" title={ file.Action }>{ string(file.Action[0]) }</span>
32
{ " " }
33
if file.From.Path != "" {
···
40
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)) }>{ file.To.Path }</a>
41
}
42
</div>
43
-
<div class="whitespace-pre code">@templ.Raw(file.Patch)</div>
44
}
45
}
46
}
47
-
···
4
import "github.com/dustin/go-humanize"
5
import "go.jolheiser.com/ugit/internal/git"
6
7
+
type RepoCommitContext struct {
8
+
BaseContext
9
+
RepoHeaderComponentContext
10
+
Commit git.Commit
11
}
12
13
templ RepoCommit(rcc RepoCommitContext) {
···
25
<div>{ rcc.Commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)) }>{ fmt.Sprintf("<%s>", rcc.Commit.Email) }</a></div>
26
<div title={ rcc.Commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(rcc.Commit.When) }</div>
27
</div>
28
+
<details class="text-text mt-5">
29
+
<summary class="cursor-pointer">{ fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions) }</summary>
30
+
<div class="p-3 bg-base rounded">
31
+
for _, file := range rcc.Commit.Files {
32
+
<a class="block underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ "#" + file.Path() }>{ file.Path() }</a>
33
+
}
34
+
</div>
35
+
</details>
36
for _, file := range rcc.Commit.Files {
37
+
<div class="text-text mt-5" id={ file.Path() }>
38
<span class="text-text/80" title={ file.Action }>{ string(file.Action[0]) }</span>
39
{ " " }
40
if file.From.Path != "" {
···
47
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)) }>{ file.To.Path }</a>
48
}
49
</div>
50
+
<div class="code">
51
+
@templ.Raw(file.Patch)
52
+
</div>
53
}
54
}
55
}
+162
-81
internal/html/repo_commit_templ.go
+162
-81
internal/html/repo_commit_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import "fmt"
14
import "github.com/dustin/go-humanize"
···
21
}
22
23
func RepoCommit(rcc RepoCommitContext) templ.Component {
24
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
25
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
26
if !templ_7745c5c3_IsBuffer {
27
-
templ_7745c5c3_Buffer = templ.GetBuffer()
28
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
29
}
30
ctx = templ.InitializeContext(ctx)
31
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
33
templ_7745c5c3_Var1 = templ.NopComponent
34
}
35
ctx = templ.ClearChildren(ctx)
36
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
37
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
38
if !templ_7745c5c3_IsBuffer {
39
-
templ_7745c5c3_Buffer = templ.GetBuffer()
40
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
41
}
42
templ_7745c5c3_Err = repoHeaderComponent(rcc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
43
if templ_7745c5c3_Err != nil {
44
return templ_7745c5c3_Err
45
}
46
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
47
if templ_7745c5c3_Err != nil {
48
return templ_7745c5c3_Err
49
}
50
-
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
51
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
52
if templ_7745c5c3_Err != nil {
53
return templ_7745c5c3_Err
54
}
55
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
56
if templ_7745c5c3_Err != nil {
57
return templ_7745c5c3_Err
58
}
···
65
if templ_7745c5c3_Err != nil {
66
return templ_7745c5c3_Err
67
}
68
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
69
if templ_7745c5c3_Err != nil {
70
return templ_7745c5c3_Err
71
}
72
-
var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
73
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5)))
74
if templ_7745c5c3_Err != nil {
75
return templ_7745c5c3_Err
76
}
77
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a>")
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
···
87
if templ_7745c5c3_Err != nil {
88
return templ_7745c5c3_Err
89
}
90
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
91
if templ_7745c5c3_Err != nil {
92
return templ_7745c5c3_Err
93
}
94
-
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
95
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
96
if templ_7745c5c3_Err != nil {
97
return templ_7745c5c3_Err
98
}
99
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">patch</a></div><div class=\"text-text whitespace-pre mt-5 p-3 bg-base rounded\">")
100
if templ_7745c5c3_Err != nil {
101
return templ_7745c5c3_Err
102
}
···
109
if templ_7745c5c3_Err != nil {
110
return templ_7745c5c3_Err
111
}
112
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
113
if templ_7745c5c3_Err != nil {
114
return templ_7745c5c3_Err
115
}
116
if rcc.Commit.Signature != "" {
117
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><div class=\"p-3 bg-base rounded\"><code>")
118
if templ_7745c5c3_Err != nil {
119
return templ_7745c5c3_Err
120
}
···
127
if templ_7745c5c3_Err != nil {
128
return templ_7745c5c3_Err
129
}
130
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></div></details>")
131
if templ_7745c5c3_Err != nil {
132
return templ_7745c5c3_Err
133
}
134
}
135
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"text-text mt-3\"><div>")
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
···
154
if templ_7745c5c3_Err != nil {
155
return templ_7745c5c3_Err
156
}
157
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
158
if templ_7745c5c3_Err != nil {
159
return templ_7745c5c3_Err
160
}
161
-
var templ_7745c5c3_Var12 templ.SafeURL = templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email))
162
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var12)))
163
if templ_7745c5c3_Err != nil {
164
return templ_7745c5c3_Err
165
}
166
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
167
if templ_7745c5c3_Err != nil {
168
return templ_7745c5c3_Err
169
}
···
176
if templ_7745c5c3_Err != nil {
177
return templ_7745c5c3_Err
178
}
179
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"")
180
if templ_7745c5c3_Err != nil {
181
return templ_7745c5c3_Err
182
}
···
189
if templ_7745c5c3_Err != nil {
190
return templ_7745c5c3_Err
191
}
192
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
193
if templ_7745c5c3_Err != nil {
194
return templ_7745c5c3_Err
195
}
···
202
if templ_7745c5c3_Err != nil {
203
return templ_7745c5c3_Err
204
}
205
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"text-text mt-5\">")
206
if templ_7745c5c3_Err != nil {
207
return templ_7745c5c3_Err
208
}
209
var templ_7745c5c3_Var16 string
210
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions))
211
if templ_7745c5c3_Err != nil {
212
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 28, Col: 179}
213
}
214
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
215
if templ_7745c5c3_Err != nil {
216
return templ_7745c5c3_Err
217
}
218
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
219
if templ_7745c5c3_Err != nil {
220
return templ_7745c5c3_Err
221
}
222
for _, file := range rcc.Commit.Files {
223
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5\"><span class=\"text-text/80\" title=\"")
224
if templ_7745c5c3_Err != nil {
225
return templ_7745c5c3_Err
226
}
227
-
var templ_7745c5c3_Var17 string
228
-
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action)
229
if templ_7745c5c3_Err != nil {
230
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 50}
231
}
232
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
233
if templ_7745c5c3_Err != nil {
234
return templ_7745c5c3_Err
235
}
236
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
237
if templ_7745c5c3_Err != nil {
238
return templ_7745c5c3_Err
239
}
240
var templ_7745c5c3_Var18 string
241
-
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0]))
242
if templ_7745c5c3_Err != nil {
243
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 77}
244
}
245
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
246
if templ_7745c5c3_Err != nil {
247
return templ_7745c5c3_Err
248
}
249
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ")
250
if templ_7745c5c3_Err != nil {
251
return templ_7745c5c3_Err
252
}
253
var templ_7745c5c3_Var19 string
254
-
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
255
if templ_7745c5c3_Err != nil {
256
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 9}
257
}
258
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
259
if templ_7745c5c3_Err != nil {
260
return templ_7745c5c3_Err
261
}
262
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
263
if templ_7745c5c3_Err != nil {
264
return templ_7745c5c3_Err
265
}
266
if file.From.Path != "" {
267
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
268
if templ_7745c5c3_Err != nil {
269
return templ_7745c5c3_Err
270
}
271
-
var templ_7745c5c3_Var20 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path))
272
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var20)))
273
if templ_7745c5c3_Err != nil {
274
return templ_7745c5c3_Err
275
}
276
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
277
if templ_7745c5c3_Err != nil {
278
return templ_7745c5c3_Err
279
}
280
-
var templ_7745c5c3_Var21 string
281
-
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path)
282
if templ_7745c5c3_Err != nil {
283
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 34, Col: 227}
284
}
285
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
286
if templ_7745c5c3_Err != nil {
287
return templ_7745c5c3_Err
288
}
289
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
290
if templ_7745c5c3_Err != nil {
291
return templ_7745c5c3_Err
292
}
293
}
294
if file.From.Path != "" && file.To.Path != "" {
295
-
var templ_7745c5c3_Var22 string
296
-
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ")
297
if templ_7745c5c3_Err != nil {
298
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 13}
299
}
300
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
301
if templ_7745c5c3_Err != nil {
302
return templ_7745c5c3_Err
303
}
304
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
305
if templ_7745c5c3_Err != nil {
306
return templ_7745c5c3_Err
307
}
308
}
309
if file.To.Path != "" {
310
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
311
if templ_7745c5c3_Err != nil {
312
return templ_7745c5c3_Err
313
}
314
-
var templ_7745c5c3_Var23 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path))
315
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var23)))
316
if templ_7745c5c3_Err != nil {
317
return templ_7745c5c3_Err
318
}
319
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
320
if templ_7745c5c3_Err != nil {
321
return templ_7745c5c3_Err
322
}
323
-
var templ_7745c5c3_Var24 string
324
-
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path)
325
if templ_7745c5c3_Err != nil {
326
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 40, Col: 221}
327
}
328
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
329
if templ_7745c5c3_Err != nil {
330
return templ_7745c5c3_Err
331
}
332
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
333
if templ_7745c5c3_Err != nil {
334
return templ_7745c5c3_Err
335
}
336
}
337
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"whitespace-pre code\">")
338
if templ_7745c5c3_Err != nil {
339
return templ_7745c5c3_Err
340
}
···
342
if templ_7745c5c3_Err != nil {
343
return templ_7745c5c3_Err
344
}
345
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
346
if templ_7745c5c3_Err != nil {
347
return templ_7745c5c3_Err
348
}
349
}
350
-
if !templ_7745c5c3_IsBuffer {
351
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
352
-
}
353
-
return templ_7745c5c3_Err
354
})
355
templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
356
if templ_7745c5c3_Err != nil {
357
return templ_7745c5c3_Err
358
}
359
-
if !templ_7745c5c3_IsBuffer {
360
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
361
-
}
362
-
return templ_7745c5c3_Err
363
})
364
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import "fmt"
12
import "github.com/dustin/go-humanize"
···
19
}
20
21
func RepoCommit(rcc RepoCommitContext) templ.Component {
22
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
23
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
24
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
25
+
return templ_7745c5c3_CtxErr
26
+
}
27
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
28
if !templ_7745c5c3_IsBuffer {
29
+
defer func() {
30
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
31
+
if templ_7745c5c3_Err == nil {
32
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
33
+
}
34
+
}()
35
}
36
ctx = templ.InitializeContext(ctx)
37
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
39
templ_7745c5c3_Var1 = templ.NopComponent
40
}
41
ctx = templ.ClearChildren(ctx)
42
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
43
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
44
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
45
if !templ_7745c5c3_IsBuffer {
46
+
defer func() {
47
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
48
+
if templ_7745c5c3_Err == nil {
49
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
50
+
}
51
+
}()
52
}
53
+
ctx = templ.InitializeContext(ctx)
54
templ_7745c5c3_Err = repoHeaderComponent(rcc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
55
if templ_7745c5c3_Err != nil {
56
return templ_7745c5c3_Err
57
}
58
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
59
if templ_7745c5c3_Err != nil {
60
return templ_7745c5c3_Err
61
}
62
+
var templ_7745c5c3_Var3 templ.SafeURL
63
+
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)))
64
+
if templ_7745c5c3_Err != nil {
65
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 213}
66
+
}
67
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
68
if templ_7745c5c3_Err != nil {
69
return templ_7745c5c3_Err
70
}
71
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">tree</a>")
72
if templ_7745c5c3_Err != nil {
73
return templ_7745c5c3_Err
74
}
···
81
if templ_7745c5c3_Err != nil {
82
return templ_7745c5c3_Err
83
}
84
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
85
if templ_7745c5c3_Err != nil {
86
return templ_7745c5c3_Err
87
}
88
+
var templ_7745c5c3_Var5 templ.SafeURL
89
+
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)))
90
+
if templ_7745c5c3_Err != nil {
91
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 412}
92
+
}
93
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
94
if templ_7745c5c3_Err != nil {
95
return templ_7745c5c3_Err
96
}
97
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\">log</a>")
98
if templ_7745c5c3_Err != nil {
99
return templ_7745c5c3_Err
100
}
···
107
if templ_7745c5c3_Err != nil {
108
return templ_7745c5c3_Err
109
}
110
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
111
if templ_7745c5c3_Err != nil {
112
return templ_7745c5c3_Err
113
}
114
+
var templ_7745c5c3_Var7 templ.SafeURL
115
+
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)))
116
+
if templ_7745c5c3_Err != nil {
117
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 619}
118
+
}
119
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
120
if templ_7745c5c3_Err != nil {
121
return templ_7745c5c3_Err
122
}
123
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">patch</a></div><div class=\"text-text whitespace-pre mt-5 p-3 bg-base rounded\">")
124
if templ_7745c5c3_Err != nil {
125
return templ_7745c5c3_Err
126
}
···
133
if templ_7745c5c3_Err != nil {
134
return templ_7745c5c3_Err
135
}
136
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>")
137
if templ_7745c5c3_Err != nil {
138
return templ_7745c5c3_Err
139
}
140
if rcc.Commit.Signature != "" {
141
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<details class=\"text-text whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><div class=\"p-3 bg-base rounded\"><code>")
142
if templ_7745c5c3_Err != nil {
143
return templ_7745c5c3_Err
144
}
···
151
if templ_7745c5c3_Err != nil {
152
return templ_7745c5c3_Err
153
}
154
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</code></div></details>")
155
if templ_7745c5c3_Err != nil {
156
return templ_7745c5c3_Err
157
}
158
}
159
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " <div class=\"text-text mt-3\"><div>")
160
if templ_7745c5c3_Err != nil {
161
return templ_7745c5c3_Err
162
}
···
178
if templ_7745c5c3_Err != nil {
179
return templ_7745c5c3_Err
180
}
181
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
182
if templ_7745c5c3_Err != nil {
183
return templ_7745c5c3_Err
184
}
185
+
var templ_7745c5c3_Var12 templ.SafeURL
186
+
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)))
187
+
if templ_7745c5c3_Err != nil {
188
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 181}
189
+
}
190
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
191
if templ_7745c5c3_Err != nil {
192
return templ_7745c5c3_Err
193
}
194
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">")
195
if templ_7745c5c3_Err != nil {
196
return templ_7745c5c3_Err
197
}
···
204
if templ_7745c5c3_Err != nil {
205
return templ_7745c5c3_Err
206
}
207
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</a></div><div title=\"")
208
if templ_7745c5c3_Err != nil {
209
return templ_7745c5c3_Err
210
}
···
217
if templ_7745c5c3_Err != nil {
218
return templ_7745c5c3_Err
219
}
220
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\">")
221
if templ_7745c5c3_Err != nil {
222
return templ_7745c5c3_Err
223
}
···
230
if templ_7745c5c3_Err != nil {
231
return templ_7745c5c3_Err
232
}
233
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></div><details class=\"text-text mt-5\"><summary class=\"cursor-pointer\">")
234
if templ_7745c5c3_Err != nil {
235
return templ_7745c5c3_Err
236
}
237
var templ_7745c5c3_Var16 string
238
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions))
239
if templ_7745c5c3_Err != nil {
240
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 29, Col: 184}
241
}
242
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
243
if templ_7745c5c3_Err != nil {
244
return templ_7745c5c3_Err
245
}
246
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</summary><div class=\"p-3 bg-base rounded\">")
247
if templ_7745c5c3_Err != nil {
248
return templ_7745c5c3_Err
249
}
250
for _, file := range rcc.Commit.Files {
251
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<a class=\"block underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
252
if templ_7745c5c3_Err != nil {
253
return templ_7745c5c3_Err
254
}
255
+
var templ_7745c5c3_Var17 templ.SafeURL
256
+
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs("#" + file.Path())
257
if templ_7745c5c3_Err != nil {
258
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 116}
259
}
260
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
261
if templ_7745c5c3_Err != nil {
262
return templ_7745c5c3_Err
263
}
264
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">")
265
if templ_7745c5c3_Err != nil {
266
return templ_7745c5c3_Err
267
}
268
var templ_7745c5c3_Var18 string
269
+
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path())
270
if templ_7745c5c3_Err != nil {
271
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 132}
272
}
273
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
274
if templ_7745c5c3_Err != nil {
275
return templ_7745c5c3_Err
276
}
277
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</a>")
278
+
if templ_7745c5c3_Err != nil {
279
+
return templ_7745c5c3_Err
280
+
}
281
+
}
282
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div></details> ")
283
+
if templ_7745c5c3_Err != nil {
284
+
return templ_7745c5c3_Err
285
+
}
286
+
for _, file := range rcc.Commit.Files {
287
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<div class=\"text-text mt-5\" id=\"")
288
if templ_7745c5c3_Err != nil {
289
return templ_7745c5c3_Err
290
}
291
var templ_7745c5c3_Var19 string
292
+
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path())
293
if templ_7745c5c3_Err != nil {
294
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 47}
295
}
296
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
297
if templ_7745c5c3_Err != nil {
298
return templ_7745c5c3_Err
299
}
300
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\"><span class=\"text-text/80\" title=\"")
301
+
if templ_7745c5c3_Err != nil {
302
+
return templ_7745c5c3_Err
303
+
}
304
+
var templ_7745c5c3_Var20 string
305
+
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action)
306
+
if templ_7745c5c3_Err != nil {
307
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 50}
308
+
}
309
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
310
+
if templ_7745c5c3_Err != nil {
311
+
return templ_7745c5c3_Err
312
+
}
313
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\">")
314
+
if templ_7745c5c3_Err != nil {
315
+
return templ_7745c5c3_Err
316
+
}
317
+
var templ_7745c5c3_Var21 string
318
+
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0]))
319
+
if templ_7745c5c3_Err != nil {
320
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 77}
321
+
}
322
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
323
+
if templ_7745c5c3_Err != nil {
324
+
return templ_7745c5c3_Err
325
+
}
326
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</span> ")
327
+
if templ_7745c5c3_Err != nil {
328
+
return templ_7745c5c3_Err
329
+
}
330
+
var templ_7745c5c3_Var22 string
331
+
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
332
+
if templ_7745c5c3_Err != nil {
333
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 39, Col: 9}
334
+
}
335
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
336
+
if templ_7745c5c3_Err != nil {
337
+
return templ_7745c5c3_Err
338
+
}
339
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ")
340
if templ_7745c5c3_Err != nil {
341
return templ_7745c5c3_Err
342
}
343
if file.From.Path != "" {
344
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
345
if templ_7745c5c3_Err != nil {
346
return templ_7745c5c3_Err
347
}
348
+
var templ_7745c5c3_Var23 templ.SafeURL
349
+
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)))
350
+
if templ_7745c5c3_Err != nil {
351
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 208}
352
+
}
353
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
354
if templ_7745c5c3_Err != nil {
355
return templ_7745c5c3_Err
356
}
357
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">")
358
if templ_7745c5c3_Err != nil {
359
return templ_7745c5c3_Err
360
}
361
+
var templ_7745c5c3_Var24 string
362
+
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path)
363
if templ_7745c5c3_Err != nil {
364
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 227}
365
}
366
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
367
if templ_7745c5c3_Err != nil {
368
return templ_7745c5c3_Err
369
}
370
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a> ")
371
if templ_7745c5c3_Err != nil {
372
return templ_7745c5c3_Err
373
}
374
}
375
if file.From.Path != "" && file.To.Path != "" {
376
+
var templ_7745c5c3_Var25 string
377
+
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ")
378
if templ_7745c5c3_Err != nil {
379
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 44, Col: 13}
380
}
381
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
382
if templ_7745c5c3_Err != nil {
383
return templ_7745c5c3_Err
384
}
385
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ")
386
if templ_7745c5c3_Err != nil {
387
return templ_7745c5c3_Err
388
}
389
}
390
if file.To.Path != "" {
391
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
392
if templ_7745c5c3_Err != nil {
393
return templ_7745c5c3_Err
394
}
395
+
var templ_7745c5c3_Var26 templ.SafeURL
396
+
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)))
397
+
if templ_7745c5c3_Err != nil {
398
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 204}
399
+
}
400
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
401
if templ_7745c5c3_Err != nil {
402
return templ_7745c5c3_Err
403
}
404
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\">")
405
if templ_7745c5c3_Err != nil {
406
return templ_7745c5c3_Err
407
}
408
+
var templ_7745c5c3_Var27 string
409
+
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path)
410
if templ_7745c5c3_Err != nil {
411
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 221}
412
}
413
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
414
if templ_7745c5c3_Err != nil {
415
return templ_7745c5c3_Err
416
}
417
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</a>")
418
if templ_7745c5c3_Err != nil {
419
return templ_7745c5c3_Err
420
}
421
}
422
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</div><div class=\"code\">")
423
if templ_7745c5c3_Err != nil {
424
return templ_7745c5c3_Err
425
}
···
427
if templ_7745c5c3_Err != nil {
428
return templ_7745c5c3_Err
429
}
430
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div>")
431
if templ_7745c5c3_Err != nil {
432
return templ_7745c5c3_Err
433
}
434
}
435
+
return nil
436
})
437
templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
438
if templ_7745c5c3_Err != nil {
439
return templ_7745c5c3_Err
440
}
441
+
return nil
442
})
443
}
444
+
445
+
var _ = templruntime.GeneratedTemplate
+42
-5
internal/html/repo_file.templ
+42
-5
internal/html/repo_file.templ
···
1
package html
2
3
type RepoFileContext struct {
4
BaseContext
5
RepoHeaderComponentContext
6
RepoBreadcrumbComponentContext
7
-
Code string
8
}
9
10
templ RepoFile(rfc RepoFileContext) {
···
14
@repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext)
15
{ " - " }
16
<a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a>
17
-
<div class="code">
18
@templ.Raw(rfc.Code)
19
</div>
20
</div>
21
}
···
23
const lineRe = /#L(\d+)(?:-L(\d+))?/g
24
const $lineLines = document.querySelectorAll(".chroma .lntable .lnt");
25
const $codeLines = document.querySelectorAll(".chroma .lntable .line");
26
let start = 0;
27
let end = 0;
28
···
31
start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;
32
end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;
33
}
34
-
if (start != 0) {
35
deactivateLines();
36
activateLines(start, end);
37
}
38
39
for (let line of $lineLines) {
···
45
if (event.shiftKey) {
46
end = n;
47
anchor = `#L${start}-L${end}`;
48
} else {
49
start = n;
50
end = 0;
51
anchor = `#L${start}`;
52
}
53
-
history.replaceState(null, null, anchor);
54
-
activateLines(start, end);
55
});
56
}
57
58
function activateLines(start, end) {
59
if (end < start) end = start;
···
1
package html
2
3
+
import "fmt"
4
+
5
type RepoFileContext struct {
6
BaseContext
7
RepoHeaderComponentContext
8
RepoBreadcrumbComponentContext
9
+
Code string
10
+
Commit string
11
+
Path string
12
+
}
13
+
14
+
func (rfc RepoFileContext) Permalink() string {
15
+
return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path)
16
}
17
18
templ RepoFile(rfc RepoFileContext) {
···
22
@repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext)
23
{ " - " }
24
<a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a>
25
+
{ " - " }
26
+
<a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" id="permalink" data-permalink={ rfc.Permalink() } href={ rfc.Permalink() }>permalink</a>
27
+
<div class="code relative">
28
@templ.Raw(rfc.Code)
29
+
<button id="copy" class="absolute top-0 right-0 rounded bg-base hover:bg-surface0"></button>
30
</div>
31
</div>
32
}
···
34
const lineRe = /#L(\d+)(?:-L(\d+))?/g
35
const $lineLines = document.querySelectorAll(".chroma .lntable .lnt");
36
const $codeLines = document.querySelectorAll(".chroma .lntable .line");
37
+
const $copyButton = document.getElementById('copy');
38
+
const $permalink = document.getElementById('permalink');
39
+
const $copyIcon = "๐";
40
+
const $copiedIcon = "โ
";
41
+
let $code = ""
42
+
for (let codeLine of $codeLines) $code += codeLine.innerText;
43
let start = 0;
44
let end = 0;
45
···
48
start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;
49
end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;
50
}
51
+
if (start !== 0) {
52
deactivateLines();
53
activateLines(start, end);
54
+
let anchor = `#${start}`;
55
+
if (end !== 0) anchor += `-${end}`;
56
+
if (anchor !== "") $permalink.href = $permalink.dataset.permalink + anchor;
57
+
$lineLines[start-1].scrollIntoView(true);
58
}
59
60
for (let line of $lineLines) {
···
66
if (event.shiftKey) {
67
end = n;
68
anchor = `#L${start}-L${end}`;
69
+
} else if (start === n) {
70
+
start = 0;
71
+
end = 0;
72
} else {
73
start = n;
74
end = 0;
75
anchor = `#L${start}`;
76
}
77
+
history.replaceState(null, null, window.location.pathname + anchor);
78
+
$permalink.href = $permalink.dataset.permalink + anchor;
79
+
if (start !== 0) activateLines(start, end);
80
});
81
}
82
+
83
+
if (navigator.clipboard && navigator.clipboard.writeText) {
84
+
$copyButton.innerText = $copyIcon;
85
+
$copyButton.classList.remove("hidden");
86
+
}
87
+
$copyButton.addEventListener("click", () => {
88
+
navigator.clipboard.writeText($code);
89
+
$copyButton.innerText = $copiedIcon;
90
+
setTimeout(() => {
91
+
$copyButton.innerText = $copyIcon;
92
+
}, 1000);
93
+
});
94
95
function activateLines(start, end) {
96
if (end < start) end = start;
+81
-26
internal/html/repo_file_templ.go
+81
-26
internal/html/repo_file_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
type RepoFileContext struct {
14
BaseContext
15
RepoHeaderComponentContext
16
RepoBreadcrumbComponentContext
17
-
Code string
18
}
19
20
func RepoFile(rfc RepoFileContext) templ.Component {
21
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
22
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
23
if !templ_7745c5c3_IsBuffer {
24
-
templ_7745c5c3_Buffer = templ.GetBuffer()
25
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
26
}
27
ctx = templ.InitializeContext(ctx)
28
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
30
templ_7745c5c3_Var1 = templ.NopComponent
31
}
32
ctx = templ.ClearChildren(ctx)
33
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
34
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
35
if !templ_7745c5c3_IsBuffer {
36
-
templ_7745c5c3_Buffer = templ.GetBuffer()
37
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
38
}
39
templ_7745c5c3_Err = repoHeaderComponent(rfc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
40
if templ_7745c5c3_Err != nil {
41
return templ_7745c5c3_Err
42
}
43
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"mt-2 text-text\">")
44
if templ_7745c5c3_Err != nil {
45
return templ_7745c5c3_Err
46
}
···
51
var templ_7745c5c3_Var3 string
52
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
53
if templ_7745c5c3_Err != nil {
54
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 15, Col: 10}
55
}
56
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
57
if templ_7745c5c3_Err != nil {
58
return templ_7745c5c3_Err
59
}
60
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">raw</a><div class=\"code\">")
61
if templ_7745c5c3_Err != nil {
62
return templ_7745c5c3_Err
63
}
64
-
templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer)
65
if templ_7745c5c3_Err != nil {
66
return templ_7745c5c3_Err
67
}
68
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
69
if templ_7745c5c3_Err != nil {
70
return templ_7745c5c3_Err
71
}
72
-
if !templ_7745c5c3_IsBuffer {
73
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
74
}
75
-
return templ_7745c5c3_Err
76
})
77
templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
81
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>\n\t\tconst lineRe = /#L(\\d+)(?:-L(\\d+))?/g\n\t\tconst $lineLines = document.querySelectorAll(\".chroma .lntable .lnt\");\n\t\tconst $codeLines = document.querySelectorAll(\".chroma .lntable .line\");\n\t\tlet start = 0;\n\t\tlet end = 0;\n\n\t\tconst results = [...location.hash.matchAll(lineRe)];\t\t\n\t\tif (0 in results) {\n\t\t\tstart = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;\n\t\t\tend = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;\n\t\t}\n\t\tif (start != 0) {\n\t\t\tdeactivateLines();\n\t\t\tactivateLines(start, end);\n\t\t}\n\n\t\tfor (let line of $lineLines) {\n\t\t\tline.addEventListener(\"click\", (event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdeactivateLines();\n\t\t\t\tconst n = parseInt(line.id.substring(1));\n\t\t\t\tlet anchor = \"\";\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tend = n;\n\t\t\t\t\tanchor = `#L${start}-L${end}`;\n\t\t\t\t} else {\n\t\t\t\t\tstart = n;\n\t\t\t\t\tend = 0;\n\t\t\t\t\tanchor = `#L${start}`;\n\t\t\t\t}\n\t\t\t\thistory.replaceState(null, null, anchor);\n\t\t\t\tactivateLines(start, end);\n\t\t\t});\n\t\t}\n\n\t\tfunction activateLines(start, end) {\n\t\t\tif (end < start) end = start;\n\t\t\tfor (let idx = start - 1; idx < end; idx++) {\n\t\t\t\t$codeLines[idx].classList.add(\"active\");\n\t\t\t}\n\t\t}\n\n\t\tfunction deactivateLines() {\n\t\t\tfor (let code of $codeLines) {\n\t\t\t\tcode.classList.remove(\"active\");\n\t\t\t}\n\t\t}\n\n\t\t\n\t\t\n\t</script>")
82
if templ_7745c5c3_Err != nil {
83
return templ_7745c5c3_Err
84
}
85
-
if !templ_7745c5c3_IsBuffer {
86
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
87
-
}
88
-
return templ_7745c5c3_Err
89
})
90
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
+
11
+
import "fmt"
12
13
type RepoFileContext struct {
14
BaseContext
15
RepoHeaderComponentContext
16
RepoBreadcrumbComponentContext
17
+
Code string
18
+
Commit string
19
+
Path string
20
+
}
21
+
22
+
func (rfc RepoFileContext) Permalink() string {
23
+
return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path)
24
}
25
26
func RepoFile(rfc RepoFileContext) templ.Component {
27
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
28
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
29
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
30
+
return templ_7745c5c3_CtxErr
31
+
}
32
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
33
if !templ_7745c5c3_IsBuffer {
34
+
defer func() {
35
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
36
+
if templ_7745c5c3_Err == nil {
37
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
38
+
}
39
+
}()
40
}
41
ctx = templ.InitializeContext(ctx)
42
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
44
templ_7745c5c3_Var1 = templ.NopComponent
45
}
46
ctx = templ.ClearChildren(ctx)
47
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
48
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
49
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
50
if !templ_7745c5c3_IsBuffer {
51
+
defer func() {
52
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
53
+
if templ_7745c5c3_Err == nil {
54
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
55
+
}
56
+
}()
57
}
58
+
ctx = templ.InitializeContext(ctx)
59
templ_7745c5c3_Err = repoHeaderComponent(rfc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
60
if templ_7745c5c3_Err != nil {
61
return templ_7745c5c3_Err
62
}
63
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"mt-2 text-text\">")
64
if templ_7745c5c3_Err != nil {
65
return templ_7745c5c3_Err
66
}
···
71
var templ_7745c5c3_Var3 string
72
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
73
if templ_7745c5c3_Err != nil {
74
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 23, Col: 10}
75
}
76
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
77
if templ_7745c5c3_Err != nil {
78
return templ_7745c5c3_Err
79
}
80
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">raw</a> ")
81
+
if templ_7745c5c3_Err != nil {
82
+
return templ_7745c5c3_Err
83
+
}
84
+
var templ_7745c5c3_Var4 string
85
+
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
86
+
if templ_7745c5c3_Err != nil {
87
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 25, Col: 10}
88
+
}
89
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
90
+
if templ_7745c5c3_Err != nil {
91
+
return templ_7745c5c3_Err
92
+
}
93
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" id=\"permalink\" data-permalink=\"")
94
+
if templ_7745c5c3_Err != nil {
95
+
return templ_7745c5c3_Err
96
+
}
97
+
var templ_7745c5c3_Var5 string
98
+
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(rfc.Permalink())
99
+
if templ_7745c5c3_Err != nil {
100
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 26, Col: 141}
101
+
}
102
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
103
+
if templ_7745c5c3_Err != nil {
104
+
return templ_7745c5c3_Err
105
+
}
106
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" href=\"")
107
+
if templ_7745c5c3_Err != nil {
108
+
return templ_7745c5c3_Err
109
+
}
110
+
var templ_7745c5c3_Var6 templ.SafeURL
111
+
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(rfc.Permalink())
112
+
if templ_7745c5c3_Err != nil {
113
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 26, Col: 166}
114
+
}
115
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
116
if templ_7745c5c3_Err != nil {
117
return templ_7745c5c3_Err
118
}
119
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">permalink</a><div class=\"code relative\">")
120
if templ_7745c5c3_Err != nil {
121
return templ_7745c5c3_Err
122
}
123
+
templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer)
124
if templ_7745c5c3_Err != nil {
125
return templ_7745c5c3_Err
126
}
127
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<button id=\"copy\" class=\"absolute top-0 right-0 rounded bg-base hover:bg-surface0\"></button></div></div>")
128
+
if templ_7745c5c3_Err != nil {
129
+
return templ_7745c5c3_Err
130
}
131
+
return nil
132
})
133
templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
134
if templ_7745c5c3_Err != nil {
135
return templ_7745c5c3_Err
136
}
137
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<script>\n\t\tconst lineRe = /#L(\\d+)(?:-L(\\d+))?/g\n\t\tconst $lineLines = document.querySelectorAll(\".chroma .lntable .lnt\");\n\t\tconst $codeLines = document.querySelectorAll(\".chroma .lntable .line\");\n\t\tconst $copyButton = document.getElementById('copy');\n\t\tconst $permalink = document.getElementById('permalink');\n\t\tconst $copyIcon = \"๐\";\n\t\tconst $copiedIcon = \"โ
\";\n\t\tlet $code = \"\"\n\t\tfor (let codeLine of $codeLines) $code += codeLine.innerText;\n\t\tlet start = 0;\n\t\tlet end = 0;\n\n\t\tconst results = [...location.hash.matchAll(lineRe)];\t\t\n\t\tif (0 in results) {\n\t\t\tstart = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;\n\t\t\tend = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;\n\t\t}\n\t\tif (start !== 0) {\n\t\t\tdeactivateLines();\n\t\t\tactivateLines(start, end);\n\t\t\tlet anchor = `#${start}`;\n if (end !== 0) anchor += `-${end}`;\n if (anchor !== \"\") $permalink.href = $permalink.dataset.permalink + anchor;\n\t\t\t$lineLines[start-1].scrollIntoView(true);\n\t\t}\n\n\t\tfor (let line of $lineLines) {\n\t\t\tline.addEventListener(\"click\", (event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdeactivateLines();\n\t\t\t\tconst n = parseInt(line.id.substring(1));\n\t\t\t\tlet anchor = \"\";\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tend = n;\n\t\t\t\t\tanchor = `#L${start}-L${end}`;\n\t\t\t\t} else if (start === n) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t\tend = 0;\n\t\t\t\t} else {\n\t\t\t\t\tstart = n;\n\t\t\t\t\tend = 0;\n\t\t\t\t\tanchor = `#L${start}`;\n\t\t\t\t}\n\t\t\t\thistory.replaceState(null, null, window.location.pathname + anchor);\n\t\t\t\t$permalink.href = $permalink.dataset.permalink + anchor;\n\t\t\t\tif (start !== 0) activateLines(start, end);\n\t\t\t});\n\t\t}\n\n\t\tif (navigator.clipboard && navigator.clipboard.writeText) {\n\t\t\t$copyButton.innerText = $copyIcon;\n\t\t\t$copyButton.classList.remove(\"hidden\");\n }\n\t\t$copyButton.addEventListener(\"click\", () => {\n navigator.clipboard.writeText($code);\n\t\t\t$copyButton.innerText = $copiedIcon;\n\t\t\tsetTimeout(() => {\n\t\t\t\t$copyButton.innerText = $copyIcon;\n\t\t\t}, 1000);\n });\n\n\t\tfunction activateLines(start, end) {\n\t\t\tif (end < start) end = start;\n\t\t\tfor (let idx = start - 1; idx < end; idx++) {\n\t\t\t\t$codeLines[idx].classList.add(\"active\");\n\t\t\t}\n\t\t}\n\n\t\tfunction deactivateLines() {\n\t\t\tfor (let code of $codeLines) {\n\t\t\t\tcode.classList.remove(\"active\");\n\t\t\t}\n\t\t}\n\n\t\t\n\t\t\n\t</script>")
138
if templ_7745c5c3_Err != nil {
139
return templ_7745c5c3_Err
140
}
141
+
return nil
142
})
143
}
144
+
145
+
var _ = templruntime.GeneratedTemplate
+3
-4
internal/html/repo_log.templ
+3
-4
internal/html/repo_log.templ
+54
-38
internal/html/repo_log_templ.go
+54
-38
internal/html/repo_log_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import "fmt"
14
import "github.com/dustin/go-humanize"
···
21
}
22
23
func RepoLog(rlc RepoLogContext) templ.Component {
24
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
25
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
26
if !templ_7745c5c3_IsBuffer {
27
-
templ_7745c5c3_Buffer = templ.GetBuffer()
28
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
29
}
30
ctx = templ.InitializeContext(ctx)
31
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
33
templ_7745c5c3_Var1 = templ.NopComponent
34
}
35
ctx = templ.ClearChildren(ctx)
36
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
37
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
38
if !templ_7745c5c3_IsBuffer {
39
-
templ_7745c5c3_Buffer = templ.GetBuffer()
40
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
41
}
42
templ_7745c5c3_Err = repoHeaderComponent(rlc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
43
if templ_7745c5c3_Err != nil {
44
return templ_7745c5c3_Err
45
}
46
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">")
47
if templ_7745c5c3_Err != nil {
48
return templ_7745c5c3_Err
49
}
50
for _, commit := range rlc.Commits {
51
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-5\"><div><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
52
if templ_7745c5c3_Err != nil {
53
return templ_7745c5c3_Err
54
}
55
-
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA))
56
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
57
if templ_7745c5c3_Err != nil {
58
return templ_7745c5c3_Err
59
}
60
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
61
if templ_7745c5c3_Err != nil {
62
return templ_7745c5c3_Err
63
}
···
70
if templ_7745c5c3_Err != nil {
71
return templ_7745c5c3_Err
72
}
73
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"whitespace-pre\">")
74
if templ_7745c5c3_Err != nil {
75
return templ_7745c5c3_Err
76
}
77
if commit.Details() != "" {
78
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details><summary class=\"cursor-pointer\">")
79
if templ_7745c5c3_Err != nil {
80
return templ_7745c5c3_Err
81
}
···
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary><div class=\"p-3 bg-base rounded\">")
92
if templ_7745c5c3_Err != nil {
93
return templ_7745c5c3_Err
94
}
···
101
if templ_7745c5c3_Err != nil {
102
return templ_7745c5c3_Err
103
}
104
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></details>")
105
if templ_7745c5c3_Err != nil {
106
return templ_7745c5c3_Err
107
}
···
116
return templ_7745c5c3_Err
117
}
118
}
119
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"sm:col-span-3 mb-4\"><div>")
120
if templ_7745c5c3_Err != nil {
121
return templ_7745c5c3_Err
122
}
···
138
if templ_7745c5c3_Err != nil {
139
return templ_7745c5c3_Err
140
}
141
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
142
if templ_7745c5c3_Err != nil {
143
return templ_7745c5c3_Err
144
}
145
-
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email))
146
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
147
if templ_7745c5c3_Err != nil {
148
return templ_7745c5c3_Err
149
}
150
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
151
if templ_7745c5c3_Err != nil {
152
return templ_7745c5c3_Err
153
}
···
160
if templ_7745c5c3_Err != nil {
161
return templ_7745c5c3_Err
162
}
163
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"")
164
if templ_7745c5c3_Err != nil {
165
return templ_7745c5c3_Err
166
}
···
173
if templ_7745c5c3_Err != nil {
174
return templ_7745c5c3_Err
175
}
176
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
177
if templ_7745c5c3_Err != nil {
178
return templ_7745c5c3_Err
179
}
···
186
if templ_7745c5c3_Err != nil {
187
return templ_7745c5c3_Err
188
}
189
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
190
if templ_7745c5c3_Err != nil {
191
return templ_7745c5c3_Err
192
}
193
}
194
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
195
if templ_7745c5c3_Err != nil {
196
return templ_7745c5c3_Err
197
}
198
-
if !templ_7745c5c3_IsBuffer {
199
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
200
-
}
201
-
return templ_7745c5c3_Err
202
})
203
templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
204
if templ_7745c5c3_Err != nil {
205
return templ_7745c5c3_Err
206
}
207
-
if !templ_7745c5c3_IsBuffer {
208
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
209
-
}
210
-
return templ_7745c5c3_Err
211
})
212
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import "fmt"
12
import "github.com/dustin/go-humanize"
···
19
}
20
21
func RepoLog(rlc RepoLogContext) templ.Component {
22
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
23
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
24
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
25
+
return templ_7745c5c3_CtxErr
26
+
}
27
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
28
if !templ_7745c5c3_IsBuffer {
29
+
defer func() {
30
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
31
+
if templ_7745c5c3_Err == nil {
32
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
33
+
}
34
+
}()
35
}
36
ctx = templ.InitializeContext(ctx)
37
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
39
templ_7745c5c3_Var1 = templ.NopComponent
40
}
41
ctx = templ.ClearChildren(ctx)
42
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
43
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
44
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
45
if !templ_7745c5c3_IsBuffer {
46
+
defer func() {
47
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
48
+
if templ_7745c5c3_Err == nil {
49
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
50
+
}
51
+
}()
52
}
53
+
ctx = templ.InitializeContext(ctx)
54
templ_7745c5c3_Err = repoHeaderComponent(rlc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
55
if templ_7745c5c3_Err != nil {
56
return templ_7745c5c3_Err
57
}
58
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">")
59
if templ_7745c5c3_Err != nil {
60
return templ_7745c5c3_Err
61
}
62
for _, commit := range rlc.Commits {
63
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"sm:col-span-5\"><div><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
64
if templ_7745c5c3_Err != nil {
65
return templ_7745c5c3_Err
66
}
67
+
var templ_7745c5c3_Var3 templ.SafeURL
68
+
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA)))
69
+
if templ_7745c5c3_Err != nil {
70
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 19, Col: 190}
71
+
}
72
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
73
if templ_7745c5c3_Err != nil {
74
return templ_7745c5c3_Err
75
}
76
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">")
77
if templ_7745c5c3_Err != nil {
78
return templ_7745c5c3_Err
79
}
···
86
if templ_7745c5c3_Err != nil {
87
return templ_7745c5c3_Err
88
}
89
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</a></div><div class=\"whitespace-pre\">")
90
if templ_7745c5c3_Err != nil {
91
return templ_7745c5c3_Err
92
}
93
if commit.Details() != "" {
94
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<details><summary class=\"cursor-pointer\">")
95
if templ_7745c5c3_Err != nil {
96
return templ_7745c5c3_Err
97
}
···
104
if templ_7745c5c3_Err != nil {
105
return templ_7745c5c3_Err
106
}
107
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</summary><div class=\"p-3 bg-base rounded\">")
108
if templ_7745c5c3_Err != nil {
109
return templ_7745c5c3_Err
110
}
···
117
if templ_7745c5c3_Err != nil {
118
return templ_7745c5c3_Err
119
}
120
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div></details>")
121
if templ_7745c5c3_Err != nil {
122
return templ_7745c5c3_Err
123
}
···
132
return templ_7745c5c3_Err
133
}
134
}
135
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div><div class=\"sm:col-span-3 mb-4\"><div>")
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
···
154
if templ_7745c5c3_Err != nil {
155
return templ_7745c5c3_Err
156
}
157
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
158
if templ_7745c5c3_Err != nil {
159
return templ_7745c5c3_Err
160
}
161
+
var templ_7745c5c3_Var10 templ.SafeURL
162
+
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email)))
163
+
if templ_7745c5c3_Err != nil {
164
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 175}
165
+
}
166
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
167
if templ_7745c5c3_Err != nil {
168
return templ_7745c5c3_Err
169
}
170
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">")
171
if templ_7745c5c3_Err != nil {
172
return templ_7745c5c3_Err
173
}
···
180
if templ_7745c5c3_Err != nil {
181
return templ_7745c5c3_Err
182
}
183
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div><div title=\"")
184
if templ_7745c5c3_Err != nil {
185
return templ_7745c5c3_Err
186
}
···
193
if templ_7745c5c3_Err != nil {
194
return templ_7745c5c3_Err
195
}
196
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">")
197
if templ_7745c5c3_Err != nil {
198
return templ_7745c5c3_Err
199
}
···
206
if templ_7745c5c3_Err != nil {
207
return templ_7745c5c3_Err
208
}
209
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></div>")
210
if templ_7745c5c3_Err != nil {
211
return templ_7745c5c3_Err
212
}
213
}
214
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div>")
215
if templ_7745c5c3_Err != nil {
216
return templ_7745c5c3_Err
217
}
218
+
return nil
219
})
220
templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
221
if templ_7745c5c3_Err != nil {
222
return templ_7745c5c3_Err
223
}
224
+
return nil
225
})
226
}
227
+
228
+
var _ = templruntime.GeneratedTemplate
+4
-5
internal/html/repo_refs.templ
+4
-5
internal/html/repo_refs.templ
+73
-49
internal/html/repo_refs_templ.go
+73
-49
internal/html/repo_refs_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import "fmt"
14
import "go.jolheiser.com/ugit/internal/git"
···
21
}
22
23
func RepoRefs(rrc RepoRefsContext) templ.Component {
24
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
25
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
26
if !templ_7745c5c3_IsBuffer {
27
-
templ_7745c5c3_Buffer = templ.GetBuffer()
28
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
29
}
30
ctx = templ.InitializeContext(ctx)
31
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
33
templ_7745c5c3_Var1 = templ.NopComponent
34
}
35
ctx = templ.ClearChildren(ctx)
36
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
37
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
38
if !templ_7745c5c3_IsBuffer {
39
-
templ_7745c5c3_Buffer = templ.GetBuffer()
40
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
41
}
42
templ_7745c5c3_Err = repoHeaderComponent(rrc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
43
if templ_7745c5c3_Err != nil {
44
return templ_7745c5c3_Err
45
}
46
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
47
if templ_7745c5c3_Err != nil {
48
return templ_7745c5c3_Err
49
}
50
if len(rrc.Branches) > 0 {
51
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-text text-lg mt-5\">Branches</h3><div class=\"text-text grid grid-cols-4 sm:grid-cols-8\">")
52
if templ_7745c5c3_Err != nil {
53
return templ_7745c5c3_Err
54
}
55
for _, branch := range rrc.Branches {
56
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-2 sm:col-span-1 font-bold\">")
57
if templ_7745c5c3_Err != nil {
58
return templ_7745c5c3_Err
59
}
···
66
if templ_7745c5c3_Err != nil {
67
return templ_7745c5c3_Err
68
}
69
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"col-span-2 sm:col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
70
if templ_7745c5c3_Err != nil {
71
return templ_7745c5c3_Err
72
}
73
-
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch))
74
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
75
if templ_7745c5c3_Err != nil {
76
return templ_7745c5c3_Err
77
}
78
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
79
if templ_7745c5c3_Err != nil {
80
return templ_7745c5c3_Err
81
}
···
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
92
if templ_7745c5c3_Err != nil {
93
return templ_7745c5c3_Err
94
}
95
-
var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch))
96
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6)))
97
if templ_7745c5c3_Err != nil {
98
return templ_7745c5c3_Err
99
}
100
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>")
101
if templ_7745c5c3_Err != nil {
102
return templ_7745c5c3_Err
103
}
104
}
105
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
106
if templ_7745c5c3_Err != nil {
107
return templ_7745c5c3_Err
108
}
109
}
110
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
111
if templ_7745c5c3_Err != nil {
112
return templ_7745c5c3_Err
113
}
114
if len(rrc.Tags) > 0 {
115
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-text text-lg mt-5\">Tags</h3><div class=\"text-text grid grid-cols-8\">")
116
if templ_7745c5c3_Err != nil {
117
return templ_7745c5c3_Err
118
}
119
for _, tag := range rrc.Tags {
120
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-1 font-bold\">")
121
if templ_7745c5c3_Err != nil {
122
return templ_7745c5c3_Err
123
}
···
130
if templ_7745c5c3_Err != nil {
131
return templ_7745c5c3_Err
132
}
133
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
134
if templ_7745c5c3_Err != nil {
135
return templ_7745c5c3_Err
136
}
137
-
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name))
138
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
139
if templ_7745c5c3_Err != nil {
140
return templ_7745c5c3_Err
141
}
142
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
143
if templ_7745c5c3_Err != nil {
144
return templ_7745c5c3_Err
145
}
···
152
if templ_7745c5c3_Err != nil {
153
return templ_7745c5c3_Err
154
}
155
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
156
if templ_7745c5c3_Err != nil {
157
return templ_7745c5c3_Err
158
}
159
-
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name))
160
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
161
if templ_7745c5c3_Err != nil {
162
return templ_7745c5c3_Err
163
}
164
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>")
165
if templ_7745c5c3_Err != nil {
166
return templ_7745c5c3_Err
167
}
168
if tag.Signature != "" {
169
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>")
170
if templ_7745c5c3_Err != nil {
171
return templ_7745c5c3_Err
172
}
···
179
if templ_7745c5c3_Err != nil {
180
return templ_7745c5c3_Err
181
}
182
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></details>")
183
if templ_7745c5c3_Err != nil {
184
return templ_7745c5c3_Err
185
}
186
}
187
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
188
if templ_7745c5c3_Err != nil {
189
return templ_7745c5c3_Err
190
}
191
if tag.Annotation != "" {
192
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-8 mb-3\">")
193
if templ_7745c5c3_Err != nil {
194
return templ_7745c5c3_Err
195
}
···
202
if templ_7745c5c3_Err != nil {
203
return templ_7745c5c3_Err
204
}
205
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
206
if templ_7745c5c3_Err != nil {
207
return templ_7745c5c3_Err
208
}
209
}
210
}
211
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
212
if templ_7745c5c3_Err != nil {
213
return templ_7745c5c3_Err
214
}
215
}
216
-
if !templ_7745c5c3_IsBuffer {
217
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
218
-
}
219
-
return templ_7745c5c3_Err
220
})
221
templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
222
if templ_7745c5c3_Err != nil {
223
return templ_7745c5c3_Err
224
}
225
-
if !templ_7745c5c3_IsBuffer {
226
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
227
-
}
228
-
return templ_7745c5c3_Err
229
})
230
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import "fmt"
12
import "go.jolheiser.com/ugit/internal/git"
···
19
}
20
21
func RepoRefs(rrc RepoRefsContext) templ.Component {
22
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
23
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
24
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
25
+
return templ_7745c5c3_CtxErr
26
+
}
27
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
28
if !templ_7745c5c3_IsBuffer {
29
+
defer func() {
30
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
31
+
if templ_7745c5c3_Err == nil {
32
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
33
+
}
34
+
}()
35
}
36
ctx = templ.InitializeContext(ctx)
37
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
39
templ_7745c5c3_Var1 = templ.NopComponent
40
}
41
ctx = templ.ClearChildren(ctx)
42
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
43
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
44
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
45
if !templ_7745c5c3_IsBuffer {
46
+
defer func() {
47
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
48
+
if templ_7745c5c3_Err == nil {
49
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
50
+
}
51
+
}()
52
}
53
+
ctx = templ.InitializeContext(ctx)
54
templ_7745c5c3_Err = repoHeaderComponent(rrc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
55
if templ_7745c5c3_Err != nil {
56
return templ_7745c5c3_Err
57
}
58
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ")
59
if templ_7745c5c3_Err != nil {
60
return templ_7745c5c3_Err
61
}
62
if len(rrc.Branches) > 0 {
63
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<h3 class=\"text-text text-lg mt-5\">Branches</h3><div class=\"text-text grid grid-cols-4 sm:grid-cols-8\">")
64
if templ_7745c5c3_Err != nil {
65
return templ_7745c5c3_Err
66
}
67
for _, branch := range rrc.Branches {
68
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"col-span-2 sm:col-span-1 font-bold\">")
69
if templ_7745c5c3_Err != nil {
70
return templ_7745c5c3_Err
71
}
···
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
81
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</div><div class=\"col-span-2 sm:col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
82
if templ_7745c5c3_Err != nil {
83
return templ_7745c5c3_Err
84
}
85
+
var templ_7745c5c3_Var4 templ.SafeURL
86
+
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)))
87
+
if templ_7745c5c3_Err != nil {
88
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 218}
89
+
}
90
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
91
if templ_7745c5c3_Err != nil {
92
return templ_7745c5c3_Err
93
}
94
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">tree</a>")
95
if templ_7745c5c3_Err != nil {
96
return templ_7745c5c3_Err
97
}
···
104
if templ_7745c5c3_Err != nil {
105
return templ_7745c5c3_Err
106
}
107
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
108
if templ_7745c5c3_Err != nil {
109
return templ_7745c5c3_Err
110
}
111
+
var templ_7745c5c3_Var6 templ.SafeURL
112
+
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)))
113
+
if templ_7745c5c3_Err != nil {
114
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 409}
115
+
}
116
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
117
if templ_7745c5c3_Err != nil {
118
return templ_7745c5c3_Err
119
}
120
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\">log</a></div>")
121
if templ_7745c5c3_Err != nil {
122
return templ_7745c5c3_Err
123
}
124
}
125
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>")
126
if templ_7745c5c3_Err != nil {
127
return templ_7745c5c3_Err
128
}
129
}
130
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ")
131
if templ_7745c5c3_Err != nil {
132
return templ_7745c5c3_Err
133
}
134
if len(rrc.Tags) > 0 {
135
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<h3 class=\"text-text text-lg mt-5\">Tags</h3><div class=\"text-text grid grid-cols-8\">")
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
139
for _, tag := range rrc.Tags {
140
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"col-span-1 font-bold\">")
141
if templ_7745c5c3_Err != nil {
142
return templ_7745c5c3_Err
143
}
···
150
if templ_7745c5c3_Err != nil {
151
return templ_7745c5c3_Err
152
}
153
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div><div class=\"col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
154
if templ_7745c5c3_Err != nil {
155
return templ_7745c5c3_Err
156
}
157
+
var templ_7745c5c3_Var8 templ.SafeURL
158
+
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)))
159
+
if templ_7745c5c3_Err != nil {
160
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 206}
161
+
}
162
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
163
if templ_7745c5c3_Err != nil {
164
return templ_7745c5c3_Err
165
}
166
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">tree</a>")
167
if templ_7745c5c3_Err != nil {
168
return templ_7745c5c3_Err
169
}
···
176
if templ_7745c5c3_Err != nil {
177
return templ_7745c5c3_Err
178
}
179
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
180
if templ_7745c5c3_Err != nil {
181
return templ_7745c5c3_Err
182
}
183
+
var templ_7745c5c3_Var10 templ.SafeURL
184
+
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)))
185
+
if templ_7745c5c3_Err != nil {
186
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 399}
187
+
}
188
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
189
if templ_7745c5c3_Err != nil {
190
return templ_7745c5c3_Err
191
}
192
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">log</a></div>")
193
if templ_7745c5c3_Err != nil {
194
return templ_7745c5c3_Err
195
}
196
if tag.Signature != "" {
197
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>")
198
if templ_7745c5c3_Err != nil {
199
return templ_7745c5c3_Err
200
}
···
207
if templ_7745c5c3_Err != nil {
208
return templ_7745c5c3_Err
209
}
210
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</code></details>")
211
if templ_7745c5c3_Err != nil {
212
return templ_7745c5c3_Err
213
}
214
}
215
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ")
216
if templ_7745c5c3_Err != nil {
217
return templ_7745c5c3_Err
218
}
219
if tag.Annotation != "" {
220
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div class=\"col-span-8 mb-3\">")
221
if templ_7745c5c3_Err != nil {
222
return templ_7745c5c3_Err
223
}
···
230
if templ_7745c5c3_Err != nil {
231
return templ_7745c5c3_Err
232
}
233
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>")
234
if templ_7745c5c3_Err != nil {
235
return templ_7745c5c3_Err
236
}
237
}
238
}
239
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>")
240
if templ_7745c5c3_Err != nil {
241
return templ_7745c5c3_Err
242
}
243
}
244
+
return nil
245
})
246
templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
247
if templ_7745c5c3_Err != nil {
248
return templ_7745c5c3_Err
249
}
250
+
return nil
251
})
252
}
253
+
254
+
var _ = templruntime.GeneratedTemplate
+6
-8
internal/html/repo_search.templ
+6
-8
internal/html/repo_search.templ
···
11
12
func (s SearchContext) DedupeResults() [][]git.GrepResult {
13
var (
14
-
results [][]git.GrepResult
15
-
currentFile string
16
-
currentResults []git.GrepResult
17
)
18
for _, result := range s.Results {
19
if result.File == currentFile {
20
-
currentResults = append(currentResults, result)
21
continue
22
}
23
-
if currentFile != "" {
24
-
results = append(results, currentResults)
25
-
}
26
currentFile = result.File
27
-
currentResults = []git.GrepResult{result}
28
}
29
30
return results
···
11
12
func (s SearchContext) DedupeResults() [][]git.GrepResult {
13
var (
14
+
results [][]git.GrepResult
15
+
currentFile string
16
)
17
+
var idx int
18
for _, result := range s.Results {
19
if result.File == currentFile {
20
+
results[idx-1] = append(results[idx-1], result)
21
continue
22
}
23
+
results = append(results, []git.GrepResult{result})
24
currentFile = result.File
25
+
idx++
26
}
27
28
return results
+76
-57
internal/html/repo_search_templ.go
+76
-57
internal/html/repo_search_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import "fmt"
14
import "go.jolheiser.com/ugit/internal/git"
···
21
22
func (s SearchContext) DedupeResults() [][]git.GrepResult {
23
var (
24
-
results [][]git.GrepResult
25
-
currentFile string
26
-
currentResults []git.GrepResult
27
)
28
for _, result := range s.Results {
29
if result.File == currentFile {
30
-
currentResults = append(currentResults, result)
31
continue
32
}
33
-
if currentFile != "" {
34
-
results = append(results, currentResults)
35
-
}
36
currentFile = result.File
37
-
currentResults = []git.GrepResult{result}
38
}
39
40
return results
41
}
42
43
func RepoSearch(sc SearchContext) templ.Component {
44
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
45
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
46
if !templ_7745c5c3_IsBuffer {
47
-
templ_7745c5c3_Buffer = templ.GetBuffer()
48
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
49
}
50
ctx = templ.InitializeContext(ctx)
51
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
53
templ_7745c5c3_Var1 = templ.NopComponent
54
}
55
ctx = templ.ClearChildren(ctx)
56
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
57
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
58
if !templ_7745c5c3_IsBuffer {
59
-
templ_7745c5c3_Buffer = templ.GetBuffer()
60
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
61
}
62
templ_7745c5c3_Err = repoHeaderComponent(sc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
63
if templ_7745c5c3_Err != nil {
64
return templ_7745c5c3_Err
···
69
return templ_7745c5c3_Err
70
}
71
}
72
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
73
if templ_7745c5c3_Err != nil {
74
return templ_7745c5c3_Err
75
}
76
if len(sc.DedupeResults()) == 0 {
77
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-text mt-5 text-lg\">No results</p>")
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
81
}
82
-
if !templ_7745c5c3_IsBuffer {
83
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
84
-
}
85
-
return templ_7745c5c3_Err
86
})
87
templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>\n\t\tconst search = new URLSearchParams(window.location.search).get(\"q\");\n\t\tif (search !== \"\") document.querySelector(\"#search\").value = search;\n\t</script>")
92
if templ_7745c5c3_Err != nil {
93
return templ_7745c5c3_Err
94
}
95
-
if !templ_7745c5c3_IsBuffer {
96
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
97
-
}
98
-
return templ_7745c5c3_Err
99
})
100
}
101
102
func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Component {
103
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
104
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
105
if !templ_7745c5c3_IsBuffer {
106
-
templ_7745c5c3_Buffer = templ.GetBuffer()
107
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
108
}
109
ctx = templ.InitializeContext(ctx)
110
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
···
112
templ_7745c5c3_Var3 = templ.NopComponent
113
}
114
ctx = templ.ClearChildren(ctx)
115
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
116
if templ_7745c5c3_Err != nil {
117
return templ_7745c5c3_Err
118
}
119
-
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line))
120
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
121
if templ_7745c5c3_Err != nil {
122
return templ_7745c5c3_Err
123
}
124
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
125
if templ_7745c5c3_Err != nil {
126
return templ_7745c5c3_Err
127
}
128
var templ_7745c5c3_Var5 string
129
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
130
if templ_7745c5c3_Err != nil {
131
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 50, Col: 230}
132
}
133
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
134
if templ_7745c5c3_Err != nil {
135
return templ_7745c5c3_Err
136
}
137
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code\">")
138
if templ_7745c5c3_Err != nil {
139
return templ_7745c5c3_Err
140
}
···
142
if templ_7745c5c3_Err != nil {
143
return templ_7745c5c3_Err
144
}
145
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
146
if templ_7745c5c3_Err != nil {
147
return templ_7745c5c3_Err
148
}
149
if len(results) > 1 {
150
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text cursor-pointer\"><summary>")
151
if templ_7745c5c3_Err != nil {
152
return templ_7745c5c3_Err
153
}
154
var templ_7745c5c3_Var6 string
155
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:])))
156
if templ_7745c5c3_Err != nil {
157
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 50}
158
}
159
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
160
if templ_7745c5c3_Err != nil {
161
return templ_7745c5c3_Err
162
}
163
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("more</summary> ")
164
if templ_7745c5c3_Err != nil {
165
return templ_7745c5c3_Err
166
}
167
for _, result := range results[1:] {
168
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5 ml-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
169
if templ_7745c5c3_Err != nil {
170
return templ_7745c5c3_Err
171
}
172
-
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line))
173
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
174
if templ_7745c5c3_Err != nil {
175
return templ_7745c5c3_Err
176
}
177
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
178
if templ_7745c5c3_Err != nil {
179
return templ_7745c5c3_Err
180
}
181
var templ_7745c5c3_Var8 string
182
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
183
if templ_7745c5c3_Err != nil {
184
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 58, Col: 230}
185
}
186
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
187
if templ_7745c5c3_Err != nil {
188
return templ_7745c5c3_Err
189
}
190
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code ml-5\">")
191
if templ_7745c5c3_Err != nil {
192
return templ_7745c5c3_Err
193
}
···
195
if templ_7745c5c3_Err != nil {
196
return templ_7745c5c3_Err
197
}
198
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
199
if templ_7745c5c3_Err != nil {
200
return templ_7745c5c3_Err
201
}
202
}
203
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</details>")
204
if templ_7745c5c3_Err != nil {
205
return templ_7745c5c3_Err
206
}
207
}
208
-
if !templ_7745c5c3_IsBuffer {
209
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
210
-
}
211
-
return templ_7745c5c3_Err
212
})
213
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import "fmt"
12
import "go.jolheiser.com/ugit/internal/git"
···
19
20
func (s SearchContext) DedupeResults() [][]git.GrepResult {
21
var (
22
+
results [][]git.GrepResult
23
+
currentFile string
24
)
25
+
var idx int
26
for _, result := range s.Results {
27
if result.File == currentFile {
28
+
results[idx-1] = append(results[idx-1], result)
29
continue
30
}
31
+
results = append(results, []git.GrepResult{result})
32
currentFile = result.File
33
+
idx++
34
}
35
36
return results
37
}
38
39
func RepoSearch(sc SearchContext) templ.Component {
40
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
41
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
42
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
43
+
return templ_7745c5c3_CtxErr
44
+
}
45
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
46
if !templ_7745c5c3_IsBuffer {
47
+
defer func() {
48
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
49
+
if templ_7745c5c3_Err == nil {
50
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
51
+
}
52
+
}()
53
}
54
ctx = templ.InitializeContext(ctx)
55
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
57
templ_7745c5c3_Var1 = templ.NopComponent
58
}
59
ctx = templ.ClearChildren(ctx)
60
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
61
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
62
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
63
if !templ_7745c5c3_IsBuffer {
64
+
defer func() {
65
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
66
+
if templ_7745c5c3_Err == nil {
67
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
68
+
}
69
+
}()
70
}
71
+
ctx = templ.InitializeContext(ctx)
72
templ_7745c5c3_Err = repoHeaderComponent(sc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
73
if templ_7745c5c3_Err != nil {
74
return templ_7745c5c3_Err
···
79
return templ_7745c5c3_Err
80
}
81
}
82
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ")
83
if templ_7745c5c3_Err != nil {
84
return templ_7745c5c3_Err
85
}
86
if len(sc.DedupeResults()) == 0 {
87
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"text-text mt-5 text-lg\">No results</p>")
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
}
92
+
return nil
93
})
94
templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
95
if templ_7745c5c3_Err != nil {
96
return templ_7745c5c3_Err
97
}
98
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<script>\n\t\tconst search = new URLSearchParams(window.location.search).get(\"q\");\n\t\tif (search !== \"\") document.querySelector(\"#search\").value = search;\n\t</script>")
99
if templ_7745c5c3_Err != nil {
100
return templ_7745c5c3_Err
101
}
102
+
return nil
103
})
104
}
105
106
func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Component {
107
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
108
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
109
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
110
+
return templ_7745c5c3_CtxErr
111
+
}
112
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
113
if !templ_7745c5c3_IsBuffer {
114
+
defer func() {
115
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
116
+
if templ_7745c5c3_Err == nil {
117
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
118
+
}
119
+
}()
120
}
121
ctx = templ.InitializeContext(ctx)
122
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
···
124
templ_7745c5c3_Var3 = templ.NopComponent
125
}
126
ctx = templ.ClearChildren(ctx)
127
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
128
if templ_7745c5c3_Err != nil {
129
return templ_7745c5c3_Err
130
}
131
+
var templ_7745c5c3_Var4 templ.SafeURL
132
+
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)))
133
+
if templ_7745c5c3_Err != nil {
134
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 210}
135
+
}
136
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
137
if templ_7745c5c3_Err != nil {
138
return templ_7745c5c3_Err
139
}
140
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">")
141
if templ_7745c5c3_Err != nil {
142
return templ_7745c5c3_Err
143
}
144
var templ_7745c5c3_Var5 string
145
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
146
if templ_7745c5c3_Err != nil {
147
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 230}
148
}
149
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
150
if templ_7745c5c3_Err != nil {
151
return templ_7745c5c3_Err
152
}
153
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a></div><div class=\"code\">")
154
if templ_7745c5c3_Err != nil {
155
return templ_7745c5c3_Err
156
}
···
158
if templ_7745c5c3_Err != nil {
159
return templ_7745c5c3_Err
160
}
161
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>")
162
if templ_7745c5c3_Err != nil {
163
return templ_7745c5c3_Err
164
}
165
if len(results) > 1 {
166
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<details class=\"text-text cursor-pointer\"><summary>")
167
if templ_7745c5c3_Err != nil {
168
return templ_7745c5c3_Err
169
}
170
var templ_7745c5c3_Var6 string
171
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:])))
172
if templ_7745c5c3_Err != nil {
173
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 54, Col: 50}
174
}
175
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
176
if templ_7745c5c3_Err != nil {
177
return templ_7745c5c3_Err
178
}
179
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "more</summary> ")
180
if templ_7745c5c3_Err != nil {
181
return templ_7745c5c3_Err
182
}
183
for _, result := range results[1:] {
184
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"text-text mt-5 ml-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
185
if templ_7745c5c3_Err != nil {
186
return templ_7745c5c3_Err
187
}
188
+
var templ_7745c5c3_Var7 templ.SafeURL
189
+
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)))
190
+
if templ_7745c5c3_Err != nil {
191
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 210}
192
+
}
193
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
194
if templ_7745c5c3_Err != nil {
195
return templ_7745c5c3_Err
196
}
197
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">")
198
if templ_7745c5c3_Err != nil {
199
return templ_7745c5c3_Err
200
}
201
var templ_7745c5c3_Var8 string
202
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
203
if templ_7745c5c3_Err != nil {
204
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 230}
205
}
206
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
207
if templ_7745c5c3_Err != nil {
208
return templ_7745c5c3_Err
209
}
210
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</a></div><div class=\"code ml-5\">")
211
if templ_7745c5c3_Err != nil {
212
return templ_7745c5c3_Err
213
}
···
215
if templ_7745c5c3_Err != nil {
216
return templ_7745c5c3_Err
217
}
218
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>")
219
if templ_7745c5c3_Err != nil {
220
return templ_7745c5c3_Err
221
}
222
}
223
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</details>")
224
if templ_7745c5c3_Err != nil {
225
return templ_7745c5c3_Err
226
}
227
}
228
+
return nil
229
})
230
}
231
+
232
+
var _ = templruntime.GeneratedTemplate
+65
-40
internal/html/repo_templ.go
+65
-40
internal/html/repo_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import "fmt"
14
···
21
}
22
23
func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
24
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
25
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
26
if !templ_7745c5c3_IsBuffer {
27
-
templ_7745c5c3_Buffer = templ.GetBuffer()
28
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
29
}
30
ctx = templ.InitializeContext(ctx)
31
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
33
templ_7745c5c3_Var1 = templ.NopComponent
34
}
35
ctx = templ.ClearChildren(ctx)
36
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"mb-1 text-text\"><a class=\"text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
37
if templ_7745c5c3_Err != nil {
38
return templ_7745c5c3_Err
39
}
40
-
var templ_7745c5c3_Var2 templ.SafeURL = templ.SafeURL("/" + rhcc.Name)
41
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var2)))
42
if templ_7745c5c3_Err != nil {
43
return templ_7745c5c3_Err
44
}
45
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
46
if templ_7745c5c3_Err != nil {
47
return templ_7745c5c3_Err
48
}
···
55
if templ_7745c5c3_Err != nil {
56
return templ_7745c5c3_Err
57
}
58
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
59
if templ_7745c5c3_Err != nil {
60
return templ_7745c5c3_Err
61
}
···
69
if templ_7745c5c3_Err != nil {
70
return templ_7745c5c3_Err
71
}
72
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
73
if templ_7745c5c3_Err != nil {
74
return templ_7745c5c3_Err
75
}
76
-
var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref))
77
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5)))
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
81
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
82
if templ_7745c5c3_Err != nil {
83
return templ_7745c5c3_Err
84
}
···
91
if templ_7745c5c3_Err != nil {
92
return templ_7745c5c3_Err
93
}
94
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
95
if templ_7745c5c3_Err != nil {
96
return templ_7745c5c3_Err
97
}
···
105
if templ_7745c5c3_Err != nil {
106
return templ_7745c5c3_Err
107
}
108
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
109
if templ_7745c5c3_Err != nil {
110
return templ_7745c5c3_Err
111
}
112
-
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name))
113
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
114
if templ_7745c5c3_Err != nil {
115
return templ_7745c5c3_Err
116
}
117
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">refs</a> ")
118
if templ_7745c5c3_Err != nil {
119
return templ_7745c5c3_Err
120
}
···
127
if templ_7745c5c3_Err != nil {
128
return templ_7745c5c3_Err
129
}
130
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
131
if templ_7745c5c3_Err != nil {
132
return templ_7745c5c3_Err
133
}
134
-
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref))
135
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
139
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a> ")
140
if templ_7745c5c3_Err != nil {
141
return templ_7745c5c3_Err
142
}
···
149
if templ_7745c5c3_Err != nil {
150
return templ_7745c5c3_Err
151
}
152
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form class=\"inline-block\" action=\"")
153
if templ_7745c5c3_Err != nil {
154
return templ_7745c5c3_Err
155
}
156
-
var templ_7745c5c3_Var12 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name))
157
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var12)))
158
if templ_7745c5c3_Err != nil {
159
return templ_7745c5c3_Err
160
}
161
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" method=\"get\"><input class=\"rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0\" id=\"search\" type=\"text\" name=\"q\" placeholder=\"search\"></form>")
162
if templ_7745c5c3_Err != nil {
163
return templ_7745c5c3_Err
164
}
···
171
if templ_7745c5c3_Err != nil {
172
return templ_7745c5c3_Err
173
}
174
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">")
175
if templ_7745c5c3_Err != nil {
176
return templ_7745c5c3_Err
177
}
···
184
if templ_7745c5c3_Err != nil {
185
return templ_7745c5c3_Err
186
}
187
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</pre></div><div class=\"text-subtext0 mb-1\">")
188
if templ_7745c5c3_Err != nil {
189
return templ_7745c5c3_Err
190
}
191
for _, tag := range rhcc.Tags {
192
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
193
if templ_7745c5c3_Err != nil {
194
return templ_7745c5c3_Err
195
}
···
202
if templ_7745c5c3_Err != nil {
203
return templ_7745c5c3_Err
204
}
205
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
206
if templ_7745c5c3_Err != nil {
207
return templ_7745c5c3_Err
208
}
209
}
210
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"text-text/80 mb-1\">")
211
if templ_7745c5c3_Err != nil {
212
return templ_7745c5c3_Err
213
}
···
220
if templ_7745c5c3_Err != nil {
221
return templ_7745c5c3_Err
222
}
223
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
224
if templ_7745c5c3_Err != nil {
225
return templ_7745c5c3_Err
226
}
227
-
if !templ_7745c5c3_IsBuffer {
228
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
229
-
}
230
-
return templ_7745c5c3_Err
231
})
232
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import "fmt"
12
···
19
}
20
21
func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
22
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
23
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
24
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
25
+
return templ_7745c5c3_CtxErr
26
+
}
27
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
28
if !templ_7745c5c3_IsBuffer {
29
+
defer func() {
30
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
31
+
if templ_7745c5c3_Err == nil {
32
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
33
+
}
34
+
}()
35
}
36
ctx = templ.InitializeContext(ctx)
37
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
39
templ_7745c5c3_Var1 = templ.NopComponent
40
}
41
ctx = templ.ClearChildren(ctx)
42
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"mb-1 text-text\"><a class=\"text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
43
if templ_7745c5c3_Err != nil {
44
return templ_7745c5c3_Err
45
}
46
+
var templ_7745c5c3_Var2 templ.SafeURL
47
+
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("/" + rhcc.Name))
48
+
if templ_7745c5c3_Err != nil {
49
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 128}
50
+
}
51
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
52
if templ_7745c5c3_Err != nil {
53
return templ_7745c5c3_Err
54
}
55
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">")
56
if templ_7745c5c3_Err != nil {
57
return templ_7745c5c3_Err
58
}
···
65
if templ_7745c5c3_Err != nil {
66
return templ_7745c5c3_Err
67
}
68
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</a> ")
69
if templ_7745c5c3_Err != nil {
70
return templ_7745c5c3_Err
71
}
···
79
if templ_7745c5c3_Err != nil {
80
return templ_7745c5c3_Err
81
}
82
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " <a class=\"text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
83
if templ_7745c5c3_Err != nil {
84
return templ_7745c5c3_Err
85
}
86
+
var templ_7745c5c3_Var5 templ.SafeURL
87
+
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)))
88
+
if templ_7745c5c3_Err != nil {
89
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 175}
90
+
}
91
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
92
if templ_7745c5c3_Err != nil {
93
return templ_7745c5c3_Err
94
}
95
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">")
96
if templ_7745c5c3_Err != nil {
97
return templ_7745c5c3_Err
98
}
···
105
if templ_7745c5c3_Err != nil {
106
return templ_7745c5c3_Err
107
}
108
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ")
109
if templ_7745c5c3_Err != nil {
110
return templ_7745c5c3_Err
111
}
···
119
if templ_7745c5c3_Err != nil {
120
return templ_7745c5c3_Err
121
}
122
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
123
if templ_7745c5c3_Err != nil {
124
return templ_7745c5c3_Err
125
}
126
+
var templ_7745c5c3_Var8 templ.SafeURL
127
+
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name)))
128
+
if templ_7745c5c3_Err != nil {
129
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 21, Col: 139}
130
+
}
131
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
132
if templ_7745c5c3_Err != nil {
133
return templ_7745c5c3_Err
134
}
135
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">refs</a> ")
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
···
145
if templ_7745c5c3_Err != nil {
146
return templ_7745c5c3_Err
147
}
148
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
149
if templ_7745c5c3_Err != nil {
150
return templ_7745c5c3_Err
151
}
152
+
var templ_7745c5c3_Var10 templ.SafeURL
153
+
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)))
154
+
if templ_7745c5c3_Err != nil {
155
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 23, Col: 151}
156
+
}
157
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
158
if templ_7745c5c3_Err != nil {
159
return templ_7745c5c3_Err
160
}
161
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">log</a> ")
162
if templ_7745c5c3_Err != nil {
163
return templ_7745c5c3_Err
164
}
···
171
if templ_7745c5c3_Err != nil {
172
return templ_7745c5c3_Err
173
}
174
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<form class=\"inline-block\" action=\"")
175
if templ_7745c5c3_Err != nil {
176
return templ_7745c5c3_Err
177
}
178
+
var templ_7745c5c3_Var12 templ.SafeURL
179
+
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)))
180
+
if templ_7745c5c3_Err != nil {
181
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 25, Col: 89}
182
+
}
183
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
184
if templ_7745c5c3_Err != nil {
185
return templ_7745c5c3_Err
186
}
187
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" method=\"get\"><input class=\"rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0\" id=\"search\" type=\"text\" name=\"q\" placeholder=\"search\"></form>")
188
if templ_7745c5c3_Err != nil {
189
return templ_7745c5c3_Err
190
}
···
197
if templ_7745c5c3_Err != nil {
198
return templ_7745c5c3_Err
199
}
200
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">")
201
if templ_7745c5c3_Err != nil {
202
return templ_7745c5c3_Err
203
}
···
210
if templ_7745c5c3_Err != nil {
211
return templ_7745c5c3_Err
212
}
213
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</pre></div><div class=\"text-subtext0 mb-1\">")
214
if templ_7745c5c3_Err != nil {
215
return templ_7745c5c3_Err
216
}
217
for _, tag := range rhcc.Tags {
218
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<span class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
219
if templ_7745c5c3_Err != nil {
220
return templ_7745c5c3_Err
221
}
···
228
if templ_7745c5c3_Err != nil {
229
return templ_7745c5c3_Err
230
}
231
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</span>")
232
if templ_7745c5c3_Err != nil {
233
return templ_7745c5c3_Err
234
}
235
}
236
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"text-text/80 mb-1\">")
237
if templ_7745c5c3_Err != nil {
238
return templ_7745c5c3_Err
239
}
···
246
if templ_7745c5c3_Err != nil {
247
return templ_7745c5c3_Err
248
}
249
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>")
250
if templ_7745c5c3_Err != nil {
251
return templ_7745c5c3_Err
252
}
253
+
return nil
254
})
255
}
256
+
257
+
var _ = templruntime.GeneratedTemplate
-1
internal/html/repo_tree.templ
-1
internal/html/repo_tree.templ
+68
-48
internal/html/repo_tree_templ.go
+68
-48
internal/html/repo_tree_templ.go
···
1
// Code generated by templ - DO NOT EDIT.
2
3
-
// templ: version: v0.2.707
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
-
import "context"
10
-
import "io"
11
-
import "bytes"
12
13
import (
14
"fmt"
···
21
RepoBreadcrumbComponentContext
22
RepoTreeComponentContext
23
ReadmeComponentContext
24
-
Description string
25
}
26
27
func RepoTree(rtc RepoTreeContext) templ.Component {
28
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
29
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
30
if !templ_7745c5c3_IsBuffer {
31
-
templ_7745c5c3_Buffer = templ.GetBuffer()
32
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
33
}
34
ctx = templ.InitializeContext(ctx)
35
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
37
templ_7745c5c3_Var1 = templ.NopComponent
38
}
39
ctx = templ.ClearChildren(ctx)
40
-
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
41
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
42
if !templ_7745c5c3_IsBuffer {
43
-
templ_7745c5c3_Buffer = templ.GetBuffer()
44
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
45
}
46
templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
47
if templ_7745c5c3_Err != nil {
48
return templ_7745c5c3_Err
49
}
50
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
51
if templ_7745c5c3_Err != nil {
52
return templ_7745c5c3_Err
53
}
···
55
if templ_7745c5c3_Err != nil {
56
return templ_7745c5c3_Err
57
}
58
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
59
if templ_7745c5c3_Err != nil {
60
return templ_7745c5c3_Err
61
}
···
63
if templ_7745c5c3_Err != nil {
64
return templ_7745c5c3_Err
65
}
66
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
67
if templ_7745c5c3_Err != nil {
68
return templ_7745c5c3_Err
69
}
···
71
if templ_7745c5c3_Err != nil {
72
return templ_7745c5c3_Err
73
}
74
-
if !templ_7745c5c3_IsBuffer {
75
-
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
76
-
}
77
-
return templ_7745c5c3_Err
78
})
79
templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
80
if templ_7745c5c3_Err != nil {
81
return templ_7745c5c3_Err
82
}
83
-
if !templ_7745c5c3_IsBuffer {
84
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
85
-
}
86
-
return templ_7745c5c3_Err
87
})
88
}
89
···
102
}
103
104
func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component {
105
-
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
106
-
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
107
if !templ_7745c5c3_IsBuffer {
108
-
templ_7745c5c3_Buffer = templ.GetBuffer()
109
-
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
110
}
111
ctx = templ.InitializeContext(ctx)
112
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
···
114
templ_7745c5c3_Var3 = templ.NopComponent
115
}
116
ctx = templ.ClearChildren(ctx)
117
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50\">")
118
if templ_7745c5c3_Err != nil {
119
return templ_7745c5c3_Err
120
}
121
if rtcc.Back != "" {
122
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-2\"></div><div class=\"sm:col-span-6\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
123
if templ_7745c5c3_Err != nil {
124
return templ_7745c5c3_Err
125
}
126
-
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back))
127
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
128
if templ_7745c5c3_Err != nil {
129
return templ_7745c5c3_Err
130
}
131
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">..</a></div>")
132
if templ_7745c5c3_Err != nil {
133
return templ_7745c5c3_Err
134
}
135
}
136
for _, fi := range rtcc.Tree {
137
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-1 break-keep\">")
138
if templ_7745c5c3_Err != nil {
139
return templ_7745c5c3_Err
140
}
141
var templ_7745c5c3_Var5 string
142
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode)
143
if templ_7745c5c3_Err != nil {
144
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50}
145
}
146
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
147
if templ_7745c5c3_Err != nil {
148
return templ_7745c5c3_Err
149
}
150
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-right\">")
151
if templ_7745c5c3_Err != nil {
152
return templ_7745c5c3_Err
153
}
154
var templ_7745c5c3_Var6 string
155
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size)
156
if templ_7745c5c3_Err != nil {
157
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 50}
158
}
159
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
160
if templ_7745c5c3_Err != nil {
161
return templ_7745c5c3_Err
162
}
163
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-6 overflow-hidden text-ellipsis\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
164
if templ_7745c5c3_Err != nil {
165
return templ_7745c5c3_Err
166
}
167
-
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path))
168
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
169
if templ_7745c5c3_Err != nil {
170
return templ_7745c5c3_Err
171
}
172
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
173
if templ_7745c5c3_Err != nil {
174
return templ_7745c5c3_Err
175
}
176
var templ_7745c5c3_Var8 string
177
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir))
178
if templ_7745c5c3_Err != nil {
179
-
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 256}
180
}
181
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
182
if templ_7745c5c3_Err != nil {
183
return templ_7745c5c3_Err
184
}
185
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
186
if templ_7745c5c3_Err != nil {
187
return templ_7745c5c3_Err
188
}
189
}
190
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
191
if templ_7745c5c3_Err != nil {
192
return templ_7745c5c3_Err
193
}
194
-
if !templ_7745c5c3_IsBuffer {
195
-
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
196
-
}
197
-
return templ_7745c5c3_Err
198
})
199
}
···
1
// Code generated by templ - DO NOT EDIT.
2
3
+
// templ: version: v0.3.924
4
package html
5
6
//lint:file-ignore SA4006 This context is only used if a nested component is present.
7
8
import "github.com/a-h/templ"
9
+
import templruntime "github.com/a-h/templ/runtime"
10
11
import (
12
"fmt"
···
19
RepoBreadcrumbComponentContext
20
RepoTreeComponentContext
21
ReadmeComponentContext
22
}
23
24
func RepoTree(rtc RepoTreeContext) templ.Component {
25
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
26
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
27
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
28
+
return templ_7745c5c3_CtxErr
29
+
}
30
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
31
if !templ_7745c5c3_IsBuffer {
32
+
defer func() {
33
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
34
+
if templ_7745c5c3_Err == nil {
35
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
36
+
}
37
+
}()
38
}
39
ctx = templ.InitializeContext(ctx)
40
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
···
42
templ_7745c5c3_Var1 = templ.NopComponent
43
}
44
ctx = templ.ClearChildren(ctx)
45
+
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
46
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
47
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
48
if !templ_7745c5c3_IsBuffer {
49
+
defer func() {
50
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
51
+
if templ_7745c5c3_Err == nil {
52
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
53
+
}
54
+
}()
55
}
56
+
ctx = templ.InitializeContext(ctx)
57
templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
58
if templ_7745c5c3_Err != nil {
59
return templ_7745c5c3_Err
60
}
61
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ")
62
if templ_7745c5c3_Err != nil {
63
return templ_7745c5c3_Err
64
}
···
66
if templ_7745c5c3_Err != nil {
67
return templ_7745c5c3_Err
68
}
69
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ")
70
if templ_7745c5c3_Err != nil {
71
return templ_7745c5c3_Err
72
}
···
74
if templ_7745c5c3_Err != nil {
75
return templ_7745c5c3_Err
76
}
77
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ")
78
if templ_7745c5c3_Err != nil {
79
return templ_7745c5c3_Err
80
}
···
82
if templ_7745c5c3_Err != nil {
83
return templ_7745c5c3_Err
84
}
85
+
return nil
86
})
87
templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
88
if templ_7745c5c3_Err != nil {
89
return templ_7745c5c3_Err
90
}
91
+
return nil
92
})
93
}
94
···
107
}
108
109
func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component {
110
+
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
111
+
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
112
+
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
113
+
return templ_7745c5c3_CtxErr
114
+
}
115
+
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
116
if !templ_7745c5c3_IsBuffer {
117
+
defer func() {
118
+
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
119
+
if templ_7745c5c3_Err == nil {
120
+
templ_7745c5c3_Err = templ_7745c5c3_BufErr
121
+
}
122
+
}()
123
}
124
ctx = templ.InitializeContext(ctx)
125
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
···
127
templ_7745c5c3_Var3 = templ.NopComponent
128
}
129
ctx = templ.ClearChildren(ctx)
130
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50\">")
131
if templ_7745c5c3_Err != nil {
132
return templ_7745c5c3_Err
133
}
134
if rtcc.Back != "" {
135
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div class=\"col-span-2\"></div><div class=\"sm:col-span-6\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
136
if templ_7745c5c3_Err != nil {
137
return templ_7745c5c3_Err
138
}
139
+
var templ_7745c5c3_Var4 templ.SafeURL
140
+
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)))
141
+
if templ_7745c5c3_Err != nil {
142
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 43, Col: 194}
143
+
}
144
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
145
if templ_7745c5c3_Err != nil {
146
return templ_7745c5c3_Err
147
}
148
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">..</a></div>")
149
if templ_7745c5c3_Err != nil {
150
return templ_7745c5c3_Err
151
}
152
}
153
for _, fi := range rtcc.Tree {
154
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"sm:col-span-1 break-keep\">")
155
if templ_7745c5c3_Err != nil {
156
return templ_7745c5c3_Err
157
}
158
var templ_7745c5c3_Var5 string
159
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode)
160
if templ_7745c5c3_Err != nil {
161
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 46, Col: 50}
162
}
163
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
164
if templ_7745c5c3_Err != nil {
165
return templ_7745c5c3_Err
166
}
167
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div><div class=\"sm:col-span-1 text-right\">")
168
if templ_7745c5c3_Err != nil {
169
return templ_7745c5c3_Err
170
}
171
var templ_7745c5c3_Var6 string
172
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size)
173
if templ_7745c5c3_Err != nil {
174
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50}
175
}
176
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
177
if templ_7745c5c3_Err != nil {
178
return templ_7745c5c3_Err
179
}
180
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div><div class=\"sm:col-span-6 overflow-hidden text-ellipsis\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
181
if templ_7745c5c3_Err != nil {
182
return templ_7745c5c3_Err
183
}
184
+
var templ_7745c5c3_Var7 templ.SafeURL
185
+
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path)))
186
+
if templ_7745c5c3_Err != nil {
187
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 222}
188
+
}
189
+
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
190
if templ_7745c5c3_Err != nil {
191
return templ_7745c5c3_Err
192
}
193
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">")
194
if templ_7745c5c3_Err != nil {
195
return templ_7745c5c3_Err
196
}
197
var templ_7745c5c3_Var8 string
198
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir))
199
if templ_7745c5c3_Err != nil {
200
+
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 256}
201
}
202
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
203
if templ_7745c5c3_Err != nil {
204
return templ_7745c5c3_Err
205
}
206
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div>")
207
if templ_7745c5c3_Err != nil {
208
return templ_7745c5c3_Err
209
}
210
}
211
+
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>")
212
if templ_7745c5c3_Err != nil {
213
return templ_7745c5c3_Err
214
}
215
+
return nil
216
})
217
}
218
+
219
+
var _ = templruntime.GeneratedTemplate
+1
-1
internal/html/tailwind.config.js
+1
-1
internal/html/tailwind.config.js
+1
-1
internal/html/tailwind.go
+1
-1
internal/html/tailwind.go
···
5
6
func TailwindHandler(w http.ResponseWriter, r *http.Request) {
7
w.Header().Set("Content-Type", "text/css")
8
-
w.Write([]byte("/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:\"\"}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}.latte{--ctp-rosewater:220,138,120;--ctp-flamingo:221,120,120;--ctp-pink:234,118,203;--ctp-mauve:136,57,239;--ctp-red:210,15,57;--ctp-maroon:230,69,83;--ctp-peach:254,100,11;--ctp-yellow:223,142,29;--ctp-green:64,160,43;--ctp-teal:23,146,153;--ctp-sky:4,165,229;--ctp-sapphire:32,159,181;--ctp-blue:30,102,245;--ctp-lavender:114,135,253;--ctp-text:76,79,105;--ctp-subtext1:92,95,119;--ctp-subtext0:108,111,133;--ctp-overlay2:124,127,147;--ctp-overlay1:140,143,161;--ctp-overlay0:156,160,176;--ctp-surface2:172,176,190;--ctp-surface1:188,192,204;--ctp-surface0:204,208,218;--ctp-base:239,241,245;--ctp-mantle:230,233,239;--ctp-crust:220,224,232}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-7{grid-column:span 7/span 7}.col-span-8{grid-column:span 8/span 8}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.inline-block{display:inline-block}.inline{display:inline}.grid{display:grid}.h-5{height:1.25rem}.w-5{width:1.25rem}.max-w-7xl{max-width:80rem}.cursor-pointer{cursor:pointer}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1{row-gap:.25rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-pre{white-space:pre}.break-keep{word-break:keep-all}.rounded{border-radius:.25rem}.border{border-width:1px}.border-solid{border-style:solid}.border-rosewater{--tw-border-opacity:1;border-color:rgba(var(--ctp-rosewater),var(--tw-border-opacity))}.bg-base{--tw-bg-opacity:1;background-color:rgba(var(--ctp-base),var(--tw-bg-opacity))}.bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.bg-mantle{--tw-bg-opacity:1;background-color:rgba(var(--ctp-mantle),var(--tw-bg-opacity))}.stroke-mauve{stroke:rgb(var(--ctp-mauve))}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-0{padding-bottom:0}.pb-0\\.5{padding-bottom:.125rem}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-blue{--tw-text-opacity:1;color:rgba(var(--ctp-blue),var(--tw-text-opacity))}.text-mauve{--tw-text-opacity:1;color:rgba(var(--ctp-mauve),var(--tw-text-opacity))}.text-subtext0{--tw-text-opacity:1;color:rgba(var(--ctp-subtext0),var(--tw-text-opacity))}.text-subtext1{--tw-text-opacity:1;color:rgba(var(--ctp-subtext1),var(--tw-text-opacity))}.text-text{--tw-text-opacity:1;color:rgba(var(--ctp-text),var(--tw-text-opacity))}.text-text\\/80{color:rgba(var(--ctp-text),.8)}.underline{text-decoration-line:underline}.decoration-blue\\/50{text-decoration-color:rgba(var(--ctp-blue),.5)}.decoration-mauve\\/50{text-decoration-color:rgba(var(--ctp-mauve),.5)}.decoration-text\\/50{text-decoration-color:rgba(var(--ctp-text),.5)}.decoration-dashed{text-decoration-style:dashed}.markdown *{all:revert-layer;color:rgb(var(--ctp-text))}.markdown code,.markdown pre{background-color:rgb(var(--ctp-base))}.markdown a{color:rgb(var(--ctp-blue));text-decoration-line:underline;text-decoration-style:dashed}.markdown a:hover{text-decoration-style:solid}.markdown .chroma{border-radius:.25rem;padding:.75rem}.chroma *{background-color:rgb(var(--ctp-base))!important}.chroma table{border-spacing:5px 0!important}.chroma .lnt{color:rgb(var(--ctp-subtext1))!important}.chroma .lnt:focus,.chroma .lnt:target{color:rgb(var(--ctp-subtext0))!important}.chroma .line.active,.chroma .line.active *{background:rgb(var(--ctp-surface0))!important}.code>.chroma{overflow:scroll;border-radius:.25rem;padding:.75rem;font-size:.875rem;line-height:1.25rem}.chroma .line{overflow:scroll}.bg,.chroma{color:#4c4f69;background-color:#eff1f5}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#bcc0cc;background-color:#eff1f5}.chroma .err{color:#d20f39}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{color:#bcc0cc}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#8c8fa1}.chroma .line{display:flex}.chroma .k{color:#8839ef}.chroma .kc{color:#fe640b}.chroma .kd{color:#d20f39}.chroma .kn{color:#179299}.chroma .kp,.chroma .kr{color:#8839ef}.chroma .kt{color:#d20f39}.chroma .na{color:#1e66f5}.chroma .bp,.chroma .nb{color:#04a5e5}.chroma .nc,.chroma .no{color:#df8e1d}.chroma .nd{color:#1e66f5;font-weight:700}.chroma .ni{color:#179299}.chroma .ne{color:#fe640b}.chroma .fm,.chroma .nf{color:#1e66f5}.chroma .nl{color:#04a5e5}.chroma .nn,.chroma .py{color:#fe640b}.chroma .nt{color:#8839ef}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#dc8a78}.chroma .s{color:#40a02b}.chroma .sa{color:#d20f39}.chroma .sb,.chroma .sc{color:#40a02b}.chroma .dl{color:#1e66f5}.chroma .sd{color:#9ca0b0}.chroma .s2{color:#40a02b}.chroma .se{color:#1e66f5}.chroma .sh{color:#9ca0b0}.chroma .si,.chroma .sx{color:#40a02b}.chroma .sr{color:#179299}.chroma .s1,.chroma .ss{color:#40a02b}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fe640b}.chroma .o,.chroma .ow{color:#04a5e5;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#9ca0b0;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#d20f39;background-color:#ccd0da}.chroma .ge{font-style:italic}.chroma .gr{color:#d20f39}.chroma .gh{color:#fe640b;font-weight:700}.chroma .gi{color:#40a02b;background-color:#ccd0da}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fe640b}.chroma .gt{color:#d20f39}.chroma .gl{text-decoration:underline}@media (prefers-color-scheme:dark){.bg,.chroma{color:#cdd6f4;background-color:#1e1e2e}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#45475a;background-color:#1e1e2e}.chroma .err{color:#f38ba8}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{color:#45475a}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f849c}.chroma .line{display:flex}.chroma .k{color:#cba6f7}.chroma .kc{color:#fab387}.chroma .kd{color:#f38ba8}.chroma .kn{color:#94e2d5}.chroma .kp,.chroma .kr{color:#cba6f7}.chroma .kt{color:#f38ba8}.chroma .na{color:#89b4fa}.chroma .bp,.chroma .nb{color:#89dceb}.chroma .nc,.chroma .no{color:#f9e2af}.chroma .nd{color:#89b4fa;font-weight:700}.chroma .ni{color:#94e2d5}.chroma .ne{color:#fab387}.chroma .fm,.chroma .nf{color:#89b4fa}.chroma .nl{color:#89dceb}.chroma .nn,.chroma .py{color:#fab387}.chroma .nt{color:#cba6f7}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#f5e0dc}.chroma .s{color:#a6e3a1}.chroma .sa{color:#f38ba8}.chroma .sb,.chroma .sc{color:#a6e3a1}.chroma .dl{color:#89b4fa}.chroma .sd{color:#6c7086}.chroma .s2{color:#a6e3a1}.chroma .se{color:#89b4fa}.chroma .sh{color:#6c7086}.chroma .si,.chroma .sx{color:#a6e3a1}.chroma .sr{color:#94e2d5}.chroma .s1,.chroma .ss{color:#a6e3a1}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fab387}.chroma .o,.chroma .ow{color:#89dceb;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#6c7086;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#f38ba8;background-color:#313244}.chroma .ge{font-style:italic}.chroma .gr{color:#f38ba8}.chroma .gh{color:#fab387;font-weight:700}.chroma .gi{color:#a6e3a1;background-color:#313244}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fab387}.chroma .gt{color:#f38ba8}.chroma .gl{text-decoration:underline}.dark\\:mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}}.hover\\:decoration-solid:hover{text-decoration-style:solid}.focus\\:border-lavender:focus{--tw-border-opacity:1;border-color:rgba(var(--ctp-lavender),var(--tw-border-opacity))}.focus\\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}@media (prefers-color-scheme:dark){.dark\\:bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.dark\\:bg-base\\/95{background-color:rgba(var(--ctp-base),.95)}.dark\\:text-lavender{--tw-text-opacity:1;color:rgba(var(--ctp-lavender),var(--tw-text-opacity))}.dark\\:decoration-lavender\\/50{text-decoration-color:rgba(var(--ctp-lavender),.5)}}@media (min-width:640px){.sm\\:col-span-1{grid-column:span 1/span 1}.sm\\:col-span-2{grid-column:span 2/span 2}.sm\\:col-span-3{grid-column:span 3/span 3}.sm\\:col-span-4{grid-column:span 4/span 4}.sm\\:col-span-5{grid-column:span 5/span 5}.sm\\:col-span-6{grid-column:span 6/span 6}.sm\\:col-span-7{grid-column:span 7/span 7}.sm\\:mx-auto{margin-left:auto;margin-right:auto}.sm\\:mb-0{margin-bottom:0}.sm\\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}"))
9
}
···
5
6
func TailwindHandler(w http.ResponseWriter, r *http.Request) {
7
w.Header().Set("Content-Type", "text/css")
8
+
w.Write([]byte("/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:\"\"}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}.latte{--ctp-rosewater:220,138,120;--ctp-flamingo:221,120,120;--ctp-pink:234,118,203;--ctp-mauve:136,57,239;--ctp-red:210,15,57;--ctp-maroon:230,69,83;--ctp-peach:254,100,11;--ctp-yellow:223,142,29;--ctp-green:64,160,43;--ctp-teal:23,146,153;--ctp-sky:4,165,229;--ctp-sapphire:32,159,181;--ctp-blue:30,102,245;--ctp-lavender:114,135,253;--ctp-text:76,79,105;--ctp-subtext1:92,95,119;--ctp-subtext0:108,111,133;--ctp-overlay2:124,127,147;--ctp-overlay1:140,143,161;--ctp-overlay0:156,160,176;--ctp-surface2:172,176,190;--ctp-surface1:188,192,204;--ctp-surface0:204,208,218;--ctp-base:239,241,245;--ctp-mantle:230,233,239;--ctp-crust:220,224,232}.mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.start-1{inset-inline-start:.25rem}.top-0{top:0}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-7{grid-column:span 7/span 7}.col-span-8{grid-column:span 8/span 8}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.grid{display:grid}.hidden{display:none}.h-5{height:1.25rem}.w-5{width:1.25rem}.max-w-7xl{max-width:80rem}.cursor-pointer{cursor:pointer}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1{row-gap:.25rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-pre{white-space:pre}.break-keep{word-break:keep-all}.rounded{border-radius:.25rem}.border{border-width:1px}.border-solid{border-style:solid}.border-rosewater{--tw-border-opacity:1;border-color:rgba(var(--ctp-rosewater),var(--tw-border-opacity))}.bg-base{--tw-bg-opacity:1;background-color:rgba(var(--ctp-base),var(--tw-bg-opacity))}.bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.bg-mantle{--tw-bg-opacity:1;background-color:rgba(var(--ctp-mantle),var(--tw-bg-opacity))}.stroke-mauve{stroke:rgb(var(--ctp-mauve))}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-0{padding-bottom:0}.pb-0\\.5{padding-bottom:.125rem}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-blue{--tw-text-opacity:1;color:rgba(var(--ctp-blue),var(--tw-text-opacity))}.text-mauve{--tw-text-opacity:1;color:rgba(var(--ctp-mauve),var(--tw-text-opacity))}.text-subtext0{--tw-text-opacity:1;color:rgba(var(--ctp-subtext0),var(--tw-text-opacity))}.text-subtext1{--tw-text-opacity:1;color:rgba(var(--ctp-subtext1),var(--tw-text-opacity))}.text-text{--tw-text-opacity:1;color:rgba(var(--ctp-text),var(--tw-text-opacity))}.text-text\\/80{color:rgba(var(--ctp-text),.8)}.underline{text-decoration-line:underline}.decoration-blue\\/50{text-decoration-color:rgba(var(--ctp-blue),.5)}.decoration-mauve\\/50{text-decoration-color:rgba(var(--ctp-mauve),.5)}.decoration-text\\/50{text-decoration-color:rgba(var(--ctp-text),.5)}.decoration-dashed{text-decoration-style:dashed}.markdown *{all:revert-layer;color:rgb(var(--ctp-text))}.markdown code,.markdown pre{background-color:rgb(var(--ctp-base))}.markdown a{color:rgb(var(--ctp-blue));text-decoration-line:underline;text-decoration-style:dashed}.markdown a:hover{text-decoration-style:solid}.markdown .chroma{border-radius:.25rem;padding:.75rem}.chroma *{background-color:rgb(var(--ctp-base))!important}.chroma table{border-spacing:5px 0!important}.chroma .lnt{color:rgb(var(--ctp-subtext1))!important}.chroma .lnt:focus,.chroma .lnt:target{color:rgb(var(--ctp-subtext0))!important}.chroma .line.active,.chroma .line.active *{background:rgb(var(--ctp-surface0))!important}.code>.chroma{overflow:scroll;border-radius:.25rem;padding:.75rem;font-size:.875rem;line-height:1.25rem}.bg,.chroma{color:#4c4f69;background-color:#eff1f5}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#4c4f69;background-color:#bcc0cc}.chroma .err{color:#d20f39}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#bcc0cc}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#8c8fa1}.chroma .line{display:flex}.chroma .k{color:#8839ef}.chroma .kc{color:#fe640b}.chroma .kd{color:#d20f39}.chroma .kn{color:#179299}.chroma .kp,.chroma .kr{color:#8839ef}.chroma .kt{color:#d20f39}.chroma .na{color:#1e66f5}.chroma .bp,.chroma .nb{color:#04a5e5}.chroma .nc,.chroma .no{color:#df8e1d}.chroma .nd{color:#1e66f5;font-weight:700}.chroma .ni{color:#179299}.chroma .ne{color:#fe640b}.chroma .fm,.chroma .nf{color:#1e66f5}.chroma .nl{color:#04a5e5}.chroma .nn,.chroma .py{color:#fe640b}.chroma .nt{color:#8839ef}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#dc8a78}.chroma .s{color:#40a02b}.chroma .sa{color:#d20f39}.chroma .sb,.chroma .sc{color:#40a02b}.chroma .dl{color:#1e66f5}.chroma .sd{color:#9ca0b0}.chroma .s2{color:#40a02b}.chroma .se{color:#1e66f5}.chroma .sh{color:#9ca0b0}.chroma .si,.chroma .sx{color:#40a02b}.chroma .sr{color:#179299}.chroma .s1,.chroma .ss{color:#40a02b}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fe640b}.chroma .o,.chroma .ow{color:#04a5e5;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#9ca0b0;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#d20f39;background-color:#ccd0da}.chroma .ge{font-style:italic}.chroma .gr{color:#d20f39}.chroma .gh{color:#fe640b;font-weight:700}.chroma .gi{color:#40a02b;background-color:#ccd0da}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fe640b}.chroma .gt{color:#d20f39}.chroma .gl{text-decoration:underline}@media (prefers-color-scheme:dark){.bg,.chroma{color:#cdd6f4;background-color:#1e1e2e}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#cdd6f4;background-color:#45475a}.chroma .err{color:#f38ba8}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#45475a}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f849c}.chroma .line{display:flex}.chroma .k{color:#cba6f7}.chroma .kc{color:#fab387}.chroma .kd{color:#f38ba8}.chroma .kn{color:#94e2d5}.chroma .kp,.chroma .kr{color:#cba6f7}.chroma .kt{color:#f38ba8}.chroma .na{color:#89b4fa}.chroma .bp,.chroma .nb{color:#89dceb}.chroma .nc,.chroma .no{color:#f9e2af}.chroma .nd{color:#89b4fa;font-weight:700}.chroma .ni{color:#94e2d5}.chroma .ne{color:#fab387}.chroma .fm,.chroma .nf{color:#89b4fa}.chroma .nl{color:#89dceb}.chroma .nn,.chroma .py{color:#fab387}.chroma .nt{color:#cba6f7}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#f5e0dc}.chroma .s{color:#a6e3a1}.chroma .sa{color:#f38ba8}.chroma .sb,.chroma .sc{color:#a6e3a1}.chroma .dl{color:#89b4fa}.chroma .sd{color:#6c7086}.chroma .s2{color:#a6e3a1}.chroma .se{color:#89b4fa}.chroma .sh{color:#6c7086}.chroma .si,.chroma .sx{color:#a6e3a1}.chroma .sr{color:#94e2d5}.chroma .s1,.chroma .ss{color:#a6e3a1}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fab387}.chroma .o,.chroma .ow{color:#89dceb;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#6c7086;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#f38ba8;background-color:#313244}.chroma .ge{font-style:italic}.chroma .gr{color:#f38ba8}.chroma .gh{color:#fab387;font-weight:700}.chroma .gi{color:#a6e3a1;background-color:#313244}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fab387}.chroma .gt{color:#f38ba8}.chroma .gl{text-decoration:underline}.dark\\:mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}}.hover\\:bg-surface0:hover{--tw-bg-opacity:1;background-color:rgba(var(--ctp-surface0),var(--tw-bg-opacity))}.hover\\:decoration-solid:hover{text-decoration-style:solid}.focus\\:border-lavender:focus{--tw-border-opacity:1;border-color:rgba(var(--ctp-lavender),var(--tw-border-opacity))}.focus\\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}@media (prefers-color-scheme:dark){.dark\\:bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.dark\\:bg-base\\/95{background-color:rgba(var(--ctp-base),.95)}.dark\\:text-lavender{--tw-text-opacity:1;color:rgba(var(--ctp-lavender),var(--tw-text-opacity))}.dark\\:decoration-lavender\\/50{text-decoration-color:rgba(var(--ctp-lavender),.5)}}@media (min-width:640px){.sm\\:col-span-1{grid-column:span 1/span 1}.sm\\:col-span-2{grid-column:span 2/span 2}.sm\\:col-span-3{grid-column:span 3/span 3}.sm\\:col-span-5{grid-column:span 5/span 5}.sm\\:col-span-6{grid-column:span 6/span 6}.sm\\:col-span-7{grid-column:span 7/span 7}.sm\\:mx-auto{margin-left:auto;margin-right:auto}.sm\\:mb-0{margin-bottom:0}.sm\\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}"))
9
}
+12
-4
internal/http/http.go
+12
-4
internal/http/http.go
···
18
// Server is the container struct for the HTTP server
19
type Server struct {
20
port int
21
-
mux *chi.Mux
22
}
23
24
// ListenAndServe simply wraps http.ListenAndServe to contain the functionality here
25
func (s Server) ListenAndServe() error {
26
-
return http.ListenAndServe(fmt.Sprintf("localhost:%d", s.port), s.mux)
27
}
28
29
// Settings is the configuration for the HTTP server
···
34
Port int
35
RepoDir string
36
Profile Profile
37
}
38
39
// Profile is the index profile
···
101
r.Get("/tailwind.css", html.TailwindHandler)
102
})
103
104
-
return Server{mux: mux, port: settings.Port}
105
}
106
107
type repoHandler struct {
···
115
}
116
}
117
118
func (rh repoHandler) repoHeaderContext(repo *git.Repo, r *http.Request) html.RepoHeaderComponentContext {
119
ref := chi.URLParam(r, "ref")
120
if ref == "" {
···
125
Name: chi.URLParam(r, "repo"),
126
Ref: ref,
127
CloneURL: rh.s.CloneURL,
128
-
Tags: repo.Meta.Tags,
129
}
130
}
131
···
18
// Server is the container struct for the HTTP server
19
type Server struct {
20
port int
21
+
Mux *chi.Mux
22
}
23
24
// ListenAndServe simply wraps http.ListenAndServe to contain the functionality here
25
func (s Server) ListenAndServe() error {
26
+
return http.ListenAndServe(fmt.Sprintf("localhost:%d", s.port), s.Mux)
27
}
28
29
// Settings is the configuration for the HTTP server
···
34
Port int
35
RepoDir string
36
Profile Profile
37
+
ShowPrivate bool
38
}
39
40
// Profile is the index profile
···
102
r.Get("/tailwind.css", html.TailwindHandler)
103
})
104
105
+
return Server{Mux: mux, port: settings.Port}
106
}
107
108
type repoHandler struct {
···
116
}
117
}
118
119
+
func (rh repoHandler) repoBaseContext(repo *git.Repo) html.BaseContext {
120
+
return html.BaseContext{
121
+
Title: repo.Name(),
122
+
Description: repo.Meta.Description,
123
+
}
124
+
}
125
+
126
func (rh repoHandler) repoHeaderContext(repo *git.Repo, r *http.Request) html.RepoHeaderComponentContext {
127
ref := chi.URLParam(r, "ref")
128
if ref == "" {
···
133
Name: chi.URLParam(r, "repo"),
134
Ref: ref,
135
CloneURL: rh.s.CloneURL,
136
+
Tags: repo.Meta.Tags.Slice(),
137
}
138
}
139
+2
-3
internal/http/httperr/httperr.go
+2
-3
internal/http/httperr/httperr.go
+122
internal/http/httperr/httperr_test.go
+122
internal/http/httperr/httperr_test.go
···
···
1
+
package httperr_test
2
+
3
+
import (
4
+
"errors"
5
+
"net/http"
6
+
"net/http/httptest"
7
+
"testing"
8
+
9
+
"github.com/alecthomas/assert/v2"
10
+
"go.jolheiser.com/ugit/internal/http/httperr"
11
+
)
12
+
13
+
func successHandler(w http.ResponseWriter, r *http.Request) error {
14
+
w.WriteHeader(http.StatusOK)
15
+
return nil
16
+
}
17
+
18
+
func errorHandler(w http.ResponseWriter, r *http.Request) error {
19
+
return errors.New("test error")
20
+
}
21
+
22
+
func statusErrorHandler(status int) func(w http.ResponseWriter, r *http.Request) error {
23
+
return func(w http.ResponseWriter, r *http.Request) error {
24
+
return httperr.Status(errors.New("test error"), status)
25
+
}
26
+
}
27
+
28
+
func TestHandler_Success(t *testing.T) {
29
+
handler := httperr.Handler(successHandler)
30
+
31
+
req := httptest.NewRequest("GET", "/", nil)
32
+
recorder := httptest.NewRecorder()
33
+
34
+
handler.ServeHTTP(recorder, req)
35
+
36
+
assert.Equal(t, http.StatusOK, recorder.Code)
37
+
}
38
+
39
+
func TestHandler_Error(t *testing.T) {
40
+
handler := httperr.Handler(errorHandler)
41
+
42
+
req := httptest.NewRequest("GET", "/", nil)
43
+
recorder := httptest.NewRecorder()
44
+
45
+
handler.ServeHTTP(recorder, req)
46
+
47
+
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
48
+
}
49
+
50
+
func TestHandler_StatusError(t *testing.T) {
51
+
testCases := []struct {
52
+
name string
53
+
status int
54
+
expectedStatus int
55
+
}{
56
+
{
57
+
name: "not found",
58
+
status: http.StatusNotFound,
59
+
expectedStatus: http.StatusNotFound,
60
+
},
61
+
{
62
+
name: "bad request",
63
+
status: http.StatusBadRequest,
64
+
expectedStatus: http.StatusBadRequest,
65
+
},
66
+
{
67
+
name: "unauthorized",
68
+
status: http.StatusUnauthorized,
69
+
expectedStatus: http.StatusUnauthorized,
70
+
},
71
+
}
72
+
73
+
for _, tc := range testCases {
74
+
t.Run(tc.name, func(t *testing.T) {
75
+
handler := httperr.Handler(statusErrorHandler(tc.status))
76
+
77
+
req := httptest.NewRequest("GET", "/", nil)
78
+
recorder := httptest.NewRecorder()
79
+
80
+
handler.ServeHTTP(recorder, req)
81
+
82
+
assert.Equal(t, tc.expectedStatus, recorder.Code)
83
+
})
84
+
}
85
+
}
86
+
87
+
type unwrapper interface {
88
+
Unwrap() error
89
+
}
90
+
91
+
func TestError(t *testing.T) {
92
+
originalErr := errors.New("original error")
93
+
httpErr := httperr.Error(originalErr)
94
+
95
+
assert.Equal(t, originalErr.Error(), httpErr.Error())
96
+
97
+
unwrapper, ok := any(httpErr).(unwrapper)
98
+
assert.True(t, ok)
99
+
assert.Equal(t, originalErr, unwrapper.Unwrap())
100
+
}
101
+
102
+
func TestStatus(t *testing.T) {
103
+
originalErr := errors.New("original error")
104
+
httpErr := httperr.Status(originalErr, http.StatusNotFound)
105
+
106
+
assert.Equal(t, originalErr.Error(), httpErr.Error())
107
+
108
+
unwrapper, ok := any(httpErr).(unwrapper)
109
+
assert.True(t, ok)
110
+
assert.Equal(t, originalErr, unwrapper.Unwrap())
111
+
112
+
handler := httperr.Handler(func(w http.ResponseWriter, r *http.Request) error {
113
+
return httpErr
114
+
})
115
+
116
+
req := httptest.NewRequest("GET", "/", nil)
117
+
recorder := httptest.NewRecorder()
118
+
119
+
handler.ServeHTTP(recorder, req)
120
+
121
+
assert.Equal(t, http.StatusNotFound, recorder.Code)
122
+
}
+6
-3
internal/http/index.go
+6
-3
internal/http/index.go
···
3
import (
4
"net/http"
5
"os"
6
"sort"
7
"strings"
8
"time"
···
30
return httperr.Error(err)
31
}
32
if repo.Meta.Private {
33
+
if !rh.s.ShowPrivate {
34
+
continue
35
+
}
36
+
repo.Meta.Tags.Add("private")
37
}
38
+
39
+
if tagFilter != "" && !repo.Meta.Tags.Contains(strings.ToLower(tagFilter)) {
40
continue
41
}
42
repos = append(repos, repo)
+4
-1
internal/http/middleware.go
+4
-1
internal/http/middleware.go
···
27
return httperr.Status(err, httpErr)
28
}
29
if repo.Meta.Private {
30
+
if !rh.s.ShowPrivate {
31
+
return httperr.Status(errors.New("could not get git repo"), http.StatusNotFound)
32
+
}
33
+
repo.Meta.Tags.Add("private")
34
}
35
r = r.WithContext(context.WithValue(r.Context(), repoCtxKey, repo))
36
next.ServeHTTP(w, r)
+18
-10
internal/http/repo.go
+18
-10
internal/http/repo.go
···
48
back = filepath.Dir(path)
49
}
50
if err := html.RepoTree(html.RepoTreeContext{
51
-
Description: repo.Meta.Description,
52
-
BaseContext: rh.baseContext(),
53
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
54
RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path),
55
RepoTreeComponentContext: html.RepoTreeComponentContext{
···
88
}
89
90
var buf bytes.Buffer
91
-
if err := markup.Code.Convert([]byte(content), filepath.Base(path), &buf); err != nil {
92
return httperr.Error(err)
93
}
94
95
if err := html.RepoFile(html.RepoFileContext{
96
-
BaseContext: rh.baseContext(),
97
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
98
RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path),
99
Code: buf.String(),
100
}).Render(r.Context(), w); err != nil {
101
return httperr.Error(err)
102
}
···
118
}
119
120
if err := html.RepoRefs(html.RepoRefsContext{
121
-
BaseContext: rh.baseContext(),
122
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
123
Branches: branches,
124
Tags: tags,
···
138
}
139
140
if err := html.RepoLog(html.RepoLogContext{
141
-
BaseContext: rh.baseContext(),
142
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
143
Commits: commits,
144
}).Render(r.Context(), w); err != nil {
···
158
159
for idx, p := range commit.Files {
160
var patch bytes.Buffer
161
-
if err := markup.Code.Basic([]byte(p.Patch), "commit.patch", &patch); err != nil {
162
return httperr.Error(err)
163
}
164
commit.Files[idx].Patch = patch.String()
165
}
166
167
if err := html.RepoCommit(html.RepoCommitContext{
168
-
BaseContext: rh.baseContext(),
169
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
170
Commit: commit,
171
}).Render(r.Context(), w); err != nil {
···
206
}
207
results[idx].Content = buf.String()
208
}
209
-
210
}
211
212
if err := html.RepoSearch(html.SearchContext{
213
-
BaseContext: rh.baseContext(),
214
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
215
Results: results,
216
}).Render(r.Context(), w); err != nil {
···
48
back = filepath.Dir(path)
49
}
50
if err := html.RepoTree(html.RepoTreeContext{
51
+
BaseContext: rh.repoBaseContext(repo),
52
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
53
RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path),
54
RepoTreeComponentContext: html.RepoTreeComponentContext{
···
87
}
88
89
var buf bytes.Buffer
90
+
if err := markup.Convert([]byte(content), filepath.Base(path), "L", &buf); err != nil {
91
return httperr.Error(err)
92
}
93
94
+
commit := ref
95
+
if len(ref) < 40 {
96
+
commitObj, err := repo.GetCommitFromRef(ref)
97
+
if err == nil {
98
+
commit = commitObj.Hash.String()
99
+
}
100
+
}
101
+
102
if err := html.RepoFile(html.RepoFileContext{
103
+
BaseContext: rh.repoBaseContext(repo),
104
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
105
RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path),
106
Code: buf.String(),
107
+
Commit: commit,
108
+
Path: path,
109
}).Render(r.Context(), w); err != nil {
110
return httperr.Error(err)
111
}
···
127
}
128
129
if err := html.RepoRefs(html.RepoRefsContext{
130
+
BaseContext: rh.repoBaseContext(repo),
131
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
132
Branches: branches,
133
Tags: tags,
···
147
}
148
149
if err := html.RepoLog(html.RepoLogContext{
150
+
BaseContext: rh.repoBaseContext(repo),
151
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
152
Commits: commits,
153
}).Render(r.Context(), w); err != nil {
···
167
168
for idx, p := range commit.Files {
169
var patch bytes.Buffer
170
+
if err := markup.Convert([]byte(p.Patch), "commit.patch", p.Path()+"-L", &patch); err != nil {
171
return httperr.Error(err)
172
}
173
commit.Files[idx].Patch = patch.String()
174
}
175
176
if err := html.RepoCommit(html.RepoCommitContext{
177
+
BaseContext: rh.repoBaseContext(repo),
178
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
179
Commit: commit,
180
}).Render(r.Context(), w); err != nil {
···
215
}
216
results[idx].Content = buf.String()
217
}
218
}
219
220
if err := html.RepoSearch(html.SearchContext{
221
+
BaseContext: rh.repoBaseContext(repo),
222
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
223
Results: results,
224
}).Render(r.Context(), w); err != nil {
-37
internal/ssh/form.go
-37
internal/ssh/form.go
···
1
-
package ssh
2
-
3
-
import (
4
-
"strings"
5
-
6
-
"github.com/charmbracelet/huh"
7
-
"go.jolheiser.com/ugit/internal/git"
8
-
)
9
-
10
-
type stringSliceAccessor []string
11
-
12
-
func (s stringSliceAccessor) Get() string {
13
-
return strings.Join(s, "\n")
14
-
}
15
-
16
-
func (s stringSliceAccessor) Set(value string) {
17
-
s = strings.Split(value, "\n")
18
-
}
19
-
20
-
func newForm(meta git.RepoMeta) *huh.Form {
21
-
return huh.NewForm(
22
-
huh.NewGroup(
23
-
huh.NewText().
24
-
Title("Description").
25
-
Value(&meta.Description),
26
-
huh.NewConfirm().
27
-
Title("Visibility").
28
-
Affirmative("Public").
29
-
Negative("Private").
30
-
Value(&meta.Private),
31
-
huh.NewText().
32
-
Title("Tags").
33
-
Description("One per line").
34
-
Accessor(stringSliceAccessor(meta.Tags)),
35
-
),
36
-
)
37
-
}
···
+3
-3
internal/ssh/ssh.go
+3
-3
internal/ssh/ssh.go
···
2
3
import (
4
"fmt"
5
6
-
"github.com/charmbracelet/log"
7
"github.com/charmbracelet/ssh"
8
"github.com/charmbracelet/wish"
9
"github.com/charmbracelet/wish/logging"
···
42
func (a hooks) Fetch(_ string, _ ssh.PublicKey) {}
43
44
var (
45
-
DefaultLogger logging.Logger = log.StandardLog()
46
NoopLogger logging.Logger = noopLogger{}
47
)
48
49
type noopLogger struct{}
50
51
-
func (n noopLogger) Printf(format string, v ...interface{}) {}
···
2
3
import (
4
"fmt"
5
+
"log"
6
7
"github.com/charmbracelet/ssh"
8
"github.com/charmbracelet/wish"
9
"github.com/charmbracelet/wish/logging"
···
42
func (a hooks) Fetch(_ string, _ ssh.PublicKey) {}
43
44
var (
45
+
DefaultLogger logging.Logger = log.Default()
46
NoopLogger logging.Logger = noopLogger{}
47
)
48
49
type noopLogger struct{}
50
51
+
func (n noopLogger) Printf(format string, v ...any) {}
+4
-14
internal/ssh/wish.go
+4
-14
internal/ssh/wish.go
···
5
"errors"
6
"fmt"
7
"io/fs"
8
"os"
9
"path/filepath"
10
"strings"
···
12
13
"go.jolheiser.com/ugit/internal/git"
14
15
-
"github.com/charmbracelet/log"
16
"github.com/charmbracelet/ssh"
17
"github.com/charmbracelet/wish"
18
)
···
91
if errors.Is(err, ErrInvalidRepo) {
92
Fatal(s, ErrInvalidRepo)
93
}
94
-
log.Error("unknown git error", "error", err)
95
Fatal(s, ErrSystemMalfunction)
96
}
97
gh.Fetch(repo, pk)
···
103
if len(cmd) == 0 {
104
des, err := os.ReadDir(repoDir)
105
if err != nil && err != fs.ErrNotExist {
106
-
log.Error("invalid repository", "error", err)
107
}
108
tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0)
109
for _, de := range des {
···
122
}
123
tw.Flush()
124
}
125
-
126
-
// Edit repo
127
-
if len(cmd) == 1 {
128
-
repo, err := git.NewRepo(cmd[0])
129
-
if err != nil {
130
-
Fatal(s, ErrInvalidRepo)
131
-
}
132
-
133
-
}
134
-
135
sh(s)
136
}
137
}
···
178
}
179
180
// Fatal prints to the session's STDOUT as a git response and exit 1.
181
-
func Fatal(s ssh.Session, v ...interface{}) {
182
msg := fmt.Sprint(v...)
183
// hex length includes 4 byte length prefix and ending newline
184
pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg)
···
5
"errors"
6
"fmt"
7
"io/fs"
8
+
"log/slog"
9
"os"
10
"path/filepath"
11
"strings"
···
13
14
"go.jolheiser.com/ugit/internal/git"
15
16
"github.com/charmbracelet/ssh"
17
"github.com/charmbracelet/wish"
18
)
···
91
if errors.Is(err, ErrInvalidRepo) {
92
Fatal(s, ErrInvalidRepo)
93
}
94
+
slog.Error("unknown git error", "error", err)
95
Fatal(s, ErrSystemMalfunction)
96
}
97
gh.Fetch(repo, pk)
···
103
if len(cmd) == 0 {
104
des, err := os.ReadDir(repoDir)
105
if err != nil && err != fs.ErrNotExist {
106
+
slog.Error("invalid repository", "error", err)
107
}
108
tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0)
109
for _, de := range des {
···
122
}
123
tw.Flush()
124
}
125
sh(s)
126
}
127
}
···
168
}
169
170
// Fatal prints to the session's STDOUT as a git response and exit 1.
171
+
func Fatal(s ssh.Session, v ...any) {
172
msg := fmt.Sprint(v...)
173
// hex length includes 4 byte length prefix and ending newline
174
pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg)
+10
nix/default.nix
+10
nix/default.nix
+228
nix/module.nix
+228
nix/module.nix
···
···
1
+
{
2
+
pkgs,
3
+
lib,
4
+
config,
5
+
...
6
+
}:
7
+
let
8
+
cfg = config.services.ugit;
9
+
pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; };
10
+
yamlFormat = pkgs.formats.yaml { };
11
+
instanceOptions =
12
+
{ name, config, ... }:
13
+
let
14
+
inherit (lib) mkEnableOption mkOption types;
15
+
baseDir = "/var/lib/ugit-${name}";
16
+
in
17
+
{
18
+
options = {
19
+
enable = mkEnableOption "Enable ugit";
20
+
21
+
package = mkOption {
22
+
type = types.package;
23
+
description = "ugit package to use";
24
+
default = pkg;
25
+
};
26
+
27
+
homeDir = mkOption {
28
+
type = types.str;
29
+
description = "ugit home directory";
30
+
default = baseDir;
31
+
};
32
+
33
+
repoDir = mkOption {
34
+
type = types.str;
35
+
description = "where ugit stores repositories";
36
+
default = "${baseDir}/repos";
37
+
};
38
+
39
+
authorizedKeys = mkOption {
40
+
type = types.listOf types.str;
41
+
description = "list of keys to use for authorized_keys";
42
+
default = [ ];
43
+
};
44
+
45
+
authorizedKeysFile = mkOption {
46
+
type = types.str;
47
+
description = "path to authorized_keys file ugit uses for auth";
48
+
default = "${baseDir}/authorized_keys";
49
+
};
50
+
51
+
hostKeyFile = mkOption {
52
+
type = types.str;
53
+
description = "path to host key file (will be created if it doesn't exist)";
54
+
default = "${baseDir}/ugit_ed25519";
55
+
};
56
+
57
+
config = mkOption {
58
+
type = types.attrs;
59
+
default = { };
60
+
description = "config.yaml contents";
61
+
};
62
+
63
+
user = mkOption {
64
+
type = types.str;
65
+
default = "ugit-${name}";
66
+
description = "User account under which ugit runs";
67
+
};
68
+
69
+
group = mkOption {
70
+
type = types.str;
71
+
default = "ugit-${name}";
72
+
description = "Group account under which ugit runs";
73
+
};
74
+
75
+
hooks = mkOption {
76
+
type = types.listOf (
77
+
types.submodule {
78
+
options = {
79
+
name = mkOption {
80
+
type = types.str;
81
+
description = "Hook name";
82
+
};
83
+
content = mkOption {
84
+
type = types.str;
85
+
description = "Hook contents";
86
+
};
87
+
};
88
+
}
89
+
);
90
+
description = "A list of pre-receive hooks to run";
91
+
default = [ ];
92
+
};
93
+
};
94
+
};
95
+
in
96
+
{
97
+
options = {
98
+
services.ugit = lib.mkOption {
99
+
type = lib.types.attrsOf (lib.types.submodule instanceOptions);
100
+
default = { };
101
+
description = "Attribute set of ugit instances";
102
+
};
103
+
};
104
+
config = lib.mkIf (cfg != { }) {
105
+
users.users = lib.mapAttrs' (
106
+
name: instanceCfg:
107
+
lib.nameValuePair instanceCfg.user {
108
+
home = instanceCfg.homeDir;
109
+
createHome = true;
110
+
group = instanceCfg.group;
111
+
isSystemUser = true;
112
+
isNormalUser = false;
113
+
description = "user for ugit ${name} service";
114
+
}
115
+
) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg);
116
+
117
+
users.groups = lib.mapAttrs' (name: instanceCfg: lib.nameValuePair instanceCfg.group { }) (
118
+
lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg
119
+
);
120
+
121
+
systemd.services = lib.foldl' (
122
+
acc: name:
123
+
let
124
+
instanceCfg = cfg.${name};
125
+
in
126
+
lib.recursiveUpdate acc (
127
+
lib.optionalAttrs instanceCfg.enable {
128
+
"ugit-${name}" = {
129
+
enable = true;
130
+
description = "ugit instance ${name}";
131
+
wantedBy = [ "multi-user.target" ];
132
+
after = [ "network.target" ];
133
+
path = [
134
+
instanceCfg.package
135
+
pkgs.git
136
+
pkgs.bash
137
+
];
138
+
serviceConfig = {
139
+
User = instanceCfg.user;
140
+
Group = instanceCfg.group;
141
+
Restart = "always";
142
+
RestartSec = "15";
143
+
WorkingDirectory = instanceCfg.homeDir;
144
+
ReadWritePaths = [ instanceCfg.homeDir ];
145
+
CapabilityBoundingSet = "";
146
+
NoNewPrivileges = true;
147
+
ProtectSystem = "strict";
148
+
ProtectHome = true;
149
+
PrivateTmp = true;
150
+
PrivateDevices = true;
151
+
PrivateUsers = true;
152
+
ProtectHostname = true;
153
+
ProtectClock = true;
154
+
ProtectKernelTunables = true;
155
+
ProtectKernelModules = true;
156
+
ProtectKernelLogs = true;
157
+
ProtectControlGroups = true;
158
+
RestrictAddressFamilies = [
159
+
"AF_UNIX"
160
+
"AF_INET"
161
+
"AF_INET6"
162
+
];
163
+
RestrictNamespaces = true;
164
+
LockPersonality = true;
165
+
MemoryDenyWriteExecute = true;
166
+
RestrictRealtime = true;
167
+
RestrictSUIDSGID = true;
168
+
RemoveIPC = true;
169
+
PrivateMounts = true;
170
+
SystemCallArchitectures = "native";
171
+
ExecStart =
172
+
let
173
+
configFile = pkgs.writeText "ugit-${name}.yaml" (
174
+
builtins.readFile (yamlFormat.generate "ugit-${name}-yaml" instanceCfg.config)
175
+
);
176
+
authorizedKeysFile = pkgs.writeText "ugit_${name}_keys" (
177
+
builtins.concatStringsSep "\n" instanceCfg.authorizedKeys
178
+
);
179
+
180
+
authorizedKeysPath =
181
+
if (builtins.length instanceCfg.authorizedKeys) > 0 then
182
+
authorizedKeysFile
183
+
else
184
+
instanceCfg.authorizedKeysFile;
185
+
args = [
186
+
"--config=${configFile}"
187
+
"--repo-dir=${instanceCfg.repoDir}"
188
+
"--ssh.authorized-keys=${authorizedKeysPath}"
189
+
"--ssh.host-key=${instanceCfg.hostKeyFile}"
190
+
];
191
+
in
192
+
"${instanceCfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
193
+
};
194
+
};
195
+
196
+
"ugit-${name}-hooks" = {
197
+
description = "Setup hooks for ugit instance ${name}";
198
+
wantedBy = [ "multi-user.target" ];
199
+
after = [ "ugit-${name}.service" ];
200
+
requires = [ "ugit-${name}.service" ];
201
+
serviceConfig = {
202
+
Type = "oneshot";
203
+
RemainAfterExit = true;
204
+
User = instanceCfg.user;
205
+
Group = instanceCfg.group;
206
+
ExecStart =
207
+
let
208
+
hookDir = "${instanceCfg.repoDir}/hooks/pre-receive.d";
209
+
mkHookScript =
210
+
hook:
211
+
let
212
+
script = pkgs.writeShellScript "ugit-${name}-${hook.name}" hook.content;
213
+
in
214
+
''
215
+
mkdir -p ${hookDir}
216
+
ln -sf ${script} ${hookDir}/${hook.name}
217
+
'';
218
+
in
219
+
pkgs.writeShellScript "ugit-${name}-hooks-setup" ''
220
+
${builtins.concatStringsSep "\n" (map mkHookScript instanceCfg.hooks)}
221
+
'';
222
+
};
223
+
};
224
+
}
225
+
)
226
+
) { } (builtins.attrNames cfg);
227
+
};
228
+
}
+32
nix/pkg.nix
+32
nix/pkg.nix
···
···
1
+
{
2
+
pkgs ? import <nixpkgs> { },
3
+
}:
4
+
let
5
+
name = "ugitd";
6
+
in
7
+
pkgs.buildGoModule {
8
+
pname = name;
9
+
version = "main";
10
+
src = pkgs.nix-gitignore.gitignoreSource [ ] (
11
+
builtins.path {
12
+
inherit name;
13
+
path = ../.;
14
+
}
15
+
);
16
+
subPackages = [
17
+
"cmd/ugitd"
18
+
];
19
+
vendorHash = pkgs.lib.fileContents ../go.mod.sri;
20
+
env.CGO_ENABLED = 0;
21
+
flags = [ "-trimpath" ];
22
+
ldflags = [
23
+
"-s"
24
+
"-w"
25
+
"-extldflags -static"
26
+
];
27
+
meta = {
28
+
description = "Minimal git server";
29
+
homepage = "https://git.jolheiser.com/ugit";
30
+
mainProgram = "ugitd";
31
+
};
32
+
}
+84
nix/vm.nix
+84
nix/vm.nix
···
···
1
+
{ pkgs, ... }:
2
+
let
3
+
privKey = ''
4
+
-----BEGIN OPENSSH PRIVATE KEY-----
5
+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
6
+
QyNTUxOQAAACBIpmLtcHhECei1ls6s0kKUehjpRCP9yel/c5YCIb5DpQAAAIgAYtkzAGLZ
7
+
MwAAAAtzc2gtZWQyNTUxOQAAACBIpmLtcHhECei1ls6s0kKUehjpRCP9yel/c5YCIb5DpQ
8
+
AAAEDFY3M69VfnFbyE67r3l4lDcf5eht5qgNemE9xtMhRkBkimYu1weEQJ6LWWzqzSQpR6
9
+
GOlEI/3J6X9zlgIhvkOlAAAAAAECAwQF
10
+
-----END OPENSSH PRIVATE KEY-----
11
+
'';
12
+
pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEimYu1weEQJ6LWWzqzSQpR6GOlEI/3J6X9zlgIhvkOl";
13
+
sshConfig = ''
14
+
Host ugit
15
+
HostName localhost
16
+
Port 8448
17
+
User ugit
18
+
IdentityFile ~/.ssh/vm
19
+
IdentitiesOnly yes
20
+
'';
21
+
in
22
+
{
23
+
imports = [ ./module.nix ];
24
+
environment.systemPackages = with pkgs; [ git ];
25
+
services.getty.autologinUser = "root";
26
+
services.openssh.enable = true;
27
+
services.ugit.vm = {
28
+
enable = true;
29
+
authorizedKeys = [ pubKey ];
30
+
hooks = [
31
+
{
32
+
name = "pre-receive";
33
+
content = ''
34
+
echo "Pre-receive hook executed"
35
+
'';
36
+
}
37
+
];
38
+
};
39
+
systemd.services."setup-vm" = {
40
+
wantedBy = [ "multi-user.target" ];
41
+
after = [ "ugit-vm.service" ];
42
+
path = with pkgs; [
43
+
git
44
+
];
45
+
serviceConfig = {
46
+
Type = "oneshot";
47
+
RemainAfterExit = true;
48
+
User = "root";
49
+
Group = "root";
50
+
ExecStart =
51
+
let
52
+
privSSH = pkgs.writeText "vm-privkey" privKey;
53
+
sshConfigFile = pkgs.writeText "vm-sshconfig" sshConfig;
54
+
in
55
+
pkgs.writeShellScript "setup-vm-script" ''
56
+
# Hack to let ugit start up and generate its SSH keypair
57
+
sleep 3
58
+
59
+
# Set up git
60
+
git config --global user.name "NixUser"
61
+
git config --global user.email "nixuser@example.com"
62
+
git config --global init.defaultBranch main
63
+
git config --global push.autoSetupRemote true
64
+
65
+
# Set up SSH files
66
+
mkdir ~/.ssh
67
+
ln -sf ${sshConfigFile} ~/.ssh/config
68
+
cp ${privSSH} ~/.ssh/vm
69
+
chmod 600 ~/.ssh/vm
70
+
echo "[localhost]:8448 $(cat /var/lib/ugit-vm/ugit_ed25519.pub)" > ~/.ssh/known_hosts
71
+
72
+
# Stage some git activity
73
+
mkdir ~/repo
74
+
cd ~/repo
75
+
git init
76
+
git remote add origin ugit:repo.git
77
+
touch README.md
78
+
git add README.md
79
+
git commit -m "Test"
80
+
'';
81
+
};
82
+
};
83
+
84
+
}