Mirror of https://git.jolheiser.com/ugit

Compare changes

Choose any two refs to compare.

+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
+2
.gitignore
··· 1 1 /ugit* 2 2 .ssh/ 3 3 .ugit/ 4 + .tsnet/ 5 + *.qcow2
-5
.helix/languages.toml
··· 1 - [[language]] 2 - name = "templ" 3 - language-id = "html" 4 - language-servers = ["templ", "vscode-html-language-server", "tailwindcss-ls"] 5 -
+4 -4
README.md
··· 2 2 <picture> 3 3 <img alt="ugit logo" width="250" src="./assets/ugit.svg" /> 4 4 </picture> 5 - <h3 align="center">ugit</h3> 5 + <h3 align="center">ยตgit</h3> 6 6 </p> 7 7 8 8 Minimal git server 9 9 10 - ugit allows cloning via HTTPS/SSH, but can only be pushed to via SSH. 10 + ยตgit allows cloning via HTTPS/SSH, but can only be pushed to via SSH. 11 11 12 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). 13 + If you wish to collaborate, please send me patches via [git-pr](https://pr.jolheiser.com/repos/ugit). 14 14 15 - Currently all HTML is allowed in markdown, ugit is intended to be run by/for a trusted user. 15 + Currently all HTML is allowed in markdown, ยตgit is intended to be run by/for a trusted user. 16 16 17 17 ## Getting your public SSH keys from another forge 18 18
+1 -1
assets/ugit.svg
··· 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 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> 3 + <title>ยตgit icon</title> 4 4 <rect fill="none" x="1" y="1" rx="1" ry="1" width="22" height="22"></rect> 5 5 <ellipse cx="6" cy="6" rx="2" ry="2"></ellipse> 6 6 <ellipse cx="18" cy="6" rx="2" ry="2"></ellipse>
+69
cmd/ugitd/args.cue
··· 1 + import "strings" 2 + 3 + // Schema 4 + #Port: int & >0 & <65536 5 + #Link: string & strings.Contains(",") 6 + 7 + #Config: { 8 + "repo-dir": string 9 + "show-private": bool 10 + ssh: { 11 + enable: bool 12 + "authorized-keys": string 13 + "clone-url": string 14 + port: #Port 15 + "host-key": string 16 + } 17 + http: { 18 + enable: bool 19 + "clone-url": string 20 + port: #Port 21 + } 22 + meta: { 23 + title: string 24 + description: string 25 + } 26 + profile?: { 27 + username?: string 28 + email?: string 29 + links?: [...#Link] 30 + } 31 + log: { 32 + json: bool 33 + level: "debug" | "info" | "warn" | "warning" | "error" 34 + } 35 + 36 + // Constraints 37 + if ssh.port == http.port { 38 + error("ssh.port and http.port cannot be the same") 39 + } 40 + } 41 + 42 + // Defaults 43 + #Config: { 44 + "repo-dir": ".ugit" 45 + "show-private": false 46 + ssh: { 47 + enable: true 48 + "authorized-keys": ".ssh/authorized_keys" 49 + "clone-url": "ssh://localhost:8448" 50 + port: 8448 51 + "host-key": ".ssh/ugit_ed25519" 52 + } 53 + http: { 54 + enable: true 55 + "clone-url": "http://localhost:8449" 56 + port: 8449 57 + } 58 + meta: { 59 + title: "uGit" 60 + description: "Minimal git server" 61 + } 62 + log: { 63 + json: false 64 + level: "info" 65 + } 66 + } 67 + 68 + // Apply schema 69 + #Config
+39 -15
cmd/ugitd/args.go
··· 1 1 package main 2 2 3 3 import ( 4 + _ "embed" 4 5 "flag" 5 6 "fmt" 7 + "log/slog" 6 8 "strings" 7 9 8 - "github.com/charmbracelet/log" 9 10 "github.com/peterbourgon/ff/v3" 10 - "github.com/peterbourgon/ff/v3/ffyaml" 11 + "go.jolheiser.com/ffcue" 11 12 ) 12 13 14 + //go:embed args.cue 15 + var schema string 16 + 13 17 type cliArgs struct { 14 - RepoDir string 15 - SSH sshArgs 16 - HTTP httpArgs 17 - Meta metaArgs 18 - Profile profileArgs 19 - Log logArgs 18 + RepoDir string 19 + SSH sshArgs 20 + HTTP httpArgs 21 + Meta metaArgs 22 + Profile profileArgs 23 + Log logArgs 24 + ShowPrivate bool 20 25 } 21 26 22 27 type sshArgs struct { 28 + Enable bool 23 29 AuthorizedKeys string 24 30 CloneURL string 25 31 Port int ··· 27 33 } 28 34 29 35 type httpArgs struct { 36 + Enable bool 30 37 CloneURL string 31 38 Port int 32 39 } ··· 48 55 } 49 56 50 57 type logArgs struct { 51 - Level log.Level 58 + Level slog.Level 52 59 JSON bool 53 60 } 54 61 55 62 func parseArgs(args []string) (c cliArgs, e error) { 56 63 fs := flag.NewFlagSet("ugitd", flag.ContinueOnError) 57 - fs.String("config", "ugit.yaml", "Path to config file") 64 + fs.String("config", "ugit.cue", "Path to config file") 58 65 59 66 c = cliArgs{ 60 67 RepoDir: ".ugit", 61 68 SSH: sshArgs{ 69 + Enable: true, 62 70 AuthorizedKeys: ".ssh/authorized_keys", 63 71 CloneURL: "ssh://localhost:8448", 64 72 Port: 8448, 65 73 HostKey: ".ssh/ugit_ed25519", 66 74 }, 67 75 HTTP: httpArgs{ 76 + Enable: true, 68 77 CloneURL: "http://localhost:8449", 69 78 Port: 8449, 70 79 }, ··· 73 82 Description: "Minimal git server", 74 83 }, 75 84 Log: logArgs{ 76 - Level: log.InfoLevel, 85 + Level: slog.LevelError, 77 86 }, 78 87 } 79 88 80 89 fs.Func("log.level", "Logging level", func(s string) error { 81 - lvl, err := log.ParseLevel(s) 82 - if err != nil { 83 - return err 90 + var lvl slog.Level 91 + switch strings.ToLower(s) { 92 + case "debug": 93 + lvl = slog.LevelDebug 94 + case "info": 95 + lvl = slog.LevelInfo 96 + case "warn", "warning": 97 + lvl = slog.LevelWarn 98 + case "error": 99 + lvl = slog.LevelError 100 + default: 101 + return fmt.Errorf("unknown log level %q: options are [debug, info, warn, error]", s) 84 102 } 85 103 c.Log.Level = lvl 86 104 return nil 87 105 }) 88 106 fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format") 89 107 fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories") 108 + fs.BoolVar(&c.ShowPrivate, "show-private", c.ShowPrivate, "Show private repos in web interface") 109 + fs.BoolVar(&c.SSH.Enable, "ssh.enable", c.SSH.Enable, "Enable SSH server") 90 110 fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys") 91 111 fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base") 92 112 fs.IntVar(&c.SSH.Port, "ssh.port", c.SSH.Port, "SSH port") 93 113 fs.StringVar(&c.SSH.HostKey, "ssh.host-key", c.SSH.HostKey, "SSH host key (created if it doesn't exist)") 114 + fs.BoolVar(&c.HTTP.Enable, "http.enable", c.HTTP.Enable, "Enable HTTP server") 94 115 fs.StringVar(&c.HTTP.CloneURL, "http.clone-url", c.HTTP.CloneURL, "HTTP clone URL base") 95 116 fs.IntVar(&c.HTTP.Port, "http.port", c.HTTP.Port, "HTTP port") 96 117 fs.StringVar(&c.Meta.Title, "meta.title", c.Meta.Title, "App title") ··· 109 130 return nil 110 131 }) 111 132 133 + parser := &ffcue.ParseConfig{ 134 + Constraints: schema, 135 + } 112 136 return c, ff.Parse(fs, args, 113 137 ff.WithEnvVarPrefix("UGIT"), 114 138 ff.WithConfigFileFlag("config"), 115 139 ff.WithAllowMissingConfigFile(true), 116 - ff.WithConfigFileParser(ffyaml.Parser), 140 + ff.WithConfigFileParser(parser.Parse), 117 141 ) 118 142 }
+43 -28
cmd/ugitd/main.go
··· 4 4 "errors" 5 5 "flag" 6 6 "fmt" 7 + "log" 7 8 "log/slog" 8 9 "os" 9 10 "os/signal" 10 11 "path/filepath" 11 12 "strconv" 12 13 "strings" 14 + "syscall" 13 15 14 - "github.com/charmbracelet/log" 15 16 "github.com/go-chi/chi/v5/middleware" 16 17 "github.com/go-chi/httplog/v2" 17 18 "github.com/go-git/go-git/v5/plumbing/protocol/packp" ··· 39 40 panic(err) 40 41 } 41 42 42 - log.SetLevel(args.Log.Level) 43 + slog.SetLogLoggerLevel(args.Log.Level) 43 44 middleware.DefaultLogger = httplog.RequestLogger(httplog.NewLogger("ugit", httplog.Options{ 44 45 JSON: args.Log.JSON, 45 46 LogLevel: slog.Level(args.Log.Level), 46 - Concise: args.Log.Level != log.DebugLevel, 47 + Concise: args.Log.Level != slog.LevelDebug, 47 48 })) 48 49 49 - if args.Log.Level == log.DebugLevel { 50 + if args.Log.Level == slog.LevelDebug { 50 51 trace.SetTarget(trace.Packet) 51 52 } else { 52 53 middleware.DefaultLogger = http.NoopLogger ··· 54 55 } 55 56 56 57 if args.Log.JSON { 57 - log.SetFormatter(log.JSONFormatter) 58 + logger := slog.New(slog.NewJSONHandler(os.Stderr, nil)) 59 + slog.SetDefault(logger) 58 60 } 59 61 60 62 if err := requiredFS(args.RepoDir); err != nil { 61 63 panic(err) 62 64 } 63 65 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 { 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 { 78 76 panic(err) 79 77 } 80 - }() 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 + } 81 85 82 86 httpSettings := http.Settings{ 83 87 Title: args.Meta.Title, ··· 89 93 Username: args.Profile.Username, 90 94 Email: args.Profile.Email, 91 95 }, 96 + ShowPrivate: args.ShowPrivate, 92 97 } 93 98 for _, link := range args.Profile.Links { 94 99 httpSettings.Profile.Links = append(httpSettings.Profile.Links, http.Link{ ··· 96 101 URL: link.URL, 97 102 }) 98 103 } 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 - }() 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 + } 106 113 107 114 ch := make(chan os.Signal, 1) 108 - signal.Notify(ch, os.Kill, os.Interrupt) 115 + signal.Notify(ch, syscall.SIGTERM, os.Interrupt) 109 116 <-ch 110 117 } 111 118 ··· 128 135 } 129 136 fp = filepath.Join(fp, "pre-receive") 130 137 138 + if err := os.MkdirAll(fp+".d", os.ModePerm); err != nil { 139 + return err 140 + } 141 + 131 142 fi, err := os.Create(fp) 132 143 if err != nil { 133 144 return err 134 145 } 135 146 fi.WriteString("#!/usr/bin/env bash\n") 136 147 fi.WriteString(fmt.Sprintf("%s pre-receive-hook\n", bin)) 148 + fi.WriteString(fmt.Sprintf(`for hook in %s.d/*; do 149 + test -x "${hook}" && test -f "${hook}" || continue 150 + "${hook}" 151 + done`, fp)) 137 152 fi.Close() 138 153 139 154 return os.Chmod(fp, 0o755)
+2
config.cue
··· 1 + http: port: 1 2 + ssh: port: 1
+3 -9
contrib/layout.kdl
··· 5 5 command "nix" 6 6 args "develop" 7 7 size "90%" 8 - start_suspended true 9 8 } 10 9 pane split_direction="vertical" { 11 10 pane { 12 - name "run" 13 - command "go" 14 - args "run" "./cmd/ugitd" 15 - start_suspended true 16 - } 17 - pane { 18 - name "watch" 11 + name "air" 19 12 command "nix" 20 - args "develop" "--command" "nu" "-c" "watch --glob *.templ ./internal/html/ {|| go generate ./...}" 13 + args "develop" "--command" "air" 14 + start_suspended true 21 15 } 22 16 } 23 17 }
+3 -58
flake.lock
··· 1 1 { 2 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 3 "nixpkgs": { 43 4 "locked": { 44 - "lastModified": 1719379843, 45 - "narHash": "sha256-u+D+IOAMMl70+CJ9NKB+RMrASjInuIWMHzjLWQjPZ6c=", 5 + "lastModified": 1755205935, 6 + "narHash": "sha256-EQ6qHuJWguaoBZyxdqsgJqyEdS77k+2CnlKrfFxlkRY=", 46 7 "owner": "nixos", 47 8 "repo": "nixpkgs", 48 - "rev": "b3f3c1b13fb08f3828442ee86630362e81136bbc", 9 + "rev": "c5e2e42c112de623adfd662b3e51f0805bf9ff83", 49 10 "type": "github" 50 11 }, 51 12 "original": { ··· 57 18 }, 58 19 "root": { 59 20 "inputs": { 60 - "gomod2nix": "gomod2nix", 61 21 "nixpkgs": "nixpkgs", 62 22 "tailwind-ctp": "tailwind-ctp", 63 23 "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 24 } 80 25 }, 81 26 "tailwind-ctp": {
+67 -153
flake.nix
··· 3 3 4 4 inputs = { 5 5 nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 - gomod2nix = { 7 - url = "github:nix-community/gomod2nix"; 8 - inputs.nixpkgs.follows = "nixpkgs"; 9 - }; 10 6 tailwind-ctp = { 11 7 url = "git+https://git.jolheiser.com/tailwind-ctp"; 12 8 inputs.nixpkgs.follows = "nixpkgs"; ··· 17 13 }; 18 14 }; 19 15 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 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" 66 31 ]; 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"; 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 = import nixpkgs { inherit system; }; }); 38 + devShells = forAllSystems ( 39 + system: 40 + let 41 + pkgs = import nixpkgs { inherit 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 + ]; 117 53 }; 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 - }; 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 + ]; 136 70 }; 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"; 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 + ''}"; 169 84 }; 170 - }; 171 - }; 85 + } 86 + ); 172 87 }; 173 - }; 174 88 }
+66 -54
go.mod
··· 1 1 module go.jolheiser.com/ugit 2 2 3 - go 1.21 3 + go 1.23.1 4 4 5 - toolchain go1.21.5 5 + toolchain go1.23.3 6 6 7 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 8 + github.com/a-h/templ v0.3.924 9 + github.com/alecthomas/assert/v2 v2.11.0 10 + github.com/alecthomas/chroma/v2 v2.15.0 11 + github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c 12 + github.com/charmbracelet/wish v1.4.4 13 13 github.com/dustin/go-humanize v1.0.1 14 - github.com/go-chi/chi/v5 v5.0.11 14 + github.com/go-chi/chi/v5 v5.2.0 15 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 16 + github.com/go-git/go-billy/v5 v5.6.1 17 + github.com/go-git/go-git/v5 v5.13.1 18 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 19 + github.com/yuin/goldmark v1.7.12 20 + github.com/yuin/goldmark-emoji v1.0.4 21 21 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc 22 - golang.org/x/net v0.25.0 22 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75 23 + golang.org/x/net v0.42.0 23 24 ) 24 25 25 26 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 27 + cuelang.org/go v0.14.1 // indirect 28 + dario.cat/mergo v1.0.1 // indirect 29 + github.com/Microsoft/go-winio v0.6.2 // indirect 30 + github.com/ProtonMail/go-crypto v1.1.4 // indirect 31 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect 32 + github.com/alecthomas/repr v0.4.0 // indirect 33 + github.com/andybalholm/brotli v1.1.0 // indirect 29 34 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 30 - github.com/atotto/clipboard v0.1.4 // indirect 31 35 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 36 + github.com/cenkalti/backoff/v4 v4.3.0 // indirect 37 + github.com/charmbracelet/bubbletea v1.2.4 // indirect 38 + github.com/charmbracelet/keygen v0.5.1 // indirect 39 + github.com/charmbracelet/lipgloss v1.0.0 // indirect 40 + github.com/charmbracelet/log v0.4.0 // indirect 41 + github.com/charmbracelet/x/ansi v0.6.0 // indirect 42 + github.com/charmbracelet/x/conpty v0.1.0 // indirect 43 + github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 // indirect 44 + github.com/charmbracelet/x/term v0.2.1 // indirect 45 + github.com/charmbracelet/x/termios v0.1.0 // indirect 46 + github.com/cli/browser v1.3.0 // indirect 47 + github.com/cloudflare/circl v1.5.0 // indirect 48 + github.com/cockroachdb/apd/v3 v3.2.1 // indirect 49 + github.com/creack/pty v1.1.24 // indirect 50 + github.com/cyphar/filepath-securejoin v0.3.6 // indirect 51 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 52 + github.com/dlclark/regexp2 v1.11.4 // indirect 53 + github.com/emicklei/proto v1.14.2 // indirect 50 54 github.com/emirpasic/gods v1.18.1 // indirect 51 55 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 56 + github.com/fatih/color v1.16.0 // indirect 57 + github.com/fsnotify/fsnotify v1.7.0 // indirect 52 58 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 53 59 github.com/go-logfmt/logfmt v0.6.0 // indirect 54 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 60 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 61 + github.com/google/uuid v1.6.0 // indirect 62 + github.com/hexops/gotextdiff v1.0.3 // indirect 55 63 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 56 64 github.com/kevinburke/ssh_config v1.2.0 // indirect 57 65 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 66 + github.com/mattn/go-colorable v0.1.13 // indirect 58 67 github.com/mattn/go-isatty v0.0.20 // indirect 59 68 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 69 + github.com/mattn/go-runewidth v0.0.16 // indirect 70 + github.com/mitchellh/go-wordwrap v1.0.1 // indirect 71 + github.com/mmcloughlin/avo v0.6.0 // indirect 62 72 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 63 73 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 74 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5 // indirect 75 + github.com/natefinch/atomic v1.0.1 // indirect 76 + github.com/pelletier/go-toml/v2 v2.2.4 // indirect 77 + github.com/pjbgf/sha1cd v0.3.1 // indirect 78 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 79 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5 // indirect 67 80 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 81 + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 82 + github.com/skeema/knownhosts v1.3.0 // indirect 71 83 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 84 + golang.org/x/crypto v0.40.0 // indirect 85 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect 86 + golang.org/x/mod v0.26.0 // indirect 87 + golang.org/x/sync v0.16.0 // indirect 88 + golang.org/x/sys v0.34.0 // indirect 89 + golang.org/x/text v0.27.0 // indirect 90 + golang.org/x/tools v0.35.0 // indirect 81 91 gopkg.in/warnings.v0 v0.1.2 // indirect 82 - gopkg.in/yaml.v2 v2.4.0 // indirect 92 + gopkg.in/yaml.v3 v3.0.1 // indirect 83 93 ) 94 + 95 + tool github.com/a-h/templ/cmd/templ
+1 -1
go.mod.sri
··· 1 - sha256-8kI94hcJupAUye6cEAmIlN+CrtYSXlgoAlmpyXArfF8= 1 + sha256-DjweXB8uqEpOIBwGabLCnVL4ZOKkPcJDf6JlAS5FmKI=
+151 -189
go.sum
··· 1 - dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= 2 - dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 1 + cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d h1:lX0EawyoAu4kgMJJfy7MmNkIHioBcdBGFRSKDZ+CWo0= 2 + cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc= 3 + cuelang.org/go v0.14.1 h1:kxFAHr7bvrCikbtVps2chPIARazVdnRmlz65dAzKyWg= 4 + cuelang.org/go v0.14.1/go.mod h1:aSP9UZUM5m2izHAHUvqtq0wTlWn5oLjuv2iBMQZBLLs= 5 + dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 6 + dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 3 7 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= 8 + github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 9 + github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 10 + github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE= 11 + github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= 12 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo= 13 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ= 14 + github.com/a-h/templ v0.3.924 h1:t5gZqTneXqvehpNZsgtnlOscnBboNh9aASBH2MgV/0k= 15 + github.com/a-h/templ v0.3.924/go.mod h1:FFAu4dI//ESmEN7PQkJ7E7QfnSEMdcnu7QrAY8Dn334= 16 + github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 17 + github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 12 18 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= 19 + github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= 20 + github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= 15 21 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= 22 + github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= 23 + github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 24 + github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= 25 + github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 18 26 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 19 27 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 20 28 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 21 29 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 30 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 25 31 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= 32 + github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 33 + github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 34 + github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= 35 + github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= 36 + github.com/charmbracelet/keygen v0.5.1 h1:zBkkYPtmKDVTw+cwUyY6ZwGDhRxXkEp0Oxs9sqMLqxI= 37 + github.com/charmbracelet/keygen v0.5.1/go.mod h1:zznJVmK/GWB6dAtjluqn2qsttiCBhA5MZSiwb80fcHw= 38 + github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= 39 + github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= 40 + github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= 41 + github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= 42 + github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c h1:treQxMBdI2PaD4eOYfFux8stfCkUxhuUxaqGcxKqVpI= 43 + github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c/go.mod h1:CY1xbl2z+ZeBmNWItKZyxx0zgDgnhmR57+DTsHOobJ4= 44 + github.com/charmbracelet/wish v1.4.4 h1:wtfoAMkf8Db9zi+9Lme2f7XKMxL6BqfgDWbqcTUHLaU= 45 + github.com/charmbracelet/wish v1.4.4/go.mod h1:XB8v51UxIFMRlUod9lLaAgOsj/wpe+qW9HjsoYIiNMo= 46 + github.com/charmbracelet/x/ansi v0.6.0 h1:qOznutrb93gx9oMiGf7caF7bqqubh6YIM0SWKyA08pA= 47 + github.com/charmbracelet/x/ansi v0.6.0/go.mod h1:KBUFw1la39nl0dLl10l5ORDAqGXaeurTQmwyyVKse/Q= 48 + github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= 49 + github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= 50 + github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 h1:Hx72S6S4jAfrrWE3pv9IbudVdUV4htBgkOX800o17Bk= 51 + github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= 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.0 h1:y4rjAHeFksBAfGbkRDmVinMg7x7DELIGAFbdNvxg97k= 55 + github.com/charmbracelet/x/termios v0.1.0/go.mod h1:H/EVv/KRnrYjz+fCYa9bsKdqF3S8ouDK0AZEbG7r+/U= 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/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= 59 + github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 60 + github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= 61 + github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= 62 + github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= 63 + github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 64 + github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= 65 + github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 74 66 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 67 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 68 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 69 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 77 70 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 78 71 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= 72 + github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= 73 + github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 81 74 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 82 75 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= 76 + github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= 77 + github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= 78 + github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= 79 + github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= 85 80 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 86 81 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 87 82 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 88 83 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= 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.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= 91 + github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 93 92 github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk= 94 93 github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE= 95 94 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= 96 95 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= 96 + github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= 97 + github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= 99 98 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= 100 99 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= 100 + github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= 101 + github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= 103 102 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 104 103 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= 104 + github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 105 + github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 106 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 107 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 108 + github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 109 + github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 110 + github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 111 + github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 109 112 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 110 113 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 114 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 114 115 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 115 116 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= ··· 121 122 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 122 123 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 123 124 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 125 + github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 126 + github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 127 + github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= 128 + github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 124 129 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 125 130 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 131 + github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 132 + github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 133 + github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 126 134 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 127 135 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 128 136 github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 129 137 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= 138 + github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 139 + github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 140 + github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= 141 + github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 142 + github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= 143 + github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 135 144 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 136 145 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 137 146 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 138 147 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= 148 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5 h1:NiONcKK0EV5gUZcnCiPMORaZA0eBDc+Fgepl9xl4lZ8= 149 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= 150 + github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= 151 + github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= 152 + github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 153 + github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 154 + github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 155 + github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 156 + github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= 157 + github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 158 + github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 159 + github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 145 160 github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= 146 161 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= 162 + github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI= 163 + github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s= 149 164 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 150 165 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 166 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= 167 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 168 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 169 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5 h1:WWs1ZFnGobK5ZXNu+N9If+8PDNVB9xAqrib/stUXsV4= 170 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5/go.mod h1:BnHogPTyzYAReeQLZrOxyxzS739DaTNtTvohVdbENmA= 154 171 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 172 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 158 173 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= 174 + github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 175 + github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 176 + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= 177 + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 163 178 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= 179 + github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= 180 + github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= 166 181 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 167 182 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 168 183 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 169 184 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= 185 + github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 186 + github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 176 187 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 177 188 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 189 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= 190 + github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 191 + github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= 192 + github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= 193 + github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90= 194 + github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= 187 195 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 188 196 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= 197 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75 h1:hu2LcTy2bvgmfEDuaDCfpWIzWN1pHAKfUkAnpgjZYco= 198 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75/go.mod h1:IrDGUkvU3xl27+Seb20ZE/H2dzG95m/xmu0Z/B3crUE= 191 199 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= 200 + golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= 201 + golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= 202 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= 203 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= 204 + golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= 205 + golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= 207 206 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= 207 + golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= 208 + golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= 209 + golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= 210 + golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= 211 + golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= 212 + golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 223 213 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 224 214 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 225 215 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 226 216 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 227 217 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 228 218 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 219 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= 220 + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 236 221 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= 222 + golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= 223 + golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 241 224 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= 225 + golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= 226 + golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= 252 227 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= 228 + golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= 229 + golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 261 230 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= 231 + golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= 232 + golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= 270 233 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 271 234 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 272 235 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= ··· 274 237 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 275 238 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 276 239 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 277 - gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 278 240 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 279 241 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 280 242 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-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
··· 98 98 } 99 99 } 100 100 101 - fis := make([]FileInfo, 0) 101 + fis := make([]FileInfo, 0, len(t.Entries)) 102 102 for _, entry := range t.Entries { 103 103 fm, err := entry.Mode.ToOSFileMode() 104 104 if err != nil { ··· 118 118 sort.Slice(fis, func(i, j int) bool { 119 119 fi1 := fis[i] 120 120 fi2 := fis[j] 121 - return (fi1.IsDir && !fi2.IsDir) || fi1.Name() < fi2.Name() 121 + if fi1.IsDir != fi2.IsDir { 122 + return fi1.IsDir 123 + } 124 + return fi1.Name() < fi2.Name() 122 125 }) 123 126 124 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) 125 143 } 126 144 127 145 // FileContent returns the content of a file in the git tree at a given ref/rev
+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
··· 18 18 19 19 // Grep performs a naive "code search" via git grep 20 20 func (r Repo) Grep(search string) ([]GrepResult, error) { 21 - // Plain-text search only 22 - re, err := regexp.Compile(regexp.QuoteMeta(search)) 21 + if strings.HasPrefix(search, "=") { 22 + search = regexp.QuoteMeta(strings.TrimPrefix(search, "=")) 23 + } 24 + re, err := regexp.Compile(search) 23 25 if err != nil { 24 26 return nil, err 25 27 }
+66 -4
internal/git/meta.go
··· 3 3 import ( 4 4 "encoding/json" 5 5 "errors" 6 + "fmt" 6 7 "io/fs" 7 8 "os" 8 9 "path/filepath" 10 + "slices" 9 11 ) 10 12 11 13 // RepoMeta is the meta information a Repo can have 12 14 type RepoMeta struct { 13 - Description string `json:"description"` 14 - Private bool `json:"private"` 15 - Tags []string `json:"tags"` 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 16 68 } 17 69 18 70 // Update updates meta given another RepoMeta ··· 46 98 return json.NewEncoder(fi).Encode(r.Meta) 47 99 } 48 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 + 49 111 func ensureJSONFile(path string) error { 50 112 _, err := os.Stat(path) 51 113 if err == nil { ··· 59 121 return err 60 122 } 61 123 defer fi.Close() 62 - if _, err := fi.WriteString(`{"private":true}`); err != nil { 124 + if _, err := fi.Write(defaultMeta); err != nil { 63 125 return err 64 126 } 65 127 return nil
+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
··· 58 58 remove = true 59 59 tagValue = strings.TrimPrefix(tagValue, "-") 60 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 - } 61 + tagValue = strings.ToLower(tagValue) 62 + if remove { 63 + repo.Meta.Tags.Remove(tagValue) 64 + } else { 65 + repo.Meta.Tags.Add(tagValue) 70 66 } 71 67 } 72 68 }
-1
internal/git/protocol_git.go
··· 58 58 cmd.Env = append(os.Environ(), fmt.Sprintf("UGIT_REPODIR=%s", repoDir), "GIT_PROTOCOL=version=2") 59 59 cmd.Stdin = ctx 60 60 cmd.Stdout = ctx 61 - fmt.Println(cmd.Env, cmd.String()) 62 61 63 62 return cmd.Run() 64 63 }
+11
internal/git/repo.go
··· 57 57 if err := json.NewDecoder(fi).Decode(&r.Meta); err != nil { 58 58 return nil, err 59 59 } 60 + if r.Meta.Tags == nil { 61 + r.Meta.Tags = make(TagSet) 62 + } 60 63 61 64 return r, nil 62 65 } ··· 132 135 type CommitFileEntry struct { 133 136 Path string 134 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 135 146 } 136 147 137 148 // Short returns the first eight characters of the SHA
+3 -1
internal/html/base.templ
··· 18 18 <meta property="og:description" content={ bc.Description }/> 19 19 </head> 20 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> 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> 22 24 { children... } 23 25 </body> 24 26 </html>
+22 -17
internal/html/base_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 type BaseContext struct { 14 12 Title string ··· 16 14 } 17 15 18 16 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) 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) 21 23 if !templ_7745c5c3_IsBuffer { 22 - templ_7745c5c3_Buffer = templ.GetBuffer() 23 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 24 30 } 25 31 ctx = templ.InitializeContext(ctx) 26 32 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 28 34 templ_7745c5c3_Var1 = templ.NopComponent 29 35 } 30 36 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>") 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>") 32 38 if templ_7745c5c3_Err != nil { 33 39 return templ_7745c5c3_Err 34 40 } ··· 41 47 if templ_7745c5c3_Err != nil { 42 48 return templ_7745c5c3_Err 43 49 } 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=\"") 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=\"") 45 51 if templ_7745c5c3_Err != nil { 46 52 return templ_7745c5c3_Err 47 53 } ··· 54 60 if templ_7745c5c3_Err != nil { 55 61 return templ_7745c5c3_Err 56 62 } 57 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><meta property=\"og:description\" content=\"") 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta property=\"og:description\" content=\"") 58 64 if templ_7745c5c3_Err != nil { 59 65 return templ_7745c5c3_Err 60 66 } ··· 67 73 if templ_7745c5c3_Err != nil { 68 74 return templ_7745c5c3_Err 69 75 } 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>") 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>") 71 77 if templ_7745c5c3_Err != nil { 72 78 return templ_7745c5c3_Err 73 79 } ··· 75 81 if templ_7745c5c3_Err != nil { 76 82 return templ_7745c5c3_Err 77 83 } 78 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>") 84 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>") 79 85 if templ_7745c5c3_Err != nil { 80 86 return templ_7745c5c3_Err 81 87 } 82 - if !templ_7745c5c3_IsBuffer { 83 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 84 - } 85 - return templ_7745c5c3_Err 88 + return nil 86 89 }) 87 90 } 91 + 92 + var _ = templruntime.GeneratedTemplate
-4
internal/html/generate.css
··· 46 46 47 47 .code>.chroma { 48 48 @apply text-sm p-3 rounded overflow-scroll; 49 - } 50 - 51 - .chroma .line { 52 - @apply overflow-scroll 53 49 }
+6 -4
internal/html/generate.go
··· 12 12 13 13 "go.jolheiser.com/ugit/internal/html/markup" 14 14 15 + "github.com/alecthomas/chroma/v2/formatters/html" 15 16 "github.com/alecthomas/chroma/v2/styles" 16 17 ) 17 18 ··· 25 26 otherCSS string 26 27 ) 27 28 28 - //go:generate templ generate 29 + //go:generate go tool templ generate 29 30 //go:generate go run generate.go 30 31 func main() { 31 32 if err := tailwind(); err != nil { ··· 33 34 } 34 35 } 35 36 36 - // Generate tailwind code from templ templates and combine with other misc CSS 37 + // Generate tailwind code from templates and combine with other misc CSS 37 38 func tailwind() error { 38 39 fmt.Println("generating tailwind...") 39 40 ··· 47 48 } 48 49 49 50 fmt.Println("generating chroma styles...") 51 + formatter := html.New(markup.Options("")...) 50 52 51 53 latte := styles.Get("catppuccin-latte") 52 - if err := markup.Formatter.WriteCSS(tmp, latte); err != nil { 54 + if err := formatter.WriteCSS(tmp, latte); err != nil { 53 55 return err 54 56 } 55 57 56 58 tmp.WriteString("@media (prefers-color-scheme: dark) {") 57 59 mocha := styles.Get("catppuccin-mocha") 58 - if err := markup.Formatter.WriteCSS(tmp, mocha); err != nil { 60 + if err := formatter.WriteCSS(tmp, mocha); err != nil { 59 61 return err 60 62 } 61 63 tmp.WriteString("}")
+28 -8
internal/html/index.templ
··· 1 1 package html 2 2 3 - import "go.jolheiser.com/ugit/internal/git" 4 - import "github.com/dustin/go-humanize" 5 - import "go.jolheiser.com/ugit/assets" 3 + import ( 4 + "fmt" 5 + "github.com/dustin/go-humanize" 6 + "go.jolheiser.com/ugit/assets" 7 + "go.jolheiser.com/ugit/internal/git" 8 + ) 6 9 7 10 type IndexContext struct { 8 11 BaseContext ··· 21 24 URL string 22 25 } 23 26 24 - func lastCommit(repo *git.Repo, human bool) string { 27 + func lastCommitTime(repo *git.Repo, human bool) string { 25 28 c, err := repo.LastCommit() 26 29 if err != nil { 27 30 return "" ··· 32 35 return c.When.Format("01/02/2006 03:04:05 PM") 33 36 } 34 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 + 35 46 templ Index(ic IndexContext) { 36 47 @base(ic.BaseContext) { 37 48 <header> ··· 62 73 </div> 63 74 } 64 75 </div> 65 - <div class="grid sm:grid-cols-8 gap-2 mt-5"> 76 + <div class="grid sm:grid-cols-10 gap-2 mt-5"> 66 77 for _, repo := range ic.Repos { 78 + {{ commit := lastCommit(repo) }} 67 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> 68 - <div class="sm:col-span-4 text-subtext0">{ repo.Meta.Description }</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> 69 89 <div class="sm:col-span-1 text-subtext0"> 70 - for _, tag := range repo.Meta.Tags { 90 + for _, tag := range repo.Meta.Tags.Slice() { 71 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> 72 92 } 73 93 </div> 74 - <div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommit(repo, false) }>{ lastCommit(repo, true) }</div> 94 + <div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommitTime(repo, false) }>{ lastCommitTime(repo, true) }</div> 75 95 } 76 96 </div> 77 97 </main>
+175 -77
internal/html/index_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 - import "go.jolheiser.com/ugit/internal/git" 14 - import "github.com/dustin/go-humanize" 15 - import "go.jolheiser.com/ugit/assets" 11 + import ( 12 + "fmt" 13 + "github.com/dustin/go-humanize" 14 + "go.jolheiser.com/ugit/assets" 15 + "go.jolheiser.com/ugit/internal/git" 16 + ) 16 17 17 18 type IndexContext struct { 18 19 BaseContext ··· 31 32 URL string 32 33 } 33 34 34 - func lastCommit(repo *git.Repo, human bool) string { 35 + func lastCommitTime(repo *git.Repo, human bool) string { 35 36 c, err := repo.LastCommit() 36 37 if err != nil { 37 38 return "" ··· 42 43 return c.When.Format("01/02/2006 03:04:05 PM") 43 44 } 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 + 45 54 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) 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) 48 61 if !templ_7745c5c3_IsBuffer { 49 - templ_7745c5c3_Buffer = templ.GetBuffer() 50 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 51 68 } 52 69 ctx = templ.InitializeContext(ctx) 53 70 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 55 72 templ_7745c5c3_Var1 = templ.NopComponent 56 73 } 57 74 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) 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) 60 78 if !templ_7745c5c3_IsBuffer { 61 - templ_7745c5c3_Buffer = templ.GetBuffer() 62 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 63 85 } 64 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header><h1 class=\"text-text text-xl font-bold\">") 86 + ctx = templ.InitializeContext(ctx) 87 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<header><h1 class=\"text-text text-xl font-bold\">") 65 88 if templ_7745c5c3_Err != nil { 66 89 return templ_7745c5c3_Err 67 90 } 68 91 var templ_7745c5c3_Var3 string 69 92 templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Title) 70 93 if templ_7745c5c3_Err != nil { 71 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 38, Col: 53} 94 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 49, Col: 53} 72 95 } 73 96 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 74 97 if templ_7745c5c3_Err != nil { 75 98 return templ_7745c5c3_Err 76 99 } 77 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><h2 class=\"text-subtext1 text-lg\">") 100 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</h1><h2 class=\"text-subtext1 text-lg\">") 78 101 if templ_7745c5c3_Err != nil { 79 102 return templ_7745c5c3_Err 80 103 } 81 104 var templ_7745c5c3_Var4 string 82 105 templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Description) 83 106 if templ_7745c5c3_Err != nil { 84 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 39, Col: 53} 107 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 50, Col: 53} 85 108 } 86 109 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 87 110 if templ_7745c5c3_Err != nil { 88 111 return templ_7745c5c3_Err 89 112 } 90 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2></header><main class=\"mt-5\"><div class=\"grid grid-cols-1 sm:grid-cols-8\">") 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\">") 91 114 if templ_7745c5c3_Err != nil { 92 115 return templ_7745c5c3_Err 93 116 } 94 117 if ic.Profile.Username != "" { 95 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve\">") 118 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"text-mauve\">") 96 119 if templ_7745c5c3_Err != nil { 97 120 return templ_7745c5c3_Err 98 121 } 99 122 var templ_7745c5c3_Var5 string 100 123 templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(`@` + ic.Profile.Username) 101 124 if templ_7745c5c3_Err != nil { 102 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 44, Col: 56} 125 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 55, Col: 56} 103 126 } 104 127 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 105 128 if templ_7745c5c3_Err != nil { 106 129 return templ_7745c5c3_Err 107 130 } 108 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 131 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div>") 109 132 if templ_7745c5c3_Err != nil { 110 133 return templ_7745c5c3_Err 111 134 } 112 135 } 113 136 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\">") 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\">") 115 138 if templ_7745c5c3_Err != nil { 116 139 return templ_7745c5c3_Err 117 140 } ··· 119 142 if templ_7745c5c3_Err != nil { 120 143 return templ_7745c5c3_Err 121 144 } 122 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"") 145 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"") 123 146 if templ_7745c5c3_Err != nil { 124 147 return templ_7745c5c3_Err 125 148 } 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))) 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)) 128 155 if templ_7745c5c3_Err != nil { 129 156 return templ_7745c5c3_Err 130 157 } 131 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 158 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">") 132 159 if templ_7745c5c3_Err != nil { 133 160 return templ_7745c5c3_Err 134 161 } 135 162 var templ_7745c5c3_Var7 string 136 163 templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Profile.Email) 137 164 if templ_7745c5c3_Err != nil { 138 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 51, Col: 159} 165 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 62, Col: 159} 139 166 } 140 167 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 141 168 if templ_7745c5c3_Err != nil { 142 169 return templ_7745c5c3_Err 143 170 } 144 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>") 171 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</a></div>") 145 172 if templ_7745c5c3_Err != nil { 146 173 return templ_7745c5c3_Err 147 174 } 148 175 } 149 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">") 176 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">") 150 177 if templ_7745c5c3_Err != nil { 151 178 return templ_7745c5c3_Err 152 179 } 153 180 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\">") 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\">") 155 182 if templ_7745c5c3_Err != nil { 156 183 return templ_7745c5c3_Err 157 184 } ··· 159 186 if templ_7745c5c3_Err != nil { 160 187 return templ_7745c5c3_Err 161 188 } 162 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" rel=\"me\" href=\"") 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=\"") 163 190 if templ_7745c5c3_Err != nil { 164 191 return templ_7745c5c3_Err 165 192 } 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))) 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)) 168 199 if templ_7745c5c3_Err != nil { 169 200 return templ_7745c5c3_Err 170 201 } 171 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 202 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">") 172 203 if templ_7745c5c3_Err != nil { 173 204 return templ_7745c5c3_Err 174 205 } 175 206 var templ_7745c5c3_Var9 string 176 207 templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name) 177 208 if templ_7745c5c3_Err != nil { 178 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 61, Col: 141} 209 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 141} 179 210 } 180 211 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 181 212 if templ_7745c5c3_Err != nil { 182 213 return templ_7745c5c3_Err 183 214 } 184 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>") 215 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a></div>") 185 216 if templ_7745c5c3_Err != nil { 186 217 return templ_7745c5c3_Err 187 218 } 188 219 } 189 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid sm:grid-cols-8 gap-2 mt-5\">") 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div><div class=\"grid sm:grid-cols-10 gap-2 mt-5\">") 190 221 if templ_7745c5c3_Err != nil { 191 222 return templ_7745c5c3_Err 192 223 } 193 224 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=\"") 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=\"") 195 227 if templ_7745c5c3_Err != nil { 196 228 return templ_7745c5c3_Err 197 229 } 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))) 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)) 200 236 if templ_7745c5c3_Err != nil { 201 237 return templ_7745c5c3_Err 202 238 } 203 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 239 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">") 204 240 if templ_7745c5c3_Err != nil { 205 241 return templ_7745c5c3_Err 206 242 } 207 243 var templ_7745c5c3_Var11 string 208 244 templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Name()) 209 245 if templ_7745c5c3_Err != nil { 210 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 67, Col: 221} 246 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 221} 211 247 } 212 248 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 213 249 if templ_7745c5c3_Err != nil { 214 250 return templ_7745c5c3_Err 215 251 } 216 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"sm:col-span-4 text-subtext0\">") 252 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</a></div><div class=\"sm:col-span-3 text-subtext0\">") 217 253 if templ_7745c5c3_Err != nil { 218 254 return templ_7745c5c3_Err 219 255 } 220 256 var templ_7745c5c3_Var12 string 221 257 templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Meta.Description) 222 258 if templ_7745c5c3_Err != nil { 223 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 68, Col: 69} 259 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 80, Col: 69} 224 260 } 225 261 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 226 262 if templ_7745c5c3_Err != nil { 227 263 return templ_7745c5c3_Err 228 264 } 229 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-subtext0\">") 265 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div><div class=\"sm:col-span-3 text-subtext0\">") 230 266 if templ_7745c5c3_Err != nil { 231 267 return templ_7745c5c3_Err 232 268 } 233 - for _, tag := range repo.Meta.Tags { 234 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a href=\"") 269 + if commit != nil { 270 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div title=\"") 235 271 if templ_7745c5c3_Err != nil { 236 272 return templ_7745c5c3_Err 237 273 } 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))) 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)) 240 280 if templ_7745c5c3_Err != nil { 241 281 return templ_7745c5c3_Err 242 282 } 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\">") 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=\"") 244 284 if templ_7745c5c3_Err != nil { 245 285 return templ_7745c5c3_Err 246 286 } 247 - var templ_7745c5c3_Var14 string 248 - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(tag) 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)) 249 289 if templ_7745c5c3_Err != nil { 250 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 71, Col: 141} 290 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 206} 251 291 } 252 292 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 253 293 if templ_7745c5c3_Err != nil { 254 294 return templ_7745c5c3_Err 255 295 } 256 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 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>") 257 323 if templ_7745c5c3_Err != nil { 258 324 return templ_7745c5c3_Err 259 325 } 260 326 } 261 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"") 327 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</div><div class=\"sm:col-span-1 text-subtext0\">") 262 328 if templ_7745c5c3_Err != nil { 263 329 return templ_7745c5c3_Err 264 330 } 265 - var templ_7745c5c3_Var15 string 266 - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, false)) 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=\"") 267 364 if templ_7745c5c3_Err != nil { 268 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 89} 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} 269 371 } 270 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 372 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 271 373 if templ_7745c5c3_Err != nil { 272 374 return templ_7745c5c3_Err 273 375 } 274 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 376 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\">") 275 377 if templ_7745c5c3_Err != nil { 276 378 return templ_7745c5c3_Err 277 379 } 278 - var templ_7745c5c3_Var16 string 279 - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, true)) 380 + var templ_7745c5c3_Var20 string 381 + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, true)) 280 382 if templ_7745c5c3_Err != nil { 281 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 116} 383 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 124} 282 384 } 283 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 385 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) 284 386 if templ_7745c5c3_Err != nil { 285 387 return templ_7745c5c3_Err 286 388 } 287 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 389 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</div>") 288 390 if templ_7745c5c3_Err != nil { 289 391 return templ_7745c5c3_Err 290 392 } 291 393 } 292 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></main>") 394 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</div></main>") 293 395 if templ_7745c5c3_Err != nil { 294 396 return templ_7745c5c3_Err 295 397 } 296 - if !templ_7745c5c3_IsBuffer { 297 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 298 - } 299 - return templ_7745c5c3_Err 398 + return nil 300 399 }) 301 400 templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 302 401 if templ_7745c5c3_Err != nil { 303 402 return templ_7745c5c3_Err 304 403 } 305 - if !templ_7745c5c3_IsBuffer { 306 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 307 - } 308 - return templ_7745c5c3_Err 404 + return nil 309 405 }) 310 406 } 407 + 408 + var _ = templruntime.GeneratedTemplate
+16 -24
internal/html/markup/chroma.go
··· 2 2 3 3 import ( 4 4 "io" 5 + "path/filepath" 5 6 6 7 "github.com/alecthomas/chroma/v2" 7 8 "github.com/alecthomas/chroma/v2/formatters/html" ··· 9 10 "github.com/alecthomas/chroma/v2/styles" 10 11 ) 11 12 12 - var ( 13 - // Formatter is the default formatter 14 - Formatter = html.New( 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{ 15 20 html.WithLineNumbers(true), 16 - html.WithLinkableLineNumbers(true, "L"), 21 + html.WithLinkableLineNumbers(true, linePrefix), 17 22 html.WithClasses(true), 18 23 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{} 24 + } 25 + } 28 26 29 27 func setup(source []byte, fileName string) (chroma.Iterator, *chroma.Style, error) { 30 28 lexer := lexers.Match(fileName) 31 29 if lexer == nil { 32 30 lexer = lexers.Fallback 31 + if name, ok := customReg[filepath.Ext(fileName)]; ok { 32 + lexer = lexers.Get(name) 33 + } 33 34 } 34 35 lexer = chroma.Coalesce(lexer) 35 36 ··· 46 47 return iter, style, nil 47 48 } 48 49 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 50 // Convert formats code with line numbers, links, etc. 59 - func (c code) Convert(source []byte, fileName string, writer io.Writer) error { 51 + func Convert(source []byte, fileName, linePrefix string, writer io.Writer) error { 60 52 iter, style, err := setup(source, fileName) 61 53 if err != nil { 62 54 return err 63 55 } 64 - return Formatter.Format(writer, style, iter) 56 + return html.New(Options(linePrefix)...).Format(writer, style, iter) 65 57 } 66 58 67 59 // Snippet formats code with line numbers starting at a specific line
+1
internal/html/markup/markdown.go
··· 112 112 case *ast.Image: 113 113 link := v.Destination 114 114 if len(link) > 0 && !bytes.HasPrefix(link, []byte("http")) { 115 + v.SetAttributeString("style", []byte("max-width:100%;")) 115 116 v.Destination = []byte(resolveLink(ctx.repo, ctx.ref, ctx.path, string(link)) + "?raw&pretty") 116 117 } 117 118
+4 -3
internal/html/readme.templ
··· 1 1 package html 2 2 3 3 type ReadmeComponentContext struct { 4 - Markdown string 4 + Markdown string 5 5 } 6 6 7 7 templ readmeComponent(rcc ReadmeComponentContext) { 8 8 if rcc.Markdown != "" { 9 - <div class="bg-base dark:bg-base/50 p-5 mt-5 rounded markdown">@templ.Raw(rcc.Markdown)</div> 9 + <div class="bg-base dark:bg-base/50 p-5 mt-5 rounded markdown"> 10 + @templ.Raw(rcc.Markdown) 11 + </div> 10 12 } 11 13 } 12 -
+19 -14
internal/html/readme_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 type ReadmeComponentContext struct { 14 12 Markdown string 15 13 } 16 14 17 15 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) 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) 20 22 if !templ_7745c5c3_IsBuffer { 21 - templ_7745c5c3_Buffer = templ.GetBuffer() 22 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 23 29 } 24 30 ctx = templ.InitializeContext(ctx) 25 31 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 28 34 } 29 35 ctx = templ.ClearChildren(ctx) 30 36 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\">") 37 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"bg-base dark:bg-base/50 p-5 mt-5 rounded markdown\">") 32 38 if templ_7745c5c3_Err != nil { 33 39 return templ_7745c5c3_Err 34 40 } ··· 36 42 if templ_7745c5c3_Err != nil { 37 43 return templ_7745c5c3_Err 38 44 } 39 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 45 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div>") 40 46 if templ_7745c5c3_Err != nil { 41 47 return templ_7745c5c3_Err 42 48 } 43 49 } 44 - if !templ_7745c5c3_IsBuffer { 45 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 46 - } 47 - return templ_7745c5c3_Err 50 + return nil 48 51 }) 49 52 } 53 + 54 + var _ = templruntime.GeneratedTemplate
+1 -1
internal/html/repo_breadcrumb.templ
··· 2 2 3 3 import ( 4 4 "fmt" 5 - "strings" 6 5 "path" 6 + "strings" 7 7 ) 8 8 9 9 type RepoBreadcrumbComponentContext struct {
+30 -21
internal/html/repo_breadcrumb_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import ( 14 12 "fmt" ··· 47 45 } 48 46 49 47 func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) templ.Component { 50 - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 51 - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) 48 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 49 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 50 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 51 + return templ_7745c5c3_CtxErr 52 + } 53 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 52 54 if !templ_7745c5c3_IsBuffer { 53 - templ_7745c5c3_Buffer = templ.GetBuffer() 54 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 55 + defer func() { 56 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 57 + if templ_7745c5c3_Err == nil { 58 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 59 + } 60 + }() 55 61 } 56 62 ctx = templ.InitializeContext(ctx) 57 63 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 60 66 } 61 67 ctx = templ.ClearChildren(ctx) 62 68 if rbcc.Path != "" { 63 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"inline-block text-text\">") 69 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"inline-block text-text\">") 64 70 if templ_7745c5c3_Err != nil { 65 71 return templ_7745c5c3_Err 66 72 } 67 73 for _, crumb := range rbcc.crumbs() { 68 74 if crumb.end { 69 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>") 75 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span>") 70 76 if templ_7745c5c3_Err != nil { 71 77 return templ_7745c5c3_Err 72 78 } ··· 79 85 if templ_7745c5c3_Err != nil { 80 86 return templ_7745c5c3_Err 81 87 } 82 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>") 88 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span>") 83 89 if templ_7745c5c3_Err != nil { 84 90 return templ_7745c5c3_Err 85 91 } 86 92 } else { 87 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 93 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 88 94 if templ_7745c5c3_Err != nil { 89 95 return templ_7745c5c3_Err 90 96 } 91 - var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(crumb.href) 92 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3))) 97 + var templ_7745c5c3_Var3 templ.SafeURL 98 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(crumb.href)) 99 + if templ_7745c5c3_Err != nil { 100 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 46, Col: 118} 101 + } 102 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 93 103 if templ_7745c5c3_Err != nil { 94 104 return templ_7745c5c3_Err 95 105 } 96 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 106 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 97 107 if templ_7745c5c3_Err != nil { 98 108 return templ_7745c5c3_Err 99 109 } ··· 106 116 if templ_7745c5c3_Err != nil { 107 117 return templ_7745c5c3_Err 108 118 } 109 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 110 120 if templ_7745c5c3_Err != nil { 111 121 return templ_7745c5c3_Err 112 122 } ··· 121 131 } 122 132 } 123 133 } 124 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 134 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 125 135 if templ_7745c5c3_Err != nil { 126 136 return templ_7745c5c3_Err 127 137 } 128 138 } 129 - if !templ_7745c5c3_IsBuffer { 130 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 131 - } 132 - return templ_7745c5c3_Err 139 + return nil 133 140 }) 134 141 } 142 + 143 + var _ = templruntime.GeneratedTemplate
+16 -8
internal/html/repo_commit.templ
··· 4 4 import "github.com/dustin/go-humanize" 5 5 import "go.jolheiser.com/ugit/internal/git" 6 6 7 - type RepoCommitContext struct{ 8 - BaseContext 9 - RepoHeaderComponentContext 10 - Commit git.Commit 7 + type RepoCommitContext struct { 8 + BaseContext 9 + RepoHeaderComponentContext 10 + Commit git.Commit 11 11 } 12 12 13 13 templ RepoCommit(rcc RepoCommitContext) { ··· 25 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 26 <div title={ rcc.Commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(rcc.Commit.When) }</div> 27 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> 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> 29 36 for _, file := range rcc.Commit.Files { 30 - <div class="text-text mt-5"> 37 + <div class="text-text mt-5" id={ file.Path() }> 31 38 <span class="text-text/80" title={ file.Action }>{ string(file.Action[0]) }</span> 32 39 { " " } 33 40 if file.From.Path != "" { ··· 40 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> 41 48 } 42 49 </div> 43 - <div class="whitespace-pre code">@templ.Raw(file.Patch)</div> 50 + <div class="code"> 51 + @templ.Raw(file.Patch) 52 + </div> 44 53 } 45 54 } 46 55 } 47 -
+162 -81
internal/html/repo_commit_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import "fmt" 14 12 import "github.com/dustin/go-humanize" ··· 21 19 } 22 20 23 21 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) 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) 26 28 if !templ_7745c5c3_IsBuffer { 27 - templ_7745c5c3_Buffer = templ.GetBuffer() 28 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 29 35 } 30 36 ctx = templ.InitializeContext(ctx) 31 37 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 33 39 templ_7745c5c3_Var1 = templ.NopComponent 34 40 } 35 41 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) 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) 38 45 if !templ_7745c5c3_IsBuffer { 39 - templ_7745c5c3_Buffer = templ.GetBuffer() 40 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 41 52 } 53 + ctx = templ.InitializeContext(ctx) 42 54 templ_7745c5c3_Err = repoHeaderComponent(rcc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 43 55 if templ_7745c5c3_Err != nil { 44 56 return templ_7745c5c3_Err 45 57 } 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=\"") 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=\"") 47 59 if templ_7745c5c3_Err != nil { 48 60 return templ_7745c5c3_Err 49 61 } 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))) 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)) 52 68 if templ_7745c5c3_Err != nil { 53 69 return templ_7745c5c3_Err 54 70 } 55 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>") 71 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">tree</a>") 56 72 if templ_7745c5c3_Err != nil { 57 73 return templ_7745c5c3_Err 58 74 } ··· 65 81 if templ_7745c5c3_Err != nil { 66 82 return templ_7745c5c3_Err 67 83 } 68 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 84 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 69 85 if templ_7745c5c3_Err != nil { 70 86 return templ_7745c5c3_Err 71 87 } 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))) 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)) 74 94 if templ_7745c5c3_Err != nil { 75 95 return templ_7745c5c3_Err 76 96 } 77 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a>") 97 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\">log</a>") 78 98 if templ_7745c5c3_Err != nil { 79 99 return templ_7745c5c3_Err 80 100 } ··· 87 107 if templ_7745c5c3_Err != nil { 88 108 return templ_7745c5c3_Err 89 109 } 90 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 110 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 91 111 if templ_7745c5c3_Err != nil { 92 112 return templ_7745c5c3_Err 93 113 } 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))) 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)) 96 120 if templ_7745c5c3_Err != nil { 97 121 return templ_7745c5c3_Err 98 122 } 99 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">patch</a></div><div class=\"text-text whitespace-pre mt-5 p-3 bg-base rounded\">") 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\">") 100 124 if templ_7745c5c3_Err != nil { 101 125 return templ_7745c5c3_Err 102 126 } ··· 109 133 if templ_7745c5c3_Err != nil { 110 134 return templ_7745c5c3_Err 111 135 } 112 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 136 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 113 137 if templ_7745c5c3_Err != nil { 114 138 return templ_7745c5c3_Err 115 139 } 116 140 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>") 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>") 118 142 if templ_7745c5c3_Err != nil { 119 143 return templ_7745c5c3_Err 120 144 } ··· 127 151 if templ_7745c5c3_Err != nil { 128 152 return templ_7745c5c3_Err 129 153 } 130 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></div></details>") 154 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</code></div></details>") 131 155 if templ_7745c5c3_Err != nil { 132 156 return templ_7745c5c3_Err 133 157 } 134 158 } 135 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"text-text mt-3\"><div>") 159 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " <div class=\"text-text mt-3\"><div>") 136 160 if templ_7745c5c3_Err != nil { 137 161 return templ_7745c5c3_Err 138 162 } ··· 154 178 if templ_7745c5c3_Err != nil { 155 179 return templ_7745c5c3_Err 156 180 } 157 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 181 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 158 182 if templ_7745c5c3_Err != nil { 159 183 return templ_7745c5c3_Err 160 184 } 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))) 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)) 163 191 if templ_7745c5c3_Err != nil { 164 192 return templ_7745c5c3_Err 165 193 } 166 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 194 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 167 195 if templ_7745c5c3_Err != nil { 168 196 return templ_7745c5c3_Err 169 197 } ··· 176 204 if templ_7745c5c3_Err != nil { 177 205 return templ_7745c5c3_Err 178 206 } 179 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"") 207 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</a></div><div title=\"") 180 208 if templ_7745c5c3_Err != nil { 181 209 return templ_7745c5c3_Err 182 210 } ··· 189 217 if templ_7745c5c3_Err != nil { 190 218 return templ_7745c5c3_Err 191 219 } 192 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\">") 193 221 if templ_7745c5c3_Err != nil { 194 222 return templ_7745c5c3_Err 195 223 } ··· 202 230 if templ_7745c5c3_Err != nil { 203 231 return templ_7745c5c3_Err 204 232 } 205 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"text-text mt-5\">") 233 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></div><details class=\"text-text mt-5\"><summary class=\"cursor-pointer\">") 206 234 if templ_7745c5c3_Err != nil { 207 235 return templ_7745c5c3_Err 208 236 } 209 237 var templ_7745c5c3_Var16 string 210 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)) 211 239 if templ_7745c5c3_Err != nil { 212 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 28, Col: 179} 240 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 29, Col: 184} 213 241 } 214 242 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 215 243 if templ_7745c5c3_Err != nil { 216 244 return templ_7745c5c3_Err 217 245 } 218 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 246 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</summary><div class=\"p-3 bg-base rounded\">") 219 247 if templ_7745c5c3_Err != nil { 220 248 return templ_7745c5c3_Err 221 249 } 222 250 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=\"") 251 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<a class=\"block underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 224 252 if templ_7745c5c3_Err != nil { 225 253 return templ_7745c5c3_Err 226 254 } 227 - var templ_7745c5c3_Var17 string 228 - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action) 255 + var templ_7745c5c3_Var17 templ.SafeURL 256 + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs("#" + file.Path()) 229 257 if templ_7745c5c3_Err != nil { 230 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 50} 258 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 116} 231 259 } 232 260 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 233 261 if templ_7745c5c3_Err != nil { 234 262 return templ_7745c5c3_Err 235 263 } 236 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 264 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">") 237 265 if templ_7745c5c3_Err != nil { 238 266 return templ_7745c5c3_Err 239 267 } 240 268 var templ_7745c5c3_Var18 string 241 - templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0])) 269 + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 242 270 if templ_7745c5c3_Err != nil { 243 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 77} 271 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 132} 244 272 } 245 273 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 246 274 if templ_7745c5c3_Err != nil { 247 275 return templ_7745c5c3_Err 248 276 } 249 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ") 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=\"") 250 288 if templ_7745c5c3_Err != nil { 251 289 return templ_7745c5c3_Err 252 290 } 253 291 var templ_7745c5c3_Var19 string 254 - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 292 + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 255 293 if templ_7745c5c3_Err != nil { 256 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 9} 294 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 47} 257 295 } 258 296 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 259 297 if templ_7745c5c3_Err != nil { 260 298 return templ_7745c5c3_Err 261 299 } 262 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 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, " ") 263 340 if templ_7745c5c3_Err != nil { 264 341 return templ_7745c5c3_Err 265 342 } 266 343 if file.From.Path != "" { 267 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 344 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 268 345 if templ_7745c5c3_Err != nil { 269 346 return templ_7745c5c3_Err 270 347 } 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))) 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)) 273 354 if templ_7745c5c3_Err != nil { 274 355 return templ_7745c5c3_Err 275 356 } 276 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 357 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">") 277 358 if templ_7745c5c3_Err != nil { 278 359 return templ_7745c5c3_Err 279 360 } 280 - var templ_7745c5c3_Var21 string 281 - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path) 361 + var templ_7745c5c3_Var24 string 362 + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path) 282 363 if templ_7745c5c3_Err != nil { 283 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 34, Col: 227} 364 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 227} 284 365 } 285 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) 366 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) 286 367 if templ_7745c5c3_Err != nil { 287 368 return templ_7745c5c3_Err 288 369 } 289 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 370 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a> ") 290 371 if templ_7745c5c3_Err != nil { 291 372 return templ_7745c5c3_Err 292 373 } 293 374 } 294 375 if file.From.Path != "" && file.To.Path != "" { 295 - var templ_7745c5c3_Var22 string 296 - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ") 376 + var templ_7745c5c3_Var25 string 377 + templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ") 297 378 if templ_7745c5c3_Err != nil { 298 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 13} 379 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 44, Col: 13} 299 380 } 300 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) 381 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) 301 382 if templ_7745c5c3_Err != nil { 302 383 return templ_7745c5c3_Err 303 384 } 304 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 385 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ") 305 386 if templ_7745c5c3_Err != nil { 306 387 return templ_7745c5c3_Err 307 388 } 308 389 } 309 390 if file.To.Path != "" { 310 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 391 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 311 392 if templ_7745c5c3_Err != nil { 312 393 return templ_7745c5c3_Err 313 394 } 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))) 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)) 316 401 if templ_7745c5c3_Err != nil { 317 402 return templ_7745c5c3_Err 318 403 } 319 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 404 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\">") 320 405 if templ_7745c5c3_Err != nil { 321 406 return templ_7745c5c3_Err 322 407 } 323 - var templ_7745c5c3_Var24 string 324 - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path) 408 + var templ_7745c5c3_Var27 string 409 + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path) 325 410 if templ_7745c5c3_Err != nil { 326 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 40, Col: 221} 411 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 221} 327 412 } 328 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) 413 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) 329 414 if templ_7745c5c3_Err != nil { 330 415 return templ_7745c5c3_Err 331 416 } 332 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 417 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</a>") 333 418 if templ_7745c5c3_Err != nil { 334 419 return templ_7745c5c3_Err 335 420 } 336 421 } 337 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"whitespace-pre code\">") 422 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</div><div class=\"code\">") 338 423 if templ_7745c5c3_Err != nil { 339 424 return templ_7745c5c3_Err 340 425 } ··· 342 427 if templ_7745c5c3_Err != nil { 343 428 return templ_7745c5c3_Err 344 429 } 345 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 430 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div>") 346 431 if templ_7745c5c3_Err != nil { 347 432 return templ_7745c5c3_Err 348 433 } 349 434 } 350 - if !templ_7745c5c3_IsBuffer { 351 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 352 - } 353 - return templ_7745c5c3_Err 435 + return nil 354 436 }) 355 437 templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 356 438 if templ_7745c5c3_Err != nil { 357 439 return templ_7745c5c3_Err 358 440 } 359 - if !templ_7745c5c3_IsBuffer { 360 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 361 - } 362 - return templ_7745c5c3_Err 441 + return nil 363 442 }) 364 443 } 444 + 445 + var _ = templruntime.GeneratedTemplate
+42 -5
internal/html/repo_file.templ
··· 1 1 package html 2 2 3 + import "fmt" 4 + 3 5 type RepoFileContext struct { 4 6 BaseContext 5 7 RepoHeaderComponentContext 6 8 RepoBreadcrumbComponentContext 7 - Code string 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) 8 16 } 9 17 10 18 templ RepoFile(rfc RepoFileContext) { ··· 14 22 @repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext) 15 23 { " - " } 16 24 <a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a> 17 - <div class="code"> 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"> 18 28 @templ.Raw(rfc.Code) 29 + <button id="copy" class="absolute top-0 right-0 rounded bg-base hover:bg-surface0"></button> 19 30 </div> 20 31 </div> 21 32 } ··· 23 34 const lineRe = /#L(\d+)(?:-L(\d+))?/g 24 35 const $lineLines = document.querySelectorAll(".chroma .lntable .lnt"); 25 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; 26 43 let start = 0; 27 44 let end = 0; 28 45 ··· 31 48 start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0; 32 49 end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0; 33 50 } 34 - if (start != 0) { 51 + if (start !== 0) { 35 52 deactivateLines(); 36 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); 37 58 } 38 59 39 60 for (let line of $lineLines) { ··· 45 66 if (event.shiftKey) { 46 67 end = n; 47 68 anchor = `#L${start}-L${end}`; 69 + } else if (start === n) { 70 + start = 0; 71 + end = 0; 48 72 } else { 49 73 start = n; 50 74 end = 0; 51 75 anchor = `#L${start}`; 52 76 } 53 - history.replaceState(null, null, anchor); 54 - activateLines(start, end); 77 + history.replaceState(null, null, window.location.pathname + anchor); 78 + $permalink.href = $permalink.dataset.permalink + anchor; 79 + if (start !== 0) activateLines(start, end); 55 80 }); 56 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 + }); 57 94 58 95 function activateLines(start, end) { 59 96 if (end < start) end = start;
+81 -26
internal/html/repo_file_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 12 13 13 type RepoFileContext struct { 14 14 BaseContext 15 15 RepoHeaderComponentContext 16 16 RepoBreadcrumbComponentContext 17 - Code string 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) 18 24 } 19 25 20 26 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) 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) 23 33 if !templ_7745c5c3_IsBuffer { 24 - templ_7745c5c3_Buffer = templ.GetBuffer() 25 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 26 40 } 27 41 ctx = templ.InitializeContext(ctx) 28 42 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 30 44 templ_7745c5c3_Var1 = templ.NopComponent 31 45 } 32 46 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) 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) 35 50 if !templ_7745c5c3_IsBuffer { 36 - templ_7745c5c3_Buffer = templ.GetBuffer() 37 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 38 57 } 58 + ctx = templ.InitializeContext(ctx) 39 59 templ_7745c5c3_Err = repoHeaderComponent(rfc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 40 60 if templ_7745c5c3_Err != nil { 41 61 return templ_7745c5c3_Err 42 62 } 43 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"mt-2 text-text\">") 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"mt-2 text-text\">") 44 64 if templ_7745c5c3_Err != nil { 45 65 return templ_7745c5c3_Err 46 66 } ··· 51 71 var templ_7745c5c3_Var3 string 52 72 templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 53 73 if templ_7745c5c3_Err != nil { 54 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 15, Col: 10} 74 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 23, Col: 10} 55 75 } 56 76 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 57 77 if templ_7745c5c3_Err != nil { 58 78 return templ_7745c5c3_Err 59 79 } 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\">") 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)) 61 116 if templ_7745c5c3_Err != nil { 62 117 return templ_7745c5c3_Err 63 118 } 64 - templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer) 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">permalink</a><div class=\"code relative\">") 65 120 if templ_7745c5c3_Err != nil { 66 121 return templ_7745c5c3_Err 67 122 } 68 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>") 123 + templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer) 69 124 if templ_7745c5c3_Err != nil { 70 125 return templ_7745c5c3_Err 71 126 } 72 - if !templ_7745c5c3_IsBuffer { 73 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 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 74 130 } 75 - return templ_7745c5c3_Err 131 + return nil 76 132 }) 77 133 templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 78 134 if templ_7745c5c3_Err != nil { 79 135 return templ_7745c5c3_Err 80 136 } 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>") 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>") 82 138 if templ_7745c5c3_Err != nil { 83 139 return templ_7745c5c3_Err 84 140 } 85 - if !templ_7745c5c3_IsBuffer { 86 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 87 - } 88 - return templ_7745c5c3_Err 141 + return nil 89 142 }) 90 143 } 144 + 145 + var _ = templruntime.GeneratedTemplate
+3 -4
internal/html/repo_log.templ
··· 5 5 import "go.jolheiser.com/ugit/internal/git" 6 6 7 7 type RepoLogContext struct { 8 - BaseContext 9 - RepoHeaderComponentContext 10 - Commits []git.Commit 8 + BaseContext 9 + RepoHeaderComponentContext 10 + Commits []git.Commit 11 11 } 12 12 13 13 templ RepoLog(rlc RepoLogContext) { ··· 36 36 </div> 37 37 } 38 38 } 39 -
+54 -38
internal/html/repo_log_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import "fmt" 14 12 import "github.com/dustin/go-humanize" ··· 21 19 } 22 20 23 21 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) 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) 26 28 if !templ_7745c5c3_IsBuffer { 27 - templ_7745c5c3_Buffer = templ.GetBuffer() 28 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 29 35 } 30 36 ctx = templ.InitializeContext(ctx) 31 37 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 33 39 templ_7745c5c3_Var1 = templ.NopComponent 34 40 } 35 41 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) 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) 38 45 if !templ_7745c5c3_IsBuffer { 39 - templ_7745c5c3_Buffer = templ.GetBuffer() 40 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 41 52 } 53 + ctx = templ.InitializeContext(ctx) 42 54 templ_7745c5c3_Err = repoHeaderComponent(rlc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 43 55 if templ_7745c5c3_Err != nil { 44 56 return templ_7745c5c3_Err 45 57 } 46 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">") 58 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">") 47 59 if templ_7745c5c3_Err != nil { 48 60 return templ_7745c5c3_Err 49 61 } 50 62 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=\"") 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=\"") 52 64 if templ_7745c5c3_Err != nil { 53 65 return templ_7745c5c3_Err 54 66 } 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))) 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)) 57 73 if templ_7745c5c3_Err != nil { 58 74 return templ_7745c5c3_Err 59 75 } 60 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 76 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">") 61 77 if templ_7745c5c3_Err != nil { 62 78 return templ_7745c5c3_Err 63 79 } ··· 70 86 if templ_7745c5c3_Err != nil { 71 87 return templ_7745c5c3_Err 72 88 } 73 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"whitespace-pre\">") 89 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</a></div><div class=\"whitespace-pre\">") 74 90 if templ_7745c5c3_Err != nil { 75 91 return templ_7745c5c3_Err 76 92 } 77 93 if commit.Details() != "" { 78 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details><summary class=\"cursor-pointer\">") 94 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<details><summary class=\"cursor-pointer\">") 79 95 if templ_7745c5c3_Err != nil { 80 96 return templ_7745c5c3_Err 81 97 } ··· 88 104 if templ_7745c5c3_Err != nil { 89 105 return templ_7745c5c3_Err 90 106 } 91 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary><div class=\"p-3 bg-base rounded\">") 107 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</summary><div class=\"p-3 bg-base rounded\">") 92 108 if templ_7745c5c3_Err != nil { 93 109 return templ_7745c5c3_Err 94 110 } ··· 101 117 if templ_7745c5c3_Err != nil { 102 118 return templ_7745c5c3_Err 103 119 } 104 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></details>") 120 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div></details>") 105 121 if templ_7745c5c3_Err != nil { 106 122 return templ_7745c5c3_Err 107 123 } ··· 116 132 return templ_7745c5c3_Err 117 133 } 118 134 } 119 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"sm:col-span-3 mb-4\"><div>") 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div><div class=\"sm:col-span-3 mb-4\"><div>") 120 136 if templ_7745c5c3_Err != nil { 121 137 return templ_7745c5c3_Err 122 138 } ··· 138 154 if templ_7745c5c3_Err != nil { 139 155 return templ_7745c5c3_Err 140 156 } 141 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 157 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 142 158 if templ_7745c5c3_Err != nil { 143 159 return templ_7745c5c3_Err 144 160 } 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))) 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)) 147 167 if templ_7745c5c3_Err != nil { 148 168 return templ_7745c5c3_Err 149 169 } 150 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 170 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") 151 171 if templ_7745c5c3_Err != nil { 152 172 return templ_7745c5c3_Err 153 173 } ··· 160 180 if templ_7745c5c3_Err != nil { 161 181 return templ_7745c5c3_Err 162 182 } 163 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"") 183 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div><div title=\"") 164 184 if templ_7745c5c3_Err != nil { 165 185 return templ_7745c5c3_Err 166 186 } ··· 173 193 if templ_7745c5c3_Err != nil { 174 194 return templ_7745c5c3_Err 175 195 } 176 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 196 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 177 197 if templ_7745c5c3_Err != nil { 178 198 return templ_7745c5c3_Err 179 199 } ··· 186 206 if templ_7745c5c3_Err != nil { 187 207 return templ_7745c5c3_Err 188 208 } 189 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>") 209 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></div>") 190 210 if templ_7745c5c3_Err != nil { 191 211 return templ_7745c5c3_Err 192 212 } 193 213 } 194 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 214 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div>") 195 215 if templ_7745c5c3_Err != nil { 196 216 return templ_7745c5c3_Err 197 217 } 198 - if !templ_7745c5c3_IsBuffer { 199 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 200 - } 201 - return templ_7745c5c3_Err 218 + return nil 202 219 }) 203 220 templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 204 221 if templ_7745c5c3_Err != nil { 205 222 return templ_7745c5c3_Err 206 223 } 207 - if !templ_7745c5c3_IsBuffer { 208 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 209 - } 210 - return templ_7745c5c3_Err 224 + return nil 211 225 }) 212 226 } 227 + 228 + var _ = templruntime.GeneratedTemplate
+4 -5
internal/html/repo_refs.templ
··· 4 4 import "go.jolheiser.com/ugit/internal/git" 5 5 6 6 type RepoRefsContext struct { 7 - BaseContext 8 - RepoHeaderComponentContext 9 - Branches []string 10 - Tags []git.Tag 7 + BaseContext 8 + RepoHeaderComponentContext 9 + Branches []string 10 + Tags []git.Tag 11 11 } 12 12 13 13 templ RepoRefs(rrc RepoRefsContext) { ··· 39 39 } 40 40 } 41 41 } 42 -
+73 -49
internal/html/repo_refs_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import "fmt" 14 12 import "go.jolheiser.com/ugit/internal/git" ··· 21 19 } 22 20 23 21 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) 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) 26 28 if !templ_7745c5c3_IsBuffer { 27 - templ_7745c5c3_Buffer = templ.GetBuffer() 28 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 29 35 } 30 36 ctx = templ.InitializeContext(ctx) 31 37 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 33 39 templ_7745c5c3_Var1 = templ.NopComponent 34 40 } 35 41 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) 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) 38 45 if !templ_7745c5c3_IsBuffer { 39 - templ_7745c5c3_Buffer = templ.GetBuffer() 40 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 41 52 } 53 + ctx = templ.InitializeContext(ctx) 42 54 templ_7745c5c3_Err = repoHeaderComponent(rrc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 43 55 if templ_7745c5c3_Err != nil { 44 56 return templ_7745c5c3_Err 45 57 } 46 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 58 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 47 59 if templ_7745c5c3_Err != nil { 48 60 return templ_7745c5c3_Err 49 61 } 50 62 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\">") 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\">") 52 64 if templ_7745c5c3_Err != nil { 53 65 return templ_7745c5c3_Err 54 66 } 55 67 for _, branch := range rrc.Branches { 56 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-2 sm:col-span-1 font-bold\">") 68 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"col-span-2 sm:col-span-1 font-bold\">") 57 69 if templ_7745c5c3_Err != nil { 58 70 return templ_7745c5c3_Err 59 71 } ··· 66 78 if templ_7745c5c3_Err != nil { 67 79 return templ_7745c5c3_Err 68 80 } 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=\"") 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=\"") 70 82 if templ_7745c5c3_Err != nil { 71 83 return templ_7745c5c3_Err 72 84 } 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))) 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)) 75 91 if templ_7745c5c3_Err != nil { 76 92 return templ_7745c5c3_Err 77 93 } 78 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>") 94 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">tree</a>") 79 95 if templ_7745c5c3_Err != nil { 80 96 return templ_7745c5c3_Err 81 97 } ··· 88 104 if templ_7745c5c3_Err != nil { 89 105 return templ_7745c5c3_Err 90 106 } 91 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 107 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 92 108 if templ_7745c5c3_Err != nil { 93 109 return templ_7745c5c3_Err 94 110 } 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))) 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)) 97 117 if templ_7745c5c3_Err != nil { 98 118 return templ_7745c5c3_Err 99 119 } 100 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>") 120 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\">log</a></div>") 101 121 if templ_7745c5c3_Err != nil { 102 122 return templ_7745c5c3_Err 103 123 } 104 124 } 105 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 125 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>") 106 126 if templ_7745c5c3_Err != nil { 107 127 return templ_7745c5c3_Err 108 128 } 109 129 } 110 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 130 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ") 111 131 if templ_7745c5c3_Err != nil { 112 132 return templ_7745c5c3_Err 113 133 } 114 134 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\">") 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\">") 116 136 if templ_7745c5c3_Err != nil { 117 137 return templ_7745c5c3_Err 118 138 } 119 139 for _, tag := range rrc.Tags { 120 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-1 font-bold\">") 140 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"col-span-1 font-bold\">") 121 141 if templ_7745c5c3_Err != nil { 122 142 return templ_7745c5c3_Err 123 143 } ··· 130 150 if templ_7745c5c3_Err != nil { 131 151 return templ_7745c5c3_Err 132 152 } 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=\"") 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=\"") 134 154 if templ_7745c5c3_Err != nil { 135 155 return templ_7745c5c3_Err 136 156 } 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))) 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)) 139 163 if templ_7745c5c3_Err != nil { 140 164 return templ_7745c5c3_Err 141 165 } 142 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>") 166 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">tree</a>") 143 167 if templ_7745c5c3_Err != nil { 144 168 return templ_7745c5c3_Err 145 169 } ··· 152 176 if templ_7745c5c3_Err != nil { 153 177 return templ_7745c5c3_Err 154 178 } 155 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 179 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 156 180 if templ_7745c5c3_Err != nil { 157 181 return templ_7745c5c3_Err 158 182 } 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))) 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)) 161 189 if templ_7745c5c3_Err != nil { 162 190 return templ_7745c5c3_Err 163 191 } 164 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>") 192 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">log</a></div>") 165 193 if templ_7745c5c3_Err != nil { 166 194 return templ_7745c5c3_Err 167 195 } 168 196 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>") 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>") 170 198 if templ_7745c5c3_Err != nil { 171 199 return templ_7745c5c3_Err 172 200 } ··· 179 207 if templ_7745c5c3_Err != nil { 180 208 return templ_7745c5c3_Err 181 209 } 182 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></details>") 210 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</code></details>") 183 211 if templ_7745c5c3_Err != nil { 184 212 return templ_7745c5c3_Err 185 213 } 186 214 } 187 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 215 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ") 188 216 if templ_7745c5c3_Err != nil { 189 217 return templ_7745c5c3_Err 190 218 } 191 219 if tag.Annotation != "" { 192 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-8 mb-3\">") 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div class=\"col-span-8 mb-3\">") 193 221 if templ_7745c5c3_Err != nil { 194 222 return templ_7745c5c3_Err 195 223 } ··· 202 230 if templ_7745c5c3_Err != nil { 203 231 return templ_7745c5c3_Err 204 232 } 205 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 233 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>") 206 234 if templ_7745c5c3_Err != nil { 207 235 return templ_7745c5c3_Err 208 236 } 209 237 } 210 238 } 211 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 239 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>") 212 240 if templ_7745c5c3_Err != nil { 213 241 return templ_7745c5c3_Err 214 242 } 215 243 } 216 - if !templ_7745c5c3_IsBuffer { 217 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 218 - } 219 - return templ_7745c5c3_Err 244 + return nil 220 245 }) 221 246 templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 222 247 if templ_7745c5c3_Err != nil { 223 248 return templ_7745c5c3_Err 224 249 } 225 - if !templ_7745c5c3_IsBuffer { 226 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 227 - } 228 - return templ_7745c5c3_Err 250 + return nil 229 251 }) 230 252 } 253 + 254 + var _ = templruntime.GeneratedTemplate
+6 -8
internal/html/repo_search.templ
··· 11 11 12 12 func (s SearchContext) DedupeResults() [][]git.GrepResult { 13 13 var ( 14 - results [][]git.GrepResult 15 - currentFile string 16 - currentResults []git.GrepResult 14 + results [][]git.GrepResult 15 + currentFile string 17 16 ) 17 + var idx int 18 18 for _, result := range s.Results { 19 19 if result.File == currentFile { 20 - currentResults = append(currentResults, result) 20 + results[idx-1] = append(results[idx-1], result) 21 21 continue 22 22 } 23 - if currentFile != "" { 24 - results = append(results, currentResults) 25 - } 23 + results = append(results, []git.GrepResult{result}) 26 24 currentFile = result.File 27 - currentResults = []git.GrepResult{result} 25 + idx++ 28 26 } 29 27 30 28 return results
+76 -57
internal/html/repo_search_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import "fmt" 14 12 import "go.jolheiser.com/ugit/internal/git" ··· 21 19 22 20 func (s SearchContext) DedupeResults() [][]git.GrepResult { 23 21 var ( 24 - results [][]git.GrepResult 25 - currentFile string 26 - currentResults []git.GrepResult 22 + results [][]git.GrepResult 23 + currentFile string 27 24 ) 25 + var idx int 28 26 for _, result := range s.Results { 29 27 if result.File == currentFile { 30 - currentResults = append(currentResults, result) 28 + results[idx-1] = append(results[idx-1], result) 31 29 continue 32 30 } 33 - if currentFile != "" { 34 - results = append(results, currentResults) 35 - } 31 + results = append(results, []git.GrepResult{result}) 36 32 currentFile = result.File 37 - currentResults = []git.GrepResult{result} 33 + idx++ 38 34 } 39 35 40 36 return results 41 37 } 42 38 43 39 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) 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 46 if !templ_7745c5c3_IsBuffer { 47 - templ_7745c5c3_Buffer = templ.GetBuffer() 48 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 49 53 } 50 54 ctx = templ.InitializeContext(ctx) 51 55 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 53 57 templ_7745c5c3_Var1 = templ.NopComponent 54 58 } 55 59 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) 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) 58 63 if !templ_7745c5c3_IsBuffer { 59 - templ_7745c5c3_Buffer = templ.GetBuffer() 60 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 61 70 } 71 + ctx = templ.InitializeContext(ctx) 62 72 templ_7745c5c3_Err = repoHeaderComponent(sc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 63 73 if templ_7745c5c3_Err != nil { 64 74 return templ_7745c5c3_Err ··· 69 79 return templ_7745c5c3_Err 70 80 } 71 81 } 72 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 82 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 73 83 if templ_7745c5c3_Err != nil { 74 84 return templ_7745c5c3_Err 75 85 } 76 86 if len(sc.DedupeResults()) == 0 { 77 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-text mt-5 text-lg\">No results</p>") 87 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"text-text mt-5 text-lg\">No results</p>") 78 88 if templ_7745c5c3_Err != nil { 79 89 return templ_7745c5c3_Err 80 90 } 81 91 } 82 - if !templ_7745c5c3_IsBuffer { 83 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 84 - } 85 - return templ_7745c5c3_Err 92 + return nil 86 93 }) 87 94 templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 88 95 if templ_7745c5c3_Err != nil { 89 96 return templ_7745c5c3_Err 90 97 } 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>") 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>") 92 99 if templ_7745c5c3_Err != nil { 93 100 return templ_7745c5c3_Err 94 101 } 95 - if !templ_7745c5c3_IsBuffer { 96 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 97 - } 98 - return templ_7745c5c3_Err 102 + return nil 99 103 }) 100 104 } 101 105 102 106 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) 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) 105 113 if !templ_7745c5c3_IsBuffer { 106 - templ_7745c5c3_Buffer = templ.GetBuffer() 107 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 108 120 } 109 121 ctx = templ.InitializeContext(ctx) 110 122 templ_7745c5c3_Var3 := templ.GetChildren(ctx) ··· 112 124 templ_7745c5c3_Var3 = templ.NopComponent 113 125 } 114 126 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=\"") 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=\"") 116 128 if templ_7745c5c3_Err != nil { 117 129 return templ_7745c5c3_Err 118 130 } 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))) 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)) 121 137 if templ_7745c5c3_Err != nil { 122 138 return templ_7745c5c3_Err 123 139 } 124 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 140 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 125 141 if templ_7745c5c3_Err != nil { 126 142 return templ_7745c5c3_Err 127 143 } 128 144 var templ_7745c5c3_Var5 string 129 145 templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 130 146 if templ_7745c5c3_Err != nil { 131 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 50, Col: 230} 147 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 230} 132 148 } 133 149 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 134 150 if templ_7745c5c3_Err != nil { 135 151 return templ_7745c5c3_Err 136 152 } 137 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code\">") 153 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a></div><div class=\"code\">") 138 154 if templ_7745c5c3_Err != nil { 139 155 return templ_7745c5c3_Err 140 156 } ··· 142 158 if templ_7745c5c3_Err != nil { 143 159 return templ_7745c5c3_Err 144 160 } 145 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 146 162 if templ_7745c5c3_Err != nil { 147 163 return templ_7745c5c3_Err 148 164 } 149 165 if len(results) > 1 { 150 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text cursor-pointer\"><summary>") 166 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<details class=\"text-text cursor-pointer\"><summary>") 151 167 if templ_7745c5c3_Err != nil { 152 168 return templ_7745c5c3_Err 153 169 } 154 170 var templ_7745c5c3_Var6 string 155 171 templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:]))) 156 172 if templ_7745c5c3_Err != nil { 157 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 50} 173 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 54, Col: 50} 158 174 } 159 175 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 160 176 if templ_7745c5c3_Err != nil { 161 177 return templ_7745c5c3_Err 162 178 } 163 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("more</summary> ") 179 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "more</summary> ") 164 180 if templ_7745c5c3_Err != nil { 165 181 return templ_7745c5c3_Err 166 182 } 167 183 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=\"") 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=\"") 169 185 if templ_7745c5c3_Err != nil { 170 186 return templ_7745c5c3_Err 171 187 } 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))) 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)) 174 194 if templ_7745c5c3_Err != nil { 175 195 return templ_7745c5c3_Err 176 196 } 177 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">") 178 198 if templ_7745c5c3_Err != nil { 179 199 return templ_7745c5c3_Err 180 200 } 181 201 var templ_7745c5c3_Var8 string 182 202 templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 183 203 if templ_7745c5c3_Err != nil { 184 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 58, Col: 230} 204 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 230} 185 205 } 186 206 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 187 207 if templ_7745c5c3_Err != nil { 188 208 return templ_7745c5c3_Err 189 209 } 190 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code ml-5\">") 210 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</a></div><div class=\"code ml-5\">") 191 211 if templ_7745c5c3_Err != nil { 192 212 return templ_7745c5c3_Err 193 213 } ··· 195 215 if templ_7745c5c3_Err != nil { 196 216 return templ_7745c5c3_Err 197 217 } 198 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 218 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>") 199 219 if templ_7745c5c3_Err != nil { 200 220 return templ_7745c5c3_Err 201 221 } 202 222 } 203 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</details>") 223 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</details>") 204 224 if templ_7745c5c3_Err != nil { 205 225 return templ_7745c5c3_Err 206 226 } 207 227 } 208 - if !templ_7745c5c3_IsBuffer { 209 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 210 - } 211 - return templ_7745c5c3_Err 228 + return nil 212 229 }) 213 230 } 231 + 232 + var _ = templruntime.GeneratedTemplate
+65 -40
internal/html/repo_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import "fmt" 14 12 ··· 21 19 } 22 20 23 21 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) 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) 26 28 if !templ_7745c5c3_IsBuffer { 27 - templ_7745c5c3_Buffer = templ.GetBuffer() 28 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 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 + }() 29 35 } 30 36 ctx = templ.InitializeContext(ctx) 31 37 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 33 39 templ_7745c5c3_Var1 = templ.NopComponent 34 40 } 35 41 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=\"") 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=\"") 37 43 if templ_7745c5c3_Err != nil { 38 44 return templ_7745c5c3_Err 39 45 } 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))) 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)) 42 52 if templ_7745c5c3_Err != nil { 43 53 return templ_7745c5c3_Err 44 54 } 45 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 55 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">") 46 56 if templ_7745c5c3_Err != nil { 47 57 return templ_7745c5c3_Err 48 58 } ··· 55 65 if templ_7745c5c3_Err != nil { 56 66 return templ_7745c5c3_Err 57 67 } 58 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 68 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</a> ") 59 69 if templ_7745c5c3_Err != nil { 60 70 return templ_7745c5c3_Err 61 71 } ··· 69 79 if templ_7745c5c3_Err != nil { 70 80 return templ_7745c5c3_Err 71 81 } 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=\"") 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=\"") 73 83 if templ_7745c5c3_Err != nil { 74 84 return templ_7745c5c3_Err 75 85 } 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))) 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)) 78 92 if templ_7745c5c3_Err != nil { 79 93 return templ_7745c5c3_Err 80 94 } 81 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 95 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 82 96 if templ_7745c5c3_Err != nil { 83 97 return templ_7745c5c3_Err 84 98 } ··· 91 105 if templ_7745c5c3_Err != nil { 92 106 return templ_7745c5c3_Err 93 107 } 94 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 108 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 95 109 if templ_7745c5c3_Err != nil { 96 110 return templ_7745c5c3_Err 97 111 } ··· 105 119 if templ_7745c5c3_Err != nil { 106 120 return templ_7745c5c3_Err 107 121 } 108 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 122 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 109 123 if templ_7745c5c3_Err != nil { 110 124 return templ_7745c5c3_Err 111 125 } 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))) 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)) 114 132 if templ_7745c5c3_Err != nil { 115 133 return templ_7745c5c3_Err 116 134 } 117 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">refs</a> ") 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">refs</a> ") 118 136 if templ_7745c5c3_Err != nil { 119 137 return templ_7745c5c3_Err 120 138 } ··· 127 145 if templ_7745c5c3_Err != nil { 128 146 return templ_7745c5c3_Err 129 147 } 130 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 148 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 131 149 if templ_7745c5c3_Err != nil { 132 150 return templ_7745c5c3_Err 133 151 } 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))) 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)) 136 158 if templ_7745c5c3_Err != nil { 137 159 return templ_7745c5c3_Err 138 160 } 139 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a> ") 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">log</a> ") 140 162 if templ_7745c5c3_Err != nil { 141 163 return templ_7745c5c3_Err 142 164 } ··· 149 171 if templ_7745c5c3_Err != nil { 150 172 return templ_7745c5c3_Err 151 173 } 152 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form class=\"inline-block\" action=\"") 174 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<form class=\"inline-block\" action=\"") 153 175 if templ_7745c5c3_Err != nil { 154 176 return templ_7745c5c3_Err 155 177 } 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))) 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)) 158 184 if templ_7745c5c3_Err != nil { 159 185 return templ_7745c5c3_Err 160 186 } 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>") 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>") 162 188 if templ_7745c5c3_Err != nil { 163 189 return templ_7745c5c3_Err 164 190 } ··· 171 197 if templ_7745c5c3_Err != nil { 172 198 return templ_7745c5c3_Err 173 199 } 174 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">") 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\">") 175 201 if templ_7745c5c3_Err != nil { 176 202 return templ_7745c5c3_Err 177 203 } ··· 184 210 if templ_7745c5c3_Err != nil { 185 211 return templ_7745c5c3_Err 186 212 } 187 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</pre></div><div class=\"text-subtext0 mb-1\">") 213 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</pre></div><div class=\"text-subtext0 mb-1\">") 188 214 if templ_7745c5c3_Err != nil { 189 215 return templ_7745c5c3_Err 190 216 } 191 217 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\">") 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\">") 193 219 if templ_7745c5c3_Err != nil { 194 220 return templ_7745c5c3_Err 195 221 } ··· 202 228 if templ_7745c5c3_Err != nil { 203 229 return templ_7745c5c3_Err 204 230 } 205 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>") 231 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</span>") 206 232 if templ_7745c5c3_Err != nil { 207 233 return templ_7745c5c3_Err 208 234 } 209 235 } 210 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"text-text/80 mb-1\">") 236 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"text-text/80 mb-1\">") 211 237 if templ_7745c5c3_Err != nil { 212 238 return templ_7745c5c3_Err 213 239 } ··· 220 246 if templ_7745c5c3_Err != nil { 221 247 return templ_7745c5c3_Err 222 248 } 223 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 249 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>") 224 250 if templ_7745c5c3_Err != nil { 225 251 return templ_7745c5c3_Err 226 252 } 227 - if !templ_7745c5c3_IsBuffer { 228 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 229 - } 230 - return templ_7745c5c3_Err 253 + return nil 231 254 }) 232 255 } 256 + 257 + var _ = templruntime.GeneratedTemplate
+65 -44
internal/html/repo_tree_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.707 3 + // templ: version: v0.3.924 4 4 package html 5 5 6 6 //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 7 8 8 import "github.com/a-h/templ" 9 - import "context" 10 - import "io" 11 - import "bytes" 9 + import templruntime "github.com/a-h/templ/runtime" 12 10 13 11 import ( 14 12 "fmt" ··· 25 23 } 26 24 27 25 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) 26 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 27 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 28 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 29 + return templ_7745c5c3_CtxErr 30 + } 31 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 30 32 if !templ_7745c5c3_IsBuffer { 31 - templ_7745c5c3_Buffer = templ.GetBuffer() 32 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 33 + defer func() { 34 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 35 + if templ_7745c5c3_Err == nil { 36 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 37 + } 38 + }() 33 39 } 34 40 ctx = templ.InitializeContext(ctx) 35 41 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 37 43 templ_7745c5c3_Var1 = templ.NopComponent 38 44 } 39 45 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) 46 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 47 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 48 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 42 49 if !templ_7745c5c3_IsBuffer { 43 - templ_7745c5c3_Buffer = templ.GetBuffer() 44 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 50 + defer func() { 51 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 52 + if templ_7745c5c3_Err == nil { 53 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 54 + } 55 + }() 45 56 } 57 + ctx = templ.InitializeContext(ctx) 46 58 templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 47 59 if templ_7745c5c3_Err != nil { 48 60 return templ_7745c5c3_Err 49 61 } 50 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 62 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 51 63 if templ_7745c5c3_Err != nil { 52 64 return templ_7745c5c3_Err 53 65 } ··· 55 67 if templ_7745c5c3_Err != nil { 56 68 return templ_7745c5c3_Err 57 69 } 58 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 70 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") 59 71 if templ_7745c5c3_Err != nil { 60 72 return templ_7745c5c3_Err 61 73 } ··· 63 75 if templ_7745c5c3_Err != nil { 64 76 return templ_7745c5c3_Err 65 77 } 66 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 78 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") 67 79 if templ_7745c5c3_Err != nil { 68 80 return templ_7745c5c3_Err 69 81 } ··· 71 83 if templ_7745c5c3_Err != nil { 72 84 return templ_7745c5c3_Err 73 85 } 74 - if !templ_7745c5c3_IsBuffer { 75 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 76 - } 77 - return templ_7745c5c3_Err 86 + return nil 78 87 }) 79 88 templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 80 89 if templ_7745c5c3_Err != nil { 81 90 return templ_7745c5c3_Err 82 91 } 83 - if !templ_7745c5c3_IsBuffer { 84 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 85 - } 86 - return templ_7745c5c3_Err 92 + return nil 87 93 }) 88 94 } 89 95 ··· 102 108 } 103 109 104 110 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) 111 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 112 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 113 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 114 + return templ_7745c5c3_CtxErr 115 + } 116 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 107 117 if !templ_7745c5c3_IsBuffer { 108 - templ_7745c5c3_Buffer = templ.GetBuffer() 109 - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) 118 + defer func() { 119 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 120 + if templ_7745c5c3_Err == nil { 121 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 122 + } 123 + }() 110 124 } 111 125 ctx = templ.InitializeContext(ctx) 112 126 templ_7745c5c3_Var3 := templ.GetChildren(ctx) ··· 114 128 templ_7745c5c3_Var3 = templ.NopComponent 115 129 } 116 130 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\">") 131 + 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\">") 118 132 if templ_7745c5c3_Err != nil { 119 133 return templ_7745c5c3_Err 120 134 } 121 135 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=\"") 136 + 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=\"") 123 137 if templ_7745c5c3_Err != nil { 124 138 return templ_7745c5c3_Err 125 139 } 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))) 140 + var templ_7745c5c3_Var4 templ.SafeURL 141 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back))) 142 + if templ_7745c5c3_Err != nil { 143 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 44, Col: 194} 144 + } 145 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 128 146 if templ_7745c5c3_Err != nil { 129 147 return templ_7745c5c3_Err 130 148 } 131 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">..</a></div>") 149 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">..</a></div>") 132 150 if templ_7745c5c3_Err != nil { 133 151 return templ_7745c5c3_Err 134 152 } 135 153 } 136 154 for _, fi := range rtcc.Tree { 137 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-1 break-keep\">") 155 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"sm:col-span-1 break-keep\">") 138 156 if templ_7745c5c3_Err != nil { 139 157 return templ_7745c5c3_Err 140 158 } ··· 147 165 if templ_7745c5c3_Err != nil { 148 166 return templ_7745c5c3_Err 149 167 } 150 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-right\">") 168 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div><div class=\"sm:col-span-1 text-right\">") 151 169 if templ_7745c5c3_Err != nil { 152 170 return templ_7745c5c3_Err 153 171 } ··· 160 178 if templ_7745c5c3_Err != nil { 161 179 return templ_7745c5c3_Err 162 180 } 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=\"") 181 + 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=\"") 164 182 if templ_7745c5c3_Err != nil { 165 183 return templ_7745c5c3_Err 166 184 } 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))) 185 + var templ_7745c5c3_Var7 templ.SafeURL 186 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path))) 187 + if templ_7745c5c3_Err != nil { 188 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 222} 189 + } 190 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 169 191 if templ_7745c5c3_Err != nil { 170 192 return templ_7745c5c3_Err 171 193 } 172 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 194 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") 173 195 if templ_7745c5c3_Err != nil { 174 196 return templ_7745c5c3_Err 175 197 } ··· 182 204 if templ_7745c5c3_Err != nil { 183 205 return templ_7745c5c3_Err 184 206 } 185 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>") 207 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div>") 186 208 if templ_7745c5c3_Err != nil { 187 209 return templ_7745c5c3_Err 188 210 } 189 211 } 190 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 212 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>") 191 213 if templ_7745c5c3_Err != nil { 192 214 return templ_7745c5c3_Err 193 215 } 194 - if !templ_7745c5c3_IsBuffer { 195 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 196 - } 197 - return templ_7745c5c3_Err 216 + return nil 198 217 }) 199 218 } 219 + 220 + var _ = templruntime.GeneratedTemplate
+1 -1
internal/html/tailwind.config.js
··· 1 1 /** @type {import('tailwindcss').Config} */ 2 2 module.exports = { 3 - content: ["./**/*.templ"], 3 + content: ["./*.go"], 4 4 plugins: [require("@catppuccin/tailwindcss")], 5 5 } 6 6
+1 -1
internal/html/tailwind.go
··· 5 5 6 6 func TailwindHandler(w http.ResponseWriter, r *http.Request) { 7 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))}}")) 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 9 }
+5 -4
internal/http/http.go
··· 18 18 // Server is the container struct for the HTTP server 19 19 type Server struct { 20 20 port int 21 - mux *chi.Mux 21 + Mux *chi.Mux 22 22 } 23 23 24 24 // ListenAndServe simply wraps http.ListenAndServe to contain the functionality here 25 25 func (s Server) ListenAndServe() error { 26 - return http.ListenAndServe(fmt.Sprintf("localhost:%d", s.port), s.mux) 26 + return http.ListenAndServe(fmt.Sprintf("localhost:%d", s.port), s.Mux) 27 27 } 28 28 29 29 // Settings is the configuration for the HTTP server ··· 34 34 Port int 35 35 RepoDir string 36 36 Profile Profile 37 + ShowPrivate bool 37 38 } 38 39 39 40 // Profile is the index profile ··· 101 102 r.Get("/tailwind.css", html.TailwindHandler) 102 103 }) 103 104 104 - return Server{mux: mux, port: settings.Port} 105 + return Server{Mux: mux, port: settings.Port} 105 106 } 106 107 107 108 type repoHandler struct { ··· 125 126 Name: chi.URLParam(r, "repo"), 126 127 Ref: ref, 127 128 CloneURL: rh.s.CloneURL, 128 - Tags: repo.Meta.Tags, 129 + Tags: repo.Meta.Tags.Slice(), 129 130 } 130 131 } 131 132
+2 -3
internal/http/httperr/httperr.go
··· 2 2 3 3 import ( 4 4 "errors" 5 + "log/slog" 5 6 "net/http" 6 - 7 - "github.com/charmbracelet/log" 8 7 ) 9 8 10 9 type httpError struct { ··· 41 40 status = httpErr.status 42 41 } 43 42 44 - log.Error(err) 43 + slog.Error("httperr Handler error", "error", err) 45 44 http.Error(w, http.StatusText(status), status) 46 45 } 47 46 }
+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
··· 3 3 import ( 4 4 "net/http" 5 5 "os" 6 - "slices" 7 6 "sort" 8 7 "strings" 9 8 "time" ··· 31 30 return httperr.Error(err) 32 31 } 33 32 if repo.Meta.Private { 34 - continue 33 + if !rh.s.ShowPrivate { 34 + continue 35 + } 36 + repo.Meta.Tags.Add("private") 35 37 } 36 - if tagFilter != "" && !slices.Contains(repo.Meta.Tags, strings.ToLower(tagFilter)) { 38 + 39 + if tagFilter != "" && !repo.Meta.Tags.Contains(strings.ToLower(tagFilter)) { 37 40 continue 38 41 } 39 42 repos = append(repos, repo)
+4 -1
internal/http/middleware.go
··· 27 27 return httperr.Status(err, httpErr) 28 28 } 29 29 if repo.Meta.Private { 30 - return httperr.Status(errors.New("could not get git repo"), http.StatusNotFound) 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") 31 34 } 32 35 r = r.WithContext(context.WithValue(r.Context(), repoCtxKey, repo)) 33 36 next.ServeHTTP(w, r)
+12 -3
internal/http/repo.go
··· 88 88 } 89 89 90 90 var buf bytes.Buffer 91 - if err := markup.Code.Convert([]byte(content), filepath.Base(path), &buf); err != nil { 91 + if err := markup.Convert([]byte(content), filepath.Base(path), "L", &buf); err != nil { 92 92 return httperr.Error(err) 93 93 } 94 94 95 + commit := ref 96 + if len(ref) < 40 { 97 + commitObj, err := repo.GetCommitFromRef(ref) 98 + if err == nil { 99 + commit = commitObj.Hash.String() 100 + } 101 + } 102 + 95 103 if err := html.RepoFile(html.RepoFileContext{ 96 104 BaseContext: rh.baseContext(), 97 105 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 98 106 RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 99 107 Code: buf.String(), 108 + Commit: commit, 109 + Path: path, 100 110 }).Render(r.Context(), w); err != nil { 101 111 return httperr.Error(err) 102 112 } ··· 158 168 159 169 for idx, p := range commit.Files { 160 170 var patch bytes.Buffer 161 - if err := markup.Code.Basic([]byte(p.Patch), "commit.patch", &patch); err != nil { 171 + if err := markup.Convert([]byte(p.Patch), "commit.patch", p.Path()+"-L", &patch); err != nil { 162 172 return httperr.Error(err) 163 173 } 164 174 commit.Files[idx].Patch = patch.String() ··· 206 216 } 207 217 results[idx].Content = buf.String() 208 218 } 209 - 210 219 } 211 220 212 221 if err := html.RepoSearch(html.SearchContext{
-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 - }
+2 -2
internal/ssh/ssh.go
··· 2 2 3 3 import ( 4 4 "fmt" 5 + "log" 5 6 6 - "github.com/charmbracelet/log" 7 7 "github.com/charmbracelet/ssh" 8 8 "github.com/charmbracelet/wish" 9 9 "github.com/charmbracelet/wish/logging" ··· 42 42 func (a hooks) Fetch(_ string, _ ssh.PublicKey) {} 43 43 44 44 var ( 45 - DefaultLogger logging.Logger = log.StandardLog() 45 + DefaultLogger logging.Logger = log.Default() 46 46 NoopLogger logging.Logger = noopLogger{} 47 47 ) 48 48
+3 -13
internal/ssh/wish.go
··· 5 5 "errors" 6 6 "fmt" 7 7 "io/fs" 8 + "log/slog" 8 9 "os" 9 10 "path/filepath" 10 11 "strings" ··· 12 13 13 14 "go.jolheiser.com/ugit/internal/git" 14 15 15 - "github.com/charmbracelet/log" 16 16 "github.com/charmbracelet/ssh" 17 17 "github.com/charmbracelet/wish" 18 18 ) ··· 91 91 if errors.Is(err, ErrInvalidRepo) { 92 92 Fatal(s, ErrInvalidRepo) 93 93 } 94 - log.Error("unknown git error", "error", err) 94 + slog.Error("unknown git error", "error", err) 95 95 Fatal(s, ErrSystemMalfunction) 96 96 } 97 97 gh.Fetch(repo, pk) ··· 103 103 if len(cmd) == 0 { 104 104 des, err := os.ReadDir(repoDir) 105 105 if err != nil && err != fs.ErrNotExist { 106 - log.Error("invalid repository", "error", err) 106 + slog.Error("invalid repository", "error", err) 107 107 } 108 108 tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 109 109 for _, de := range des { ··· 122 122 } 123 123 tw.Flush() 124 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 125 sh(s) 136 126 } 137 127 }
+10
nix/default.nix
··· 1 + { 2 + pkgs ? import <nixpkgs> { }, 3 + }: 4 + let 5 + pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; }; 6 + in 7 + { 8 + ugit = pkg; 9 + default = pkg; 10 + }
+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
··· 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
··· 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 + }