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

Compare changes

Choose any two refs to compare.

+2833 -1566
+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
+51 -10
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 10 "github.com/peterbourgon/ff/v3" 9 - "go.jolheiser.com/ffdhall" 11 + "go.jolheiser.com/ffcue" 10 12 ) 11 13 14 + //go:embed args.cue 15 + var schema string 16 + 12 17 type cliArgs struct { 13 - Debug bool 14 - RepoDir string 15 - SSH sshArgs 16 - HTTP httpArgs 17 - Meta metaArgs 18 - Profile profileArgs 18 + RepoDir string 19 + SSH sshArgs 20 + HTTP httpArgs 21 + Meta metaArgs 22 + Profile profileArgs 23 + Log logArgs 24 + ShowPrivate bool 19 25 } 20 26 21 27 type sshArgs struct { 28 + Enable bool 22 29 AuthorizedKeys string 23 30 CloneURL string 24 31 Port int ··· 26 33 } 27 34 28 35 type httpArgs struct { 36 + Enable bool 29 37 CloneURL string 30 38 Port int 31 39 } ··· 46 54 URL string 47 55 } 48 56 57 + type logArgs struct { 58 + Level slog.Level 59 + JSON bool 60 + } 61 + 49 62 func parseArgs(args []string) (c cliArgs, e error) { 50 63 fs := flag.NewFlagSet("ugitd", flag.ContinueOnError) 51 - fs.String("config", "ugit.dhall", "Path to config file") 64 + fs.String("config", "ugit.cue", "Path to config file") 52 65 53 66 c = cliArgs{ 54 67 RepoDir: ".ugit", 55 68 SSH: sshArgs{ 69 + Enable: true, 56 70 AuthorizedKeys: ".ssh/authorized_keys", 57 71 CloneURL: "ssh://localhost:8448", 58 72 Port: 8448, 59 73 HostKey: ".ssh/ugit_ed25519", 60 74 }, 61 75 HTTP: httpArgs{ 76 + Enable: true, 62 77 CloneURL: "http://localhost:8449", 63 78 Port: 8449, 64 79 }, ··· 66 81 Title: "ugit", 67 82 Description: "Minimal git server", 68 83 }, 84 + Log: logArgs{ 85 + Level: slog.LevelError, 86 + }, 69 87 } 70 88 71 - fs.BoolVar(&c.Debug, "debug", c.Debug, "Debug logging") 89 + fs.Func("log.level", "Logging level", func(s string) error { 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) 102 + } 103 + c.Log.Level = lvl 104 + return nil 105 + }) 106 + fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format") 72 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") 73 110 fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys") 74 111 fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base") 75 112 fs.IntVar(&c.SSH.Port, "ssh.port", c.SSH.Port, "SSH port") 76 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") 77 115 fs.StringVar(&c.HTTP.CloneURL, "http.clone-url", c.HTTP.CloneURL, "HTTP clone URL base") 78 116 fs.IntVar(&c.HTTP.Port, "http.port", c.HTTP.Port, "HTTP port") 79 117 fs.StringVar(&c.Meta.Title, "meta.title", c.Meta.Title, "App title") ··· 92 130 return nil 93 131 }) 94 132 133 + parser := &ffcue.ParseConfig{ 134 + Constraints: schema, 135 + } 95 136 return c, ff.Parse(fs, args, 96 137 ff.WithEnvVarPrefix("UGIT"), 97 138 ff.WithConfigFileFlag("config"), 98 139 ff.WithAllowMissingConfigFile(true), 99 - ff.WithConfigFileParser(ffdhall.DhallParser), 140 + ff.WithConfigFileParser(parser.Parse), 100 141 ) 101 142 }
+55 -30
cmd/ugitd/main.go
··· 4 4 "errors" 5 5 "flag" 6 6 "fmt" 7 + "log" 8 + "log/slog" 7 9 "os" 8 10 "os/signal" 9 11 "path/filepath" 10 12 "strconv" 11 13 "strings" 14 + "syscall" 12 15 16 + "github.com/go-chi/chi/v5/middleware" 17 + "github.com/go-chi/httplog/v2" 13 18 "github.com/go-git/go-git/v5/plumbing/protocol/packp" 19 + "github.com/go-git/go-git/v5/utils/trace" 14 20 "go.jolheiser.com/ugit/internal/git" 15 - 16 21 "go.jolheiser.com/ugit/internal/http" 17 22 "go.jolheiser.com/ugit/internal/ssh" 18 - 19 - "github.com/charmbracelet/log" 20 - "github.com/go-chi/chi/v5/middleware" 21 - "github.com/go-git/go-git/v5/utils/trace" 22 23 ) 23 24 24 25 func main() { ··· 39 40 panic(err) 40 41 } 41 42 42 - if args.Debug { 43 + slog.SetLogLoggerLevel(args.Log.Level) 44 + middleware.DefaultLogger = httplog.RequestLogger(httplog.NewLogger("ugit", httplog.Options{ 45 + JSON: args.Log.JSON, 46 + LogLevel: slog.Level(args.Log.Level), 47 + Concise: args.Log.Level != slog.LevelDebug, 48 + })) 49 + 50 + if args.Log.Level == slog.LevelDebug { 43 51 trace.SetTarget(trace.Packet) 44 - log.SetLevel(log.DebugLevel) 45 52 } else { 46 53 middleware.DefaultLogger = http.NoopLogger 47 54 ssh.DefaultLogger = ssh.NoopLogger 48 55 } 49 56 57 + if args.Log.JSON { 58 + logger := slog.New(slog.NewJSONHandler(os.Stderr, nil)) 59 + slog.SetDefault(logger) 60 + } 61 + 50 62 if err := requiredFS(args.RepoDir); err != nil { 51 63 panic(err) 52 64 } 53 65 54 - sshSettings := ssh.Settings{ 55 - AuthorizedKeys: args.SSH.AuthorizedKeys, 56 - CloneURL: args.SSH.CloneURL, 57 - Port: args.SSH.Port, 58 - HostKey: args.SSH.HostKey, 59 - RepoDir: args.RepoDir, 60 - } 61 - sshSrv, err := ssh.New(sshSettings) 62 - if err != nil { 63 - panic(err) 64 - } 65 - go func() { 66 - fmt.Printf("SSH listening on ssh://localhost:%d\n", sshSettings.Port) 67 - 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 { 68 76 panic(err) 69 77 } 70 - }() 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 + } 71 85 72 86 httpSettings := http.Settings{ 73 87 Title: args.Meta.Title, ··· 79 93 Username: args.Profile.Username, 80 94 Email: args.Profile.Email, 81 95 }, 96 + ShowPrivate: args.ShowPrivate, 82 97 } 83 98 for _, link := range args.Profile.Links { 84 99 httpSettings.Profile.Links = append(httpSettings.Profile.Links, http.Link{ ··· 86 101 URL: link.URL, 87 102 }) 88 103 } 89 - httpSrv := http.New(httpSettings) 90 - go func() { 91 - fmt.Printf("HTTP listening on http://localhost:%d\n", httpSettings.Port) 92 - if err := httpSrv.ListenAndServe(); err != nil { 93 - panic(err) 94 - } 95 - }() 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 + } 96 113 97 114 ch := make(chan os.Signal, 1) 98 - signal.Notify(ch, os.Kill, os.Interrupt) 115 + signal.Notify(ch, syscall.SIGTERM, os.Interrupt) 99 116 <-ch 100 117 } 101 118 ··· 118 135 } 119 136 fp = filepath.Join(fp, "pre-receive") 120 137 138 + if err := os.MkdirAll(fp+".d", os.ModePerm); err != nil { 139 + return err 140 + } 141 + 121 142 fi, err := os.Create(fp) 122 143 if err != nil { 123 144 return err 124 145 } 125 146 fi.WriteString("#!/usr/bin/env bash\n") 126 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)) 127 152 fi.Close() 128 153 129 154 return os.Chmod(fp, 0o755)
+2
config.cue
··· 1 + http: port: 1 2 + ssh: port: 1
+1 -1
contrib/dev.nu
··· 14 14 mkdir .ugit 15 15 for $repo in $repos { 16 16 git clone --bare $"($base_url)/($repo).git" $".ugit/($repo).git" 17 - {"private": false, "description": $repo} | save $".ugit/($repo).git/ugit.json" 17 + {"private": false, "description": $repo, "tags": ["git", "dev", "mirror", "archive"]} | save $".ugit/($repo).git/ugit.json" 18 18 } 19 19 }
+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": 1704161960, 45 - "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", 5 + "lastModified": 1755205935, 6 + "narHash": "sha256-EQ6qHuJWguaoBZyxdqsgJqyEdS77k+2CnlKrfFxlkRY=", 46 7 "owner": "nixos", 47 8 "repo": "nixpkgs", 48 - "rev": "63143ac2c9186be6d9da6035fa22620018c85932", 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 -158
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" 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" 42 31 ]; 43 - ldflags = [ 44 - "-s" 45 - "-w" 46 - "-extldflags -static" 47 - ]; 48 - meta = with pkgs.lib; { 49 - description = "Minimal git server"; 50 - homepage = "https://git.jolheiser.com/ugit"; 51 - maintainers = with maintainers; [jolheiser]; 52 - mainProgram = "ugitd"; 53 - }; 54 - }; 55 - in { 56 - packages.${system}.default = ugit; 57 - devShells.${system}.default = pkgs.mkShell { 58 - nativeBuildInputs = with pkgs; [ 59 - go 60 - gopls 61 - gomod2nix.legacyPackages.${system}.gomod2nix 62 - templ 63 - tailwind-ctp 64 - tailwind-ctp-lsp 65 - vscode-langservers-extracted 66 - ]; 67 - }; 68 - nixosModules.default = { 69 - pkgs, 70 - lib, 71 - config, 72 - ... 73 - }: let 74 - cfg = config.services.ugit; 75 - yamlFormat = pkgs.formats.yaml {}; 76 - configFile = pkgs.writeText "ugit.yaml" (builtins.readFile (yamlFormat.generate "ugit-yaml" cfg.config)); 77 - authorizedKeysFile = pkgs.writeText "ugit_keys" (builtins.concatStringsSep "\n" cfg.authorizedKeys); 78 - in { 79 - options = with lib; { 80 - services.ugit = { 81 - enable = mkEnableOption "Enable ugit"; 82 - 83 - package = mkOption { 84 - type = types.package; 85 - description = "ugit package to use"; 86 - default = ugit; 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 + ]; 87 53 }; 88 - 89 - repoDir = mkOption { 90 - type = types.str; 91 - description = "where ugit stores repositories"; 92 - default = "/var/lib/ugit/repos"; 93 - }; 94 - 95 - authorizedKeys = mkOption { 96 - type = types.listOf types.str; 97 - description = "list of keys to use for authorized_keys"; 98 - default = []; 99 - }; 100 - 101 - authorizedKeysFile = mkOption { 102 - type = types.str; 103 - description = "path to authorized_keys file ugit uses for auth"; 104 - default = "/var/lib/ugit/authorized_keys"; 105 - }; 106 - 107 - hostKeyFile = mkOption { 108 - type = types.str; 109 - description = "path to host key file (will be created if it doesn't exist)"; 110 - default = "/var/lib/ugit/ugit_ed25519"; 111 - }; 112 - 113 - config = mkOption { 114 - type = types.attrs; 115 - default = {}; 116 - description = "config.yaml contents"; 117 - }; 118 - 119 - user = mkOption { 120 - type = types.str; 121 - default = "ugit"; 122 - description = "User account under which ugit runs"; 123 - }; 124 - 125 - group = mkOption { 126 - type = types.str; 127 - default = "ugit"; 128 - description = "Group account under which ugit runs"; 129 - }; 130 - 131 - debug = mkOption { 132 - type = types.bool; 133 - default = false; 134 - }; 135 - 136 - openFirewall = mkOption { 137 - type = types.bool; 138 - default = false; 139 - }; 140 - }; 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 + ]; 141 70 }; 142 - config = lib.mkIf cfg.enable { 143 - users.users."${cfg.user}" = { 144 - home = "/var/lib/ugit"; 145 - createHome = true; 146 - group = "${cfg.group}"; 147 - isSystemUser = true; 148 - isNormalUser = false; 149 - description = "user for ugit service"; 150 - }; 151 - users.groups."${cfg.group}" = {}; 152 - networking.firewall = lib.mkIf cfg.openFirewall { 153 - allowedTCPPorts = [8448 8449]; 154 - }; 155 - 156 - systemd.services.ugit = { 157 - enable = true; 158 - script = let 159 - authorizedKeysPath = 160 - if (builtins.length cfg.authorizedKeys) > 0 161 - then authorizedKeysFile 162 - else cfg.authorizedKeysFile; 163 - args = ["--config=${configFile}" "--repo-dir=${cfg.repoDir}" "--ssh.authorized-keys=${authorizedKeysPath}" "--ssh.host-key=${cfg.hostKeyFile}"] ++ lib.optionals cfg.debug ["--debug"]; 164 - in "${cfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}"; 165 - wantedBy = ["multi-user.target"]; 166 - after = ["network.target"]; 167 - path = [cfg.package pkgs.git pkgs.bash]; 168 - serviceConfig = { 169 - User = cfg.user; 170 - Group = cfg.group; 171 - Restart = "always"; 172 - RestartSec = "15"; 173 - 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 + ''}"; 174 84 }; 175 - }; 176 - }; 85 + } 86 + ); 177 87 }; 178 - }; 179 88 }
+70 -47
go.mod
··· 1 1 module go.jolheiser.com/ugit 2 2 3 - go 1.22.3 3 + go 1.23.1 4 + 5 + toolchain go1.23.3 4 6 5 7 require ( 6 - github.com/a-h/templ v0.2.543 7 - github.com/alecthomas/chroma/v2 v2.12.0 8 - github.com/charmbracelet/log v0.3.1 9 - github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560 10 - 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 11 13 github.com/dustin/go-humanize v1.0.1 12 - github.com/go-chi/chi/v5 v5.0.11 13 - github.com/go-git/go-billy/v5 v5.5.0 14 - github.com/go-git/go-git/v5 v5.11.0 14 + github.com/go-chi/chi/v5 v5.2.0 15 + github.com/go-chi/httplog/v2 v2.1.1 16 + github.com/go-git/go-billy/v5 v5.6.1 17 + github.com/go-git/go-git/v5 v5.13.1 15 18 github.com/peterbourgon/ff/v3 v3.4.0 16 - github.com/yuin/goldmark v1.6.0 17 - 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 18 21 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc 19 - golang.org/x/net v0.20.0 22 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75 23 + golang.org/x/net v0.42.0 20 24 ) 21 25 22 26 require ( 23 - dario.cat/mergo v1.0.0 // indirect 24 - github.com/Microsoft/go-winio v0.6.1 // indirect 25 - 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 26 34 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 27 35 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 28 - github.com/charmbracelet/bubbletea v0.25.0 // indirect 29 - github.com/charmbracelet/keygen v0.5.0 // indirect 30 - github.com/charmbracelet/lipgloss v0.9.1 // indirect 31 - github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 // indirect 32 - github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60 // indirect 33 - github.com/cloudflare/circl v1.3.7 // indirect 34 - github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 // indirect 35 - github.com/creack/pty v1.1.21 // indirect 36 - github.com/cyphar/filepath-securejoin v0.2.4 // indirect 37 - 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 38 54 github.com/emirpasic/gods v1.18.1 // indirect 39 - github.com/fxamacker/cbor/v2 v2.2.1-0.20200511212021-28e39be4a84f // indirect 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 40 58 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 41 59 github.com/go-logfmt/logfmt v0.6.0 // indirect 42 - 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 43 63 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 44 64 github.com/kevinburke/ssh_config v1.2.0 // indirect 45 65 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 66 + github.com/mattn/go-colorable v0.1.13 // indirect 46 67 github.com/mattn/go-isatty v0.0.20 // indirect 47 68 github.com/mattn/go-localereader v0.0.1 // indirect 48 - github.com/mattn/go-runewidth v0.0.15 // 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 49 72 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 50 73 github.com/muesli/cancelreader v0.2.2 // indirect 51 - github.com/muesli/reflow v0.3.0 // indirect 52 - github.com/muesli/termenv v0.15.2 // indirect 53 - github.com/philandstuff/dhall-golang/v6 v6.0.2 // indirect 54 - github.com/pjbgf/sha1cd v0.3.0 // indirect 55 - github.com/rivo/uniseg v0.4.6 // indirect 56 - github.com/sergi/go-diff v1.3.1 // indirect 57 - github.com/skeema/knownhosts v1.2.1 // indirect 58 - github.com/u-root/u-root v0.12.0 // indirect 59 - github.com/x448/float16 v0.8.4 // 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 80 + github.com/rivo/uniseg v0.4.7 // indirect 81 + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 82 + github.com/skeema/knownhosts v1.3.0 // indirect 60 83 github.com/xanzy/ssh-agent v0.3.3 // indirect 61 - go.jolheiser.com/ffdhall v0.0.1 // indirect 62 - golang.org/x/crypto v0.18.0 // indirect 63 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect 64 - golang.org/x/mod v0.14.0 // indirect 65 - golang.org/x/sync v0.6.0 // indirect 66 - golang.org/x/sys v0.16.0 // indirect 67 - golang.org/x/term v0.16.0 // indirect 68 - golang.org/x/text v0.14.0 // indirect 69 - golang.org/x/tools v0.17.0 // 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 70 91 gopkg.in/warnings.v0 v0.1.2 // indirect 71 - gopkg.in/yaml.v2 v2.4.0 // indirect 92 + gopkg.in/yaml.v3 v3.0.1 // indirect 72 93 ) 94 + 95 + tool github.com/a-h/templ/cmd/templ
+1 -1
go.mod.sri
··· 1 - sha256-8kI94hcJupAUye6cEAmIlN+CrtYSXlgoAlmpyXArfF8= 1 + sha256-DjweXB8uqEpOIBwGabLCnVL4ZOKkPcJDf6JlAS5FmKI=
+158 -178
go.sum
··· 1 - dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= 2 - dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 3 - github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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= 4 7 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 5 - github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= 6 - github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= 7 - github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= 8 - github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= 9 - github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk= 10 - github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA= 11 - github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= 12 - 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= 13 18 github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= 14 - github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw= 15 - 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= 16 21 github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= 17 - github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= 18 - 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= 19 26 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 20 27 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 21 28 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 22 29 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 23 30 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 24 31 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 25 - github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= 26 - github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= 27 - github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= 28 - github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc= 29 - github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8= 30 - github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= 31 - github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= 32 - github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw= 33 - github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g= 34 - github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560 h1:kUYiDRF04AsyJvWi4HrklXXSU7+S7qjExusfDnYbVGg= 35 - github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560/go.mod h1:IHy7o73i1MrQ5lmyJjjJ0g7y4+V+g69cm+Y7JCiZWPo= 36 - github.com/charmbracelet/wish v1.3.0 h1:SYV5TIlzDb6WaxjkkYXxv2WZsTu/QZGwfGVc0UB5M48= 37 - github.com/charmbracelet/wish v1.3.0/go.mod h1:1U/bI7zX+IE26ThD5gxtLgeRzctVhSrTpjucPqw4Pos= 38 - github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 h1:u0XFhTN81zvoGwyQWOYjjkrimEQj5L2DPECCX5cBsRw= 39 - github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= 40 - github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60 h1:IV19YKUZVf6ATrhiPSCirZ4Bs7EsenYwOWcUHngV+q0= 41 - github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:kOOxxyxgAFQVcR5yQJWTuLjzt5dR2pcgwy3WaLEudjE= 42 - github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= 43 - github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= 44 - github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= 45 - github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 h1:Ig+OPkE3XQrrl+SKsOqAjlkrBN/zrr+Qpw7rCuDjRCE= 46 - github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= 47 - github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 48 - github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= 49 - github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 50 - github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= 51 - 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= 52 66 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 53 - github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 54 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= 55 70 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 56 71 github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 57 - github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= 58 - 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= 59 74 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 60 75 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 61 - github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= 62 - 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= 63 80 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 64 81 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 65 - github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 66 - github.com/fxamacker/cbor/v2 v2.2.1-0.20200511212021-28e39be4a84f h1:lvGFo/tDOSQ4FKu0d2694s8XyOfAL6FLR9DCD5BIUW4= 67 - github.com/fxamacker/cbor/v2 v2.2.1-0.20200511212021-28e39be4a84f/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= 68 - github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= 69 - github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= 70 - github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= 71 - github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 82 + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 83 + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 84 + github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 85 + github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 86 + github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 87 + github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 88 + github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 89 + github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= 90 + github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= 91 + github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 92 + github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk= 93 + github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE= 72 94 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= 73 95 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 74 - github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= 75 - 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= 76 98 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= 77 99 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= 78 - github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= 79 - 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= 80 102 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 81 103 github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 82 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 83 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 84 - github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 85 - github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 86 - 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= 87 112 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 88 113 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 89 - github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 90 - github.com/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f h1:ov45/OzrJG8EKbGjn7jJZQJTN7Z1t73sFYNIRd64YlI= 91 - github.com/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f/go.mod h1:JoDrYMZpDPYo6uH9/f6Peqms3zNNWT2XiGgioMOIGuI= 92 114 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 93 115 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 94 116 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= ··· 100 122 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 101 123 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 102 124 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 103 - github.com/leanovate/gopter v0.2.5-0.20190402064358-634a59d12406/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= 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= 104 129 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 105 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= 106 134 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 107 135 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 108 136 github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 109 137 github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 110 - github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 111 - github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= 112 - github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 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= 113 144 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 114 145 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 115 146 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 116 147 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 117 - github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= 118 - github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= 119 - github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= 120 - github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= 121 - github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 122 - github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 123 - github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 124 - github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= 125 - 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= 126 160 github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= 127 161 github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= 128 - github.com/philandstuff/dhall-golang/v6 v6.0.2 h1:jv8fi4ZYiFe6uGrprx6dY7L3xPcgmEqWZo3s8ABCzkw= 129 - github.com/philandstuff/dhall-golang/v6 v6.0.2/go.mod h1:XRoxjsqZM2y7KPFhjV7CSVdWpV5CwuTzGjAY/v+1SUU= 130 - github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= 131 - github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= 132 - github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= 133 164 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 134 165 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 135 - github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 136 166 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 137 - 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= 138 171 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 139 - github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg= 140 - github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 141 - github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= 142 - github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 143 - github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 144 - github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= 145 - github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= 146 - github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 172 + github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 173 + github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= 147 178 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 148 - github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= 149 - 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= 150 181 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 151 182 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 152 183 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 153 184 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 154 - github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 155 - github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 156 - github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa h1:unMPGGK/CRzfg923allsikmvk2l7beBeFPUNC4RVX/8= 157 - github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa/go.mod h1:Zj4Tt22fJVn/nz/y6Ergm1SahR9dio1Zm/D2/S0TmXM= 158 - github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs= 159 - github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI= 160 - github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 161 - github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 162 - github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 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= 163 187 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 164 188 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 165 - github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 166 - github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 167 189 github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 168 - github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= 169 - github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 170 - github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s= 171 - 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= 172 195 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 173 196 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 174 - go.jolheiser.com/ffdhall v0.0.1 h1:HOTMUTXvUItpitv/xKEVN5stYhpSXTPlShNiERBfutA= 175 - go.jolheiser.com/ffdhall v0.0.1/go.mod h1:7VdNxVDYnHUa0WEqTms9cHqnOnyh41Mal2vot+P4O48= 176 - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 177 - 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= 178 199 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 179 - golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 180 - golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 181 - golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= 182 - golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 183 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= 184 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= 185 - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 186 - golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 187 - golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= 188 - golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 189 - golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 190 - golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 191 - golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 192 - 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= 193 206 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 194 - golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 195 - golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= 196 - golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 197 - golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 198 - golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= 199 - golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 200 - golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 201 - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 202 - golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 203 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 204 - golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 205 - golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= 206 - golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 207 - golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 208 - golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 209 - golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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= 210 213 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 211 214 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 212 215 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 213 216 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 214 217 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 215 - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 218 + golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 216 219 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 217 - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 218 - golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 219 - golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 220 - golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 221 - 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= 222 221 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 223 - golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 224 - golang.org/x/sys v0.16.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= 225 224 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 226 - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 227 - golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 228 - golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 229 - golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 230 - golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= 231 - golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= 232 - golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 233 - 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= 234 227 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 235 - golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 236 - golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 237 - golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 238 - golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 239 - golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 240 - golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 228 + golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= 229 + golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 241 230 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 242 - golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 243 - golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 244 - golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 245 - golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= 246 - golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= 247 - 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= 248 233 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 249 - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 250 234 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 251 235 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 252 236 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 253 - gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 254 - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 255 237 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 256 238 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 257 - gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 258 239 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 259 - gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 260 240 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 261 241 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 262 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 }
+64 -1
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 15 Description string `json:"description"` 14 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 15 68 } 16 69 17 70 // Update updates meta given another RepoMeta ··· 45 98 return json.NewEncoder(fi).Encode(r.Meta) 46 99 } 47 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 + 48 111 func ensureJSONFile(path string) error { 49 112 _, err := os.Stat(path) 50 113 if err == nil { ··· 58 121 return err 59 122 } 60 123 defer fi.Close() 61 - if _, err := fi.WriteString(`{"private":true}`); err != nil { 124 + if _, err := fi.Write(defaultMeta); err != nil { 62 125 return err 63 126 } 64 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 + }
+15
internal/git/protocol.go
··· 50 50 } 51 51 changed = repo.Meta.Private != private 52 52 repo.Meta.Private = private 53 + case "tags": 54 + tagValues := strings.Split(opt.Value, ",") 55 + for _, tagValue := range tagValues { 56 + var remove bool 57 + if strings.HasPrefix(tagValue, "-") { 58 + remove = true 59 + tagValue = strings.TrimPrefix(tagValue, "-") 60 + } 61 + tagValue = strings.ToLower(tagValue) 62 + if remove { 63 + repo.Meta.Tags.Remove(tagValue) 64 + } else { 65 + repo.Meta.Tags.Add(tagValue) 66 + } 67 + } 53 68 } 54 69 } 55 70 if changed {
-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>
+31 -25
internal/html/base_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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 } 35 41 var templ_7745c5c3_Var2 string 36 42 templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title) 37 43 if templ_7745c5c3_Err != nil { 38 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 13, Col: 20} 44 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 14, Col: 20} 39 45 } 40 46 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 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 } 48 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(bc.Title)) 54 + var templ_7745c5c3_Var3 string 55 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title) 49 56 if templ_7745c5c3_Err != nil { 50 - return templ_7745c5c3_Err 57 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 17, Col: 47} 51 58 } 52 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><meta property=\"og:description\" content=\"") 59 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 53 60 if templ_7745c5c3_Err != nil { 54 61 return templ_7745c5c3_Err 55 62 } 56 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(bc.Description)) 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta property=\"og:description\" content=\"") 57 64 if templ_7745c5c3_Err != nil { 58 65 return templ_7745c5c3_Err 59 66 } 60 - _, 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=\"/\">") 67 + var templ_7745c5c3_Var4 string 68 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Description) 61 69 if templ_7745c5c3_Err != nil { 62 - return templ_7745c5c3_Err 70 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 18, Col: 59} 63 71 } 64 - templ_7745c5c3_Var3 := `Home` 65 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) 72 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 66 73 if templ_7745c5c3_Err != nil { 67 74 return templ_7745c5c3_Err 68 75 } 69 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</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>") 70 77 if templ_7745c5c3_Err != nil { 71 78 return templ_7745c5c3_Err 72 79 } ··· 74 81 if templ_7745c5c3_Err != nil { 75 82 return templ_7745c5c3_Err 76 83 } 77 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>") 84 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>") 78 85 if templ_7745c5c3_Err != nil { 79 86 return templ_7745c5c3_Err 80 87 } 81 - if !templ_7745c5c3_IsBuffer { 82 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 83 - } 84 - return templ_7745c5c3_Err 88 + return nil 85 89 }) 86 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("}")
+43 -15
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 9 12 Profile IndexProfile 10 - Repos []*git.Repo 13 + Repos []*git.Repo 11 14 } 12 15 13 16 type IndexProfile struct { 14 17 Username string 15 - Email string 16 - Links []IndexLink 18 + Email string 19 + Links []IndexLink 17 20 } 18 21 19 22 type IndexLink struct { 20 23 Name string 21 - URL string 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> ··· 45 56 } 46 57 if ic.Profile.Email != "" { 47 58 <div class="text-mauve col-span-2"> 48 - <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle">@templ.Raw(string(assets.EmailIcon))</div> 59 + <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle"> 60 + @templ.Raw(string(assets.EmailIcon)) 61 + </div> 49 62 <a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL("mailto:" + ic.Profile.Email) }>{ ic.Profile.Email }</a> 50 63 </div> 51 64 } ··· 53 66 <div class="grid grid-cols-1 sm:grid-cols-8"> 54 67 for _, link := range ic.Profile.Links { 55 68 <div class="text-mauve"> 56 - <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle">@templ.Raw(string(assets.LinkIcon))</div> 69 + <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle"> 70 + @templ.Raw(string(assets.LinkIcon)) 71 + </div> 57 72 <a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" rel="me" href={ templ.SafeURL(link.URL) }>{ link.Name }</a> 58 73 </div> 59 74 } 60 75 </div> 61 - <div class="grid sm:grid-cols-8 gap-1 mt-5"> 76 + <div class="grid sm:grid-cols-10 gap-2 mt-5"> 62 77 for _, repo := range ic.Repos { 63 - <div class="sm:col-span-1 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> 64 - <div class="sm:col-span-5 text-subtext0">{ repo.Meta.Description }</div> 65 - <div class="sm:col-span-2 text-text/80 mb-4 sm:mb-0" title={ lastCommit(repo, false) }>{ lastCommit(repo, true) }</div> 78 + {{ commit := lastCommit(repo) }} 79 + <div class="sm:col-span-2 text-blue dark:text-lavender"><a class="underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ templ.URL("/" + repo.Name()) }>{ repo.Name() }</a></div> 80 + <div class="sm:col-span-3 text-subtext0">{ repo.Meta.Description }</div> 81 + <div class="sm:col-span-3 text-subtext0"> 82 + if commit != nil { 83 + <div title={ commit.Message }> 84 + <a class="underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA) }>{ commit.Short() }</a> 85 + { ": " + commit.Summary() } 86 + </div> 87 + } 88 + </div> 89 + <div class="sm:col-span-1 text-subtext0"> 90 + for _, tag := range repo.Meta.Tags.Slice() { 91 + <a href={ templ.SafeURL("?tag=" + tag) } class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</a> 92 + } 93 + </div> 94 + <div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommitTime(repo, false) }>{ lastCommitTime(repo, true) }</div> 66 95 } 67 96 </div> 68 97 </main> 69 98 } 70 99 } 71 -
+199 -64
internal/html/index_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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: 37, 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: 38, 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: 43, 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: 48, 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: 56, 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-1 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-1 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: 62, 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-5 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: 63, 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-2 text-text/80 mb-4 sm:mb-0\" title=\"") 265 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div><div class=\"sm:col-span-3 text-subtext0\">") 266 + if templ_7745c5c3_Err != nil { 267 + return templ_7745c5c3_Err 268 + } 269 + if commit != nil { 270 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div title=\"") 271 + if templ_7745c5c3_Err != nil { 272 + return templ_7745c5c3_Err 273 + } 274 + var templ_7745c5c3_Var13 string 275 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message) 276 + if templ_7745c5c3_Err != nil { 277 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 34} 278 + } 279 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 280 + if templ_7745c5c3_Err != nil { 281 + return templ_7745c5c3_Err 282 + } 283 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\"><a class=\"underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"") 284 + if templ_7745c5c3_Err != nil { 285 + return templ_7745c5c3_Err 286 + } 287 + var templ_7745c5c3_Var14 templ.SafeURL 288 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinURLErrs(fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA)) 289 + if templ_7745c5c3_Err != nil { 290 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 206} 291 + } 292 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 293 + if templ_7745c5c3_Err != nil { 294 + return templ_7745c5c3_Err 295 + } 296 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">") 297 + if templ_7745c5c3_Err != nil { 298 + return templ_7745c5c3_Err 299 + } 300 + var templ_7745c5c3_Var15 string 301 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short()) 302 + if templ_7745c5c3_Err != nil { 303 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 225} 304 + } 305 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 306 + if templ_7745c5c3_Err != nil { 307 + return templ_7745c5c3_Err 308 + } 309 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</a> ") 310 + if templ_7745c5c3_Err != nil { 311 + return templ_7745c5c3_Err 312 + } 313 + var templ_7745c5c3_Var16 string 314 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(": " + commit.Summary()) 315 + if templ_7745c5c3_Err != nil { 316 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 85, Col: 33} 317 + } 318 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 319 + if templ_7745c5c3_Err != nil { 320 + return templ_7745c5c3_Err 321 + } 322 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div>") 323 + if templ_7745c5c3_Err != nil { 324 + return templ_7745c5c3_Err 325 + } 326 + } 327 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</div><div class=\"sm:col-span-1 text-subtext0\">") 328 + if templ_7745c5c3_Err != nil { 329 + return templ_7745c5c3_Err 330 + } 331 + for _, tag := range repo.Meta.Tags.Slice() { 332 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"") 333 + if templ_7745c5c3_Err != nil { 334 + return templ_7745c5c3_Err 335 + } 336 + var templ_7745c5c3_Var17 templ.SafeURL 337 + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?tag=" + tag)) 338 + if templ_7745c5c3_Err != nil { 339 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 45} 340 + } 341 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 342 + if templ_7745c5c3_Err != nil { 343 + return templ_7745c5c3_Err 344 + } 345 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">") 346 + if templ_7745c5c3_Err != nil { 347 + return templ_7745c5c3_Err 348 + } 349 + var templ_7745c5c3_Var18 string 350 + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(tag) 351 + if templ_7745c5c3_Err != nil { 352 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 141} 353 + } 354 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 355 + if templ_7745c5c3_Err != nil { 356 + return templ_7745c5c3_Err 357 + } 358 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a>") 359 + if templ_7745c5c3_Err != nil { 360 + return templ_7745c5c3_Err 361 + } 362 + } 363 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"") 230 364 if templ_7745c5c3_Err != nil { 231 365 return templ_7745c5c3_Err 232 366 } 233 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(lastCommit(repo, false))) 367 + var templ_7745c5c3_Var19 string 368 + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, false)) 369 + if templ_7745c5c3_Err != nil { 370 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 93} 371 + } 372 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 234 373 if templ_7745c5c3_Err != nil { 235 374 return templ_7745c5c3_Err 236 375 } 237 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 376 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\">") 238 377 if templ_7745c5c3_Err != nil { 239 378 return templ_7745c5c3_Err 240 379 } 241 - var templ_7745c5c3_Var13 string 242 - templ_7745c5c3_Var13, 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)) 243 382 if templ_7745c5c3_Err != nil { 244 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 64, Col: 116} 383 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 124} 245 384 } 246 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 385 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) 247 386 if templ_7745c5c3_Err != nil { 248 387 return templ_7745c5c3_Err 249 388 } 250 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 389 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</div>") 251 390 if templ_7745c5c3_Err != nil { 252 391 return templ_7745c5c3_Err 253 392 } 254 393 } 255 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></main>") 394 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</div></main>") 256 395 if templ_7745c5c3_Err != nil { 257 396 return templ_7745c5c3_Err 258 397 } 259 - if !templ_7745c5c3_IsBuffer { 260 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 261 - } 262 - return templ_7745c5c3_Err 398 + return nil 263 399 }) 264 400 templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 265 401 if templ_7745c5c3_Err != nil { 266 402 return templ_7745c5c3_Err 267 403 } 268 - if !templ_7745c5c3_IsBuffer { 269 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 270 - } 271 - return templ_7745c5c3_Err 404 + return nil 272 405 }) 273 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.501 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
+6
internal/html/repo.templ
··· 7 7 Ref string 8 8 Description string 9 9 CloneURL string 10 + Tags []string 10 11 } 11 12 12 13 templ repoHeaderComponent(rhcc RepoHeaderComponentContext) { ··· 24 25 <form class="inline-block" action={ templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)) } 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> 25 26 { " - " } 26 27 <pre class="text-text inline select-all bg-base dark:bg-base/50 p-1 rounded">{ fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name) }</pre> 28 + </div> 29 + <div class="text-subtext0 mb-1"> 30 + for _, tag := range rhcc.Tags { 31 + <span class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</span> 32 + } 27 33 </div> 28 34 <div class="text-text/80 mb-1">{ rhcc.Description }</div> 29 35 }
+52
internal/html/repo_breadcrumb.templ
··· 1 + package html 2 + 3 + import ( 4 + "fmt" 5 + "path" 6 + "strings" 7 + ) 8 + 9 + type RepoBreadcrumbComponentContext struct { 10 + Repo string 11 + Ref string 12 + Path string 13 + } 14 + 15 + type breadcrumb struct { 16 + label string 17 + href string 18 + end bool 19 + } 20 + 21 + func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb { 22 + parts := strings.Split(r.Path, "/") 23 + breadcrumbs := []breadcrumb{ 24 + { 25 + label: r.Repo, 26 + href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref), 27 + }, 28 + } 29 + for idx, part := range parts { 30 + breadcrumbs = append(breadcrumbs, breadcrumb{ 31 + label: part, 32 + href: path.Join(breadcrumbs[idx].href, part), 33 + }) 34 + } 35 + breadcrumbs[len(breadcrumbs)-1].end = true 36 + return breadcrumbs 37 + } 38 + 39 + templ repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) { 40 + if rbcc.Path != "" { 41 + <div class="inline-block text-text"> 42 + for _, crumb := range rbcc.crumbs() { 43 + if crumb.end { 44 + <span>{ crumb.label }</span> 45 + } else { 46 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(crumb.href) }>{ crumb.label }</a> 47 + { " / " } 48 + } 49 + } 50 + </div> 51 + } 52 + }
+143
internal/html/repo_breadcrumb_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import ( 12 + "fmt" 13 + "path" 14 + "strings" 15 + ) 16 + 17 + type RepoBreadcrumbComponentContext struct { 18 + Repo string 19 + Ref string 20 + Path string 21 + } 22 + 23 + type breadcrumb struct { 24 + label string 25 + href string 26 + end bool 27 + } 28 + 29 + func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb { 30 + parts := strings.Split(r.Path, "/") 31 + breadcrumbs := []breadcrumb{ 32 + { 33 + label: r.Repo, 34 + href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref), 35 + }, 36 + } 37 + for idx, part := range parts { 38 + breadcrumbs = append(breadcrumbs, breadcrumb{ 39 + label: part, 40 + href: path.Join(breadcrumbs[idx].href, part), 41 + }) 42 + } 43 + breadcrumbs[len(breadcrumbs)-1].end = true 44 + return breadcrumbs 45 + } 46 + 47 + func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) templ.Component { 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) 54 + if !templ_7745c5c3_IsBuffer { 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 + }() 61 + } 62 + ctx = templ.InitializeContext(ctx) 63 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 64 + if templ_7745c5c3_Var1 == nil { 65 + templ_7745c5c3_Var1 = templ.NopComponent 66 + } 67 + ctx = templ.ClearChildren(ctx) 68 + if rbcc.Path != "" { 69 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"inline-block text-text\">") 70 + if templ_7745c5c3_Err != nil { 71 + return templ_7745c5c3_Err 72 + } 73 + for _, crumb := range rbcc.crumbs() { 74 + if crumb.end { 75 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span>") 76 + if templ_7745c5c3_Err != nil { 77 + return templ_7745c5c3_Err 78 + } 79 + var templ_7745c5c3_Var2 string 80 + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label) 81 + if templ_7745c5c3_Err != nil { 82 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 44, Col: 24} 83 + } 84 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 85 + if templ_7745c5c3_Err != nil { 86 + return templ_7745c5c3_Err 87 + } 88 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span>") 89 + if templ_7745c5c3_Err != nil { 90 + return templ_7745c5c3_Err 91 + } 92 + } else { 93 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 94 + if templ_7745c5c3_Err != nil { 95 + return templ_7745c5c3_Err 96 + } 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)) 103 + if templ_7745c5c3_Err != nil { 104 + return templ_7745c5c3_Err 105 + } 106 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 107 + if templ_7745c5c3_Err != nil { 108 + return templ_7745c5c3_Err 109 + } 110 + var templ_7745c5c3_Var4 string 111 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label) 112 + if templ_7745c5c3_Err != nil { 113 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 46, Col: 134} 114 + } 115 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 116 + if templ_7745c5c3_Err != nil { 117 + return templ_7745c5c3_Err 118 + } 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 120 + if templ_7745c5c3_Err != nil { 121 + return templ_7745c5c3_Err 122 + } 123 + var templ_7745c5c3_Var5 string 124 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" / ") 125 + if templ_7745c5c3_Err != nil { 126 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 47, Col: 12} 127 + } 128 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 129 + if templ_7745c5c3_Err != nil { 130 + return templ_7745c5c3_Err 131 + } 132 + } 133 + } 134 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 135 + if templ_7745c5c3_Err != nil { 136 + return templ_7745c5c3_Err 137 + } 138 + } 139 + return nil 140 + }) 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 -
+203 -144
internal/html/repo_commit_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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))) 52 64 if templ_7745c5c3_Err != nil { 53 - return templ_7745c5c3_Err 65 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 213} 54 66 } 55 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 67 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 56 68 if templ_7745c5c3_Err != nil { 57 69 return templ_7745c5c3_Err 58 70 } 59 - templ_7745c5c3_Var4 := `tree` 60 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4) 71 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">tree</a>") 61 72 if templ_7745c5c3_Err != nil { 62 73 return templ_7745c5c3_Err 63 74 } 64 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 65 - if templ_7745c5c3_Err != nil { 66 - return templ_7745c5c3_Err 67 - } 68 - var templ_7745c5c3_Var5 string 69 - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 75 + var templ_7745c5c3_Var4 string 76 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 70 77 if templ_7745c5c3_Err != nil { 71 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 15, Col: 229} 78 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 229} 72 79 } 73 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 80 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 74 81 if templ_7745c5c3_Err != nil { 75 82 return templ_7745c5c3_Err 76 83 } 77 - _, 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=\"") 78 85 if templ_7745c5c3_Err != nil { 79 86 return templ_7745c5c3_Err 80 87 } 81 - var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) 82 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6))) 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))) 83 90 if templ_7745c5c3_Err != nil { 84 - return templ_7745c5c3_Err 91 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 412} 85 92 } 86 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 93 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 87 94 if templ_7745c5c3_Err != nil { 88 95 return templ_7745c5c3_Err 89 96 } 90 - templ_7745c5c3_Var7 := `log` 91 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7) 97 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\">log</a>") 92 98 if templ_7745c5c3_Err != nil { 93 99 return templ_7745c5c3_Err 94 100 } 95 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 101 + var templ_7745c5c3_Var6 string 102 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 96 103 if templ_7745c5c3_Err != nil { 97 - return templ_7745c5c3_Err 98 - } 99 - var templ_7745c5c3_Var8 string 100 - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 101 - if templ_7745c5c3_Err != nil { 102 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 15, Col: 427} 103 - } 104 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 105 - if templ_7745c5c3_Err != nil { 106 - return templ_7745c5c3_Err 104 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 427} 107 105 } 108 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 106 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 109 107 if templ_7745c5c3_Err != nil { 110 108 return templ_7745c5c3_Err 111 109 } 112 - var templ_7745c5c3_Var9 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) 113 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var9))) 110 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 114 111 if templ_7745c5c3_Err != nil { 115 112 return templ_7745c5c3_Err 116 113 } 117 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 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))) 118 116 if templ_7745c5c3_Err != nil { 119 - return templ_7745c5c3_Err 117 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 619} 120 118 } 121 - templ_7745c5c3_Var10 := `patch` 122 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10) 119 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 123 120 if templ_7745c5c3_Err != nil { 124 121 return templ_7745c5c3_Err 125 122 } 126 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</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\">") 127 124 if templ_7745c5c3_Err != nil { 128 125 return templ_7745c5c3_Err 129 126 } 130 - var templ_7745c5c3_Var11 string 131 - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Message) 127 + var templ_7745c5c3_Var8 string 128 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Message) 132 129 if templ_7745c5c3_Err != nil { 133 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 85} 130 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 17, Col: 85} 134 131 } 135 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 132 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 136 133 if templ_7745c5c3_Err != nil { 137 134 return templ_7745c5c3_Err 138 135 } 139 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 136 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 140 137 if templ_7745c5c3_Err != nil { 141 138 return templ_7745c5c3_Err 142 139 } 143 140 if rcc.Commit.Signature != "" { 144 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text whitespace-pre\"><summary class=\"cursor-pointer\">") 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>") 145 142 if templ_7745c5c3_Err != nil { 146 143 return templ_7745c5c3_Err 147 144 } 148 - templ_7745c5c3_Var12 := `Signature` 149 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12) 145 + var templ_7745c5c3_Var9 string 146 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Signature) 150 147 if templ_7745c5c3_Err != nil { 151 - return templ_7745c5c3_Err 148 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 21, Col: 65} 152 149 } 153 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary><div class=\"p-3 bg-base rounded\"><code>") 150 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 154 151 if templ_7745c5c3_Err != nil { 155 152 return templ_7745c5c3_Err 156 153 } 157 - var templ_7745c5c3_Var13 string 158 - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Signature) 159 - if templ_7745c5c3_Err != nil { 160 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 20, Col: 65} 161 - } 162 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 163 - if templ_7745c5c3_Err != nil { 164 - return templ_7745c5c3_Err 165 - } 166 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></div></details>") 154 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</code></div></details>") 167 155 if templ_7745c5c3_Err != nil { 168 156 return templ_7745c5c3_Err 169 157 } 170 158 } 171 - _, 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>") 172 160 if templ_7745c5c3_Err != nil { 173 161 return templ_7745c5c3_Err 174 162 } 175 - var templ_7745c5c3_Var14 string 176 - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Author) 163 + var templ_7745c5c3_Var10 string 164 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Author) 177 165 if templ_7745c5c3_Err != nil { 178 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 24, Col: 27} 166 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 27} 179 167 } 180 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 168 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 181 169 if templ_7745c5c3_Err != nil { 182 170 return templ_7745c5c3_Err 183 171 } 184 - var templ_7745c5c3_Var15 string 185 - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 172 + var templ_7745c5c3_Var11 string 173 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 186 174 if templ_7745c5c3_Err != nil { 187 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 24, Col: 34} 175 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 34} 188 176 } 189 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 177 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 190 178 if templ_7745c5c3_Err != nil { 191 179 return templ_7745c5c3_Err 192 180 } 193 - _, 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=\"") 194 182 if templ_7745c5c3_Err != nil { 195 183 return templ_7745c5c3_Err 196 184 } 197 - var templ_7745c5c3_Var16 templ.SafeURL = templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)) 198 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var16))) 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)) 199 191 if templ_7745c5c3_Err != nil { 200 192 return templ_7745c5c3_Err 201 193 } 202 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 194 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 203 195 if templ_7745c5c3_Err != nil { 204 196 return templ_7745c5c3_Err 205 197 } 206 - var templ_7745c5c3_Var17 string 207 - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", rcc.Commit.Email)) 198 + var templ_7745c5c3_Var13 string 199 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", rcc.Commit.Email)) 208 200 if templ_7745c5c3_Err != nil { 209 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 24, Col: 223} 201 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 223} 210 202 } 211 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 203 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 212 204 if templ_7745c5c3_Err != nil { 213 205 return templ_7745c5c3_Err 214 206 } 215 - _, 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=\"") 216 208 if templ_7745c5c3_Err != nil { 217 209 return templ_7745c5c3_Err 218 210 } 219 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(rcc.Commit.When.Format("01/02/2006 03:04:05 PM"))) 211 + var templ_7745c5c3_Var14 string 212 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.When.Format("01/02/2006 03:04:05 PM")) 213 + if templ_7745c5c3_Err != nil { 214 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 64} 215 + } 216 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 220 217 if templ_7745c5c3_Err != nil { 221 218 return templ_7745c5c3_Err 222 219 } 223 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\">") 224 221 if templ_7745c5c3_Err != nil { 225 222 return templ_7745c5c3_Err 226 223 } 227 - var templ_7745c5c3_Var18 string 228 - templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(rcc.Commit.When)) 224 + var templ_7745c5c3_Var15 string 225 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(rcc.Commit.When)) 229 226 if templ_7745c5c3_Err != nil { 230 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 99} 227 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 99} 231 228 } 232 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 229 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 233 230 if templ_7745c5c3_Err != nil { 234 231 return templ_7745c5c3_Err 235 232 } 236 - _, 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\">") 237 234 if templ_7745c5c3_Err != nil { 238 235 return templ_7745c5c3_Err 239 236 } 240 - var templ_7745c5c3_Var19 string 241 - templ_7745c5c3_Var19, 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)) 237 + var templ_7745c5c3_Var16 string 238 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions)) 242 239 if templ_7745c5c3_Err != nil { 243 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 27, Col: 179} 240 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 29, Col: 184} 241 + } 242 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 243 + if templ_7745c5c3_Err != nil { 244 + return templ_7745c5c3_Err 244 245 } 245 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 246 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</summary><div class=\"p-3 bg-base rounded\">") 246 247 if templ_7745c5c3_Err != nil { 247 248 return templ_7745c5c3_Err 248 249 } 249 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 250 + for _, file := range rcc.Commit.Files { 251 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<a class=\"block underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 252 + if templ_7745c5c3_Err != nil { 253 + return templ_7745c5c3_Err 254 + } 255 + var templ_7745c5c3_Var17 templ.SafeURL 256 + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs("#" + file.Path()) 257 + if templ_7745c5c3_Err != nil { 258 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 116} 259 + } 260 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 261 + if templ_7745c5c3_Err != nil { 262 + return templ_7745c5c3_Err 263 + } 264 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">") 265 + if templ_7745c5c3_Err != nil { 266 + return templ_7745c5c3_Err 267 + } 268 + var templ_7745c5c3_Var18 string 269 + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 270 + if templ_7745c5c3_Err != nil { 271 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 132} 272 + } 273 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 274 + if templ_7745c5c3_Err != nil { 275 + return templ_7745c5c3_Err 276 + } 277 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</a>") 278 + if templ_7745c5c3_Err != nil { 279 + return templ_7745c5c3_Err 280 + } 281 + } 282 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div></details> ") 250 283 if templ_7745c5c3_Err != nil { 251 284 return templ_7745c5c3_Err 252 285 } 253 286 for _, file := range rcc.Commit.Files { 254 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5\"><span class=\"text-text/80\" title=\"") 287 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<div class=\"text-text mt-5\" id=\"") 255 288 if templ_7745c5c3_Err != nil { 256 289 return templ_7745c5c3_Err 257 290 } 258 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(file.Action)) 291 + var templ_7745c5c3_Var19 string 292 + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 293 + if templ_7745c5c3_Err != nil { 294 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 47} 295 + } 296 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 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=\"") 263 301 if templ_7745c5c3_Err != nil { 264 302 return templ_7745c5c3_Err 265 303 } 266 304 var templ_7745c5c3_Var20 string 267 - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0])) 305 + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action) 268 306 if templ_7745c5c3_Err != nil { 269 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 30, Col: 77} 307 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 50} 270 308 } 271 309 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) 272 310 if templ_7745c5c3_Err != nil { 273 311 return templ_7745c5c3_Err 274 312 } 275 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ") 313 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\">") 276 314 if templ_7745c5c3_Err != nil { 277 315 return templ_7745c5c3_Err 278 316 } 279 317 var templ_7745c5c3_Var21 string 280 - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 318 + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0])) 281 319 if templ_7745c5c3_Err != nil { 282 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 9} 320 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 77} 283 321 } 284 322 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) 285 323 if templ_7745c5c3_Err != nil { 286 324 return templ_7745c5c3_Err 287 325 } 288 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 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, " ") 289 340 if templ_7745c5c3_Err != nil { 290 341 return templ_7745c5c3_Err 291 342 } 292 343 if file.From.Path != "" { 293 - _, 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=\"") 294 345 if templ_7745c5c3_Err != nil { 295 346 return templ_7745c5c3_Err 296 347 } 297 - var templ_7745c5c3_Var22 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)) 298 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var22))) 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)) 299 354 if templ_7745c5c3_Err != nil { 300 355 return templ_7745c5c3_Err 301 356 } 302 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 357 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">") 303 358 if templ_7745c5c3_Err != nil { 304 359 return templ_7745c5c3_Err 305 360 } 306 - var templ_7745c5c3_Var23 string 307 - templ_7745c5c3_Var23, 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) 308 363 if templ_7745c5c3_Err != nil { 309 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 33, Col: 227} 364 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 227} 310 365 } 311 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) 366 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) 312 367 if templ_7745c5c3_Err != nil { 313 368 return templ_7745c5c3_Err 314 369 } 315 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 370 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a> ") 316 371 if templ_7745c5c3_Err != nil { 317 372 return templ_7745c5c3_Err 318 373 } 319 374 } 320 375 if file.From.Path != "" && file.To.Path != "" { 321 - var templ_7745c5c3_Var24 string 322 - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ") 376 + var templ_7745c5c3_Var25 string 377 + templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ") 323 378 if templ_7745c5c3_Err != nil { 324 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 36, Col: 13} 379 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 44, Col: 13} 325 380 } 326 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) 381 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) 382 + if templ_7745c5c3_Err != nil { 383 + return templ_7745c5c3_Err 384 + } 385 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ") 327 386 if templ_7745c5c3_Err != nil { 328 387 return templ_7745c5c3_Err 329 388 } 330 389 } 331 390 if file.To.Path != "" { 332 - _, 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=\"") 333 392 if templ_7745c5c3_Err != nil { 334 393 return templ_7745c5c3_Err 335 394 } 336 - var templ_7745c5c3_Var25 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)) 337 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var25))) 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)) 338 401 if templ_7745c5c3_Err != nil { 339 402 return templ_7745c5c3_Err 340 403 } 341 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 404 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\">") 342 405 if templ_7745c5c3_Err != nil { 343 406 return templ_7745c5c3_Err 344 407 } 345 - var templ_7745c5c3_Var26 string 346 - templ_7745c5c3_Var26, 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) 347 410 if templ_7745c5c3_Err != nil { 348 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 39, Col: 221} 411 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 221} 349 412 } 350 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) 413 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) 351 414 if templ_7745c5c3_Err != nil { 352 415 return templ_7745c5c3_Err 353 416 } 354 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 417 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</a>") 355 418 if templ_7745c5c3_Err != nil { 356 419 return templ_7745c5c3_Err 357 420 } 358 421 } 359 - _, 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\">") 360 423 if templ_7745c5c3_Err != nil { 361 424 return templ_7745c5c3_Err 362 425 } ··· 364 427 if templ_7745c5c3_Err != nil { 365 428 return templ_7745c5c3_Err 366 429 } 367 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 430 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div>") 368 431 if templ_7745c5c3_Err != nil { 369 432 return templ_7745c5c3_Err 370 433 } 371 434 } 372 - if !templ_7745c5c3_IsBuffer { 373 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 374 - } 375 - return templ_7745c5c3_Err 435 + return nil 376 436 }) 377 437 templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 378 438 if templ_7745c5c3_Err != nil { 379 439 return templ_7745c5c3_Err 380 440 } 381 - if !templ_7745c5c3_IsBuffer { 382 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 383 - } 384 - return templ_7745c5c3_Err 441 + return nil 385 442 }) 386 443 } 444 + 445 + var _ = templruntime.GeneratedTemplate
+48 -9
internal/html/repo_file.templ
··· 1 1 package html 2 2 3 + import "fmt" 4 + 3 5 type RepoFileContext struct { 4 - BaseContext 6 + BaseContext 5 7 RepoHeaderComponentContext 6 - Code string 7 - Path string 8 + RepoBreadcrumbComponentContext 9 + Code string 10 + Commit string 11 + Path string 12 + } 13 + 14 + func (rfc RepoFileContext) Permalink() string { 15 + return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path) 8 16 } 9 17 10 18 templ RepoFile(rfc RepoFileContext) { 11 19 @base(rfc.BaseContext) { 12 20 @repoHeaderComponent(rfc.RepoHeaderComponentContext) 13 21 <div class="mt-2 text-text"> 14 - <span>{ rfc.Path }{ " - " }</span> 22 + @repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext) 23 + { " - " } 15 24 <a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a> 16 - <div class="code">@templ.Raw(rfc.Code)</div> 25 + { " - " } 26 + <a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" id="permalink" data-permalink={ rfc.Permalink() } href={ rfc.Permalink() }>permalink</a> 27 + <div class="code relative"> 28 + @templ.Raw(rfc.Code) 29 + <button id="copy" class="absolute top-0 right-0 rounded bg-base hover:bg-surface0"></button> 30 + </div> 17 31 </div> 18 32 } 19 33 <script> 20 34 const lineRe = /#L(\d+)(?:-L(\d+))?/g 21 35 const $lineLines = document.querySelectorAll(".chroma .lntable .lnt"); 22 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; 23 43 let start = 0; 24 44 let end = 0; 25 45 ··· 28 48 start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0; 29 49 end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0; 30 50 } 31 - if (start != 0) { 51 + if (start !== 0) { 32 52 deactivateLines(); 33 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); 34 58 } 35 59 36 60 for (let line of $lineLines) { ··· 42 66 if (event.shiftKey) { 43 67 end = n; 44 68 anchor = `#L${start}-L${end}`; 69 + } else if (start === n) { 70 + start = 0; 71 + end = 0; 45 72 } else { 46 73 start = n; 47 74 end = 0; 48 75 anchor = `#L${start}`; 49 76 } 50 - history.pushState(null, null, anchor); 51 - 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); 52 80 }); 53 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 + }); 54 94 55 95 function activateLines(start, end) { 56 96 if (end < start) end = start; ··· 69 109 70 110 </script> 71 111 } 72 -
+73 -92
internal/html/repo_file_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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 - Code string 17 - Path string 16 + RepoBreadcrumbComponentContext 17 + Code string 18 + Commit string 19 + Path string 20 + } 21 + 22 + func (rfc RepoFileContext) Permalink() string { 23 + return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path) 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\"><span>") 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"mt-2 text-text\">") 64 + if templ_7745c5c3_Err != nil { 65 + return templ_7745c5c3_Err 66 + } 67 + templ_7745c5c3_Err = repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer) 44 68 if templ_7745c5c3_Err != nil { 45 69 return templ_7745c5c3_Err 46 70 } 47 71 var templ_7745c5c3_Var3 string 48 - templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(rfc.Path) 72 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 49 73 if templ_7745c5c3_Err != nil { 50 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 13, Col: 19} 74 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 23, Col: 10} 51 75 } 52 76 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 53 77 if templ_7745c5c3_Err != nil { 54 78 return templ_7745c5c3_Err 55 79 } 80 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">raw</a> ") 81 + if templ_7745c5c3_Err != nil { 82 + return templ_7745c5c3_Err 83 + } 56 84 var templ_7745c5c3_Var4 string 57 85 templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 58 86 if templ_7745c5c3_Err != nil { 59 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 13, Col: 28} 87 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 25, Col: 10} 60 88 } 61 89 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 62 90 if templ_7745c5c3_Err != nil { 63 91 return templ_7745c5c3_Err 64 92 } 65 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">") 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=\"") 66 94 if templ_7745c5c3_Err != nil { 67 95 return templ_7745c5c3_Err 68 96 } 69 - templ_7745c5c3_Var5 := `raw` 70 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5) 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)) 71 116 if templ_7745c5c3_Err != nil { 72 117 return templ_7745c5c3_Err 73 118 } 74 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a><div class=\"code\">") 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">permalink</a><div class=\"code relative\">") 75 120 if templ_7745c5c3_Err != nil { 76 121 return templ_7745c5c3_Err 77 122 } ··· 79 124 if templ_7745c5c3_Err != nil { 80 125 return templ_7745c5c3_Err 81 126 } 82 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>") 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>") 83 128 if templ_7745c5c3_Err != nil { 84 129 return templ_7745c5c3_Err 85 130 } 86 - if !templ_7745c5c3_IsBuffer { 87 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 88 - } 89 - return templ_7745c5c3_Err 131 + return nil 90 132 }) 91 133 templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 92 134 if templ_7745c5c3_Err != nil { 93 135 return templ_7745c5c3_Err 94 136 } 95 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>") 96 - if templ_7745c5c3_Err != nil { 97 - return templ_7745c5c3_Err 98 - } 99 - templ_7745c5c3_Var6 := ` 100 - const lineRe = /#L(\d+)(?:-L(\d+))?/g 101 - const $lineLines = document.querySelectorAll(".chroma .lntable .lnt"); 102 - const $codeLines = document.querySelectorAll(".chroma .lntable .line"); 103 - let start = 0; 104 - let end = 0; 105 - 106 - const results = [...location.hash.matchAll(lineRe)]; 107 - if (0 in results) { 108 - start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0; 109 - end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0; 110 - } 111 - if (start != 0) { 112 - deactivateLines(); 113 - activateLines(start, end); 114 - } 115 - 116 - for (let line of $lineLines) { 117 - line.addEventListener("click", (event) => { 118 - event.preventDefault(); 119 - deactivateLines(); 120 - const n = parseInt(line.id.substring(1)); 121 - let anchor = ""; 122 - if (event.shiftKey) { 123 - end = n; 124 - anchor = ` + "`" + `#L${start}-L${end}` + "`" + `; 125 - } else { 126 - start = n; 127 - end = 0; 128 - anchor = ` + "`" + `#L${start}` + "`" + `; 129 - } 130 - history.pushState(null, null, anchor); 131 - activateLines(start, end); 132 - }); 133 - } 134 - 135 - function activateLines(start, end) { 136 - if (end < start) end = start; 137 - for (let idx = start - 1; idx < end; idx++) { 138 - $codeLines[idx].classList.add("active"); 139 - } 140 - } 141 - 142 - function deactivateLines() { 143 - for (let code of $codeLines) { 144 - code.classList.remove("active"); 145 - } 146 - } 147 - 148 - 149 - 150 - ` 151 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) 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>") 152 138 if templ_7745c5c3_Err != nil { 153 139 return templ_7745c5c3_Err 154 140 } 155 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script>") 156 - if templ_7745c5c3_Err != nil { 157 - return templ_7745c5c3_Err 158 - } 159 - if !templ_7745c5c3_IsBuffer { 160 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 161 - } 162 - return templ_7745c5c3_Err 141 + return nil 163 142 }) 164 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 -
+71 -50
internal/html/repo_log_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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 } 64 80 var templ_7745c5c3_Var4 string 65 81 templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short()) 66 82 if templ_7745c5c3_Err != nil { 67 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 18, Col: 209} 83 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 19, Col: 209} 68 84 } 69 85 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 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 } 82 98 var templ_7745c5c3_Var5 string 83 99 templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Summary()) 84 100 if templ_7745c5c3_Err != nil { 85 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 22, Col: 58} 101 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 23, Col: 58} 86 102 } 87 103 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 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 } 95 111 var templ_7745c5c3_Var6 string 96 112 templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Details()) 97 113 if templ_7745c5c3_Err != nil { 98 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 23, Col: 59} 114 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 24, Col: 59} 99 115 } 100 116 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 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 } ··· 109 125 var templ_7745c5c3_Var7 string 110 126 templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message) 111 127 if templ_7745c5c3_Err != nil { 112 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 26, Col: 23} 128 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 27, Col: 23} 113 129 } 114 130 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 115 131 if templ_7745c5c3_Err != nil { 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 } 123 139 var templ_7745c5c3_Var8 string 124 140 templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Author) 125 141 if templ_7745c5c3_Err != nil { 126 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 31, Col: 25} 142 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 25} 127 143 } 128 144 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 129 145 if templ_7745c5c3_Err != nil { ··· 132 148 var templ_7745c5c3_Var9 string 133 149 templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 134 150 if templ_7745c5c3_Err != nil { 135 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 31, Col: 32} 151 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 32} 136 152 } 137 153 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 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 } 154 174 var templ_7745c5c3_Var11 string 155 175 templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", commit.Email)) 156 176 if templ_7745c5c3_Err != nil { 157 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 31, Col: 213} 177 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 213} 158 178 } 159 179 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 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 } 167 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(commit.When.Format("01/02/2006 03:04:05 PM"))) 187 + var templ_7745c5c3_Var12 string 188 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(commit.When.Format("01/02/2006 03:04:05 PM")) 189 + if templ_7745c5c3_Err != nil { 190 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 62} 191 + } 192 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 168 193 if templ_7745c5c3_Err != nil { 169 194 return templ_7745c5c3_Err 170 195 } 171 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 196 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 172 197 if templ_7745c5c3_Err != nil { 173 198 return templ_7745c5c3_Err 174 199 } 175 - var templ_7745c5c3_Var12 string 176 - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(commit.When)) 200 + var templ_7745c5c3_Var13 string 201 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(commit.When)) 177 202 if templ_7745c5c3_Err != nil { 178 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 93} 203 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 93} 179 204 } 180 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 205 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 181 206 if templ_7745c5c3_Err != nil { 182 207 return templ_7745c5c3_Err 183 208 } 184 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>") 209 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></div>") 185 210 if templ_7745c5c3_Err != nil { 186 211 return templ_7745c5c3_Err 187 212 } 188 213 } 189 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 214 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div>") 190 215 if templ_7745c5c3_Err != nil { 191 216 return templ_7745c5c3_Err 192 217 } 193 - if !templ_7745c5c3_IsBuffer { 194 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 195 - } 196 - return templ_7745c5c3_Err 218 + return nil 197 219 }) 198 220 templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 199 221 if templ_7745c5c3_Err != nil { 200 222 return templ_7745c5c3_Err 201 223 } 202 - if !templ_7745c5c3_IsBuffer { 203 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 204 - } 205 - return templ_7745c5c3_Err 224 + return nil 206 225 }) 207 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 -
+89 -128
internal/html/repo_refs_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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\">") 52 - if templ_7745c5c3_Err != nil { 53 - return templ_7745c5c3_Err 54 - } 55 - templ_7745c5c3_Var3 := `Branches` 56 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) 57 - if templ_7745c5c3_Err != nil { 58 - return templ_7745c5c3_Err 59 - } 60 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</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\">") 61 64 if templ_7745c5c3_Err != nil { 62 65 return templ_7745c5c3_Err 63 66 } 64 67 for _, branch := range rrc.Branches { 65 - _, 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\">") 66 69 if templ_7745c5c3_Err != nil { 67 70 return templ_7745c5c3_Err 68 71 } 69 - var templ_7745c5c3_Var4 string 70 - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(branch) 72 + var templ_7745c5c3_Var3 string 73 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(branch) 71 74 if templ_7745c5c3_Err != nil { 72 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 19, Col: 61} 75 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 20, Col: 61} 73 76 } 74 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 77 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 75 78 if templ_7745c5c3_Err != nil { 76 79 return templ_7745c5c3_Err 77 80 } 78 - _, 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=\"") 79 82 if templ_7745c5c3_Err != nil { 80 83 return templ_7745c5c3_Err 81 84 } 82 - var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)) 83 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5))) 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))) 84 87 if templ_7745c5c3_Err != nil { 85 - return templ_7745c5c3_Err 88 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 218} 86 89 } 87 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 90 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 88 91 if templ_7745c5c3_Err != nil { 89 92 return templ_7745c5c3_Err 90 93 } 91 - templ_7745c5c3_Var6 := `tree` 92 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) 93 - if templ_7745c5c3_Err != nil { 94 - return templ_7745c5c3_Err 95 - } 96 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 94 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">tree</a>") 97 95 if templ_7745c5c3_Err != nil { 98 96 return templ_7745c5c3_Err 99 97 } 100 - var templ_7745c5c3_Var7 string 101 - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 102 - if templ_7745c5c3_Err != nil { 103 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 20, Col: 234} 104 - } 105 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 98 + var templ_7745c5c3_Var5 string 99 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 106 100 if templ_7745c5c3_Err != nil { 107 - return templ_7745c5c3_Err 101 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 234} 108 102 } 109 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 103 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 110 104 if templ_7745c5c3_Err != nil { 111 105 return templ_7745c5c3_Err 112 106 } 113 - var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)) 114 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8))) 107 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 115 108 if templ_7745c5c3_Err != nil { 116 109 return templ_7745c5c3_Err 117 110 } 118 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 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))) 119 113 if templ_7745c5c3_Err != nil { 120 - return templ_7745c5c3_Err 114 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 409} 121 115 } 122 - templ_7745c5c3_Var9 := `log` 123 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9) 116 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 124 117 if templ_7745c5c3_Err != nil { 125 118 return templ_7745c5c3_Err 126 119 } 127 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>") 120 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\">log</a></div>") 128 121 if templ_7745c5c3_Err != nil { 129 122 return templ_7745c5c3_Err 130 123 } 131 124 } 132 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 125 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>") 133 126 if templ_7745c5c3_Err != nil { 134 127 return templ_7745c5c3_Err 135 128 } 136 129 } 137 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 130 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ") 138 131 if templ_7745c5c3_Err != nil { 139 132 return templ_7745c5c3_Err 140 133 } 141 134 if len(rrc.Tags) > 0 { 142 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-text text-lg mt-5\">") 143 - if templ_7745c5c3_Err != nil { 144 - return templ_7745c5c3_Err 145 - } 146 - templ_7745c5c3_Var10 := `Tags` 147 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10) 148 - if templ_7745c5c3_Err != nil { 149 - return templ_7745c5c3_Err 150 - } 151 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</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\">") 152 136 if templ_7745c5c3_Err != nil { 153 137 return templ_7745c5c3_Err 154 138 } 155 139 for _, tag := range rrc.Tags { 156 - _, 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\">") 157 141 if templ_7745c5c3_Err != nil { 158 142 return templ_7745c5c3_Err 159 143 } 160 - var templ_7745c5c3_Var11 string 161 - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Name) 144 + var templ_7745c5c3_Var7 string 145 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Name) 162 146 if templ_7745c5c3_Err != nil { 163 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 28, Col: 49} 147 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 29, Col: 49} 164 148 } 165 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 149 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 166 150 if templ_7745c5c3_Err != nil { 167 151 return templ_7745c5c3_Err 168 152 } 169 - _, 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=\"") 170 154 if templ_7745c5c3_Err != nil { 171 155 return templ_7745c5c3_Err 172 156 } 173 - var templ_7745c5c3_Var12 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)) 174 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var12))) 175 - if templ_7745c5c3_Err != nil { 176 - return templ_7745c5c3_Err 177 - } 178 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 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))) 179 159 if templ_7745c5c3_Err != nil { 180 - return templ_7745c5c3_Err 160 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 206} 181 161 } 182 - templ_7745c5c3_Var13 := `tree` 183 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13) 162 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 184 163 if templ_7745c5c3_Err != nil { 185 164 return templ_7745c5c3_Err 186 165 } 187 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 166 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">tree</a>") 188 167 if templ_7745c5c3_Err != nil { 189 168 return templ_7745c5c3_Err 190 169 } 191 - var templ_7745c5c3_Var14 string 192 - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 170 + var templ_7745c5c3_Var9 string 171 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 193 172 if templ_7745c5c3_Err != nil { 194 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 29, Col: 222} 173 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 222} 195 174 } 196 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 175 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 197 176 if templ_7745c5c3_Err != nil { 198 177 return templ_7745c5c3_Err 199 178 } 200 - _, 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=\"") 201 180 if templ_7745c5c3_Err != nil { 202 181 return templ_7745c5c3_Err 203 182 } 204 - var templ_7745c5c3_Var15 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)) 205 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var15))) 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))) 206 185 if templ_7745c5c3_Err != nil { 207 - return templ_7745c5c3_Err 208 - } 209 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 210 - if templ_7745c5c3_Err != nil { 211 - return templ_7745c5c3_Err 186 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 399} 212 187 } 213 - templ_7745c5c3_Var16 := `log` 214 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) 188 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 215 189 if templ_7745c5c3_Err != nil { 216 190 return templ_7745c5c3_Err 217 191 } 218 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>") 192 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">log</a></div>") 219 193 if templ_7745c5c3_Err != nil { 220 194 return templ_7745c5c3_Err 221 195 } 222 196 if tag.Signature != "" { 223 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">") 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>") 224 198 if templ_7745c5c3_Err != nil { 225 199 return templ_7745c5c3_Err 226 200 } 227 - templ_7745c5c3_Var17 := `Signature` 228 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17) 201 + var templ_7745c5c3_Var11 string 202 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Signature) 229 203 if templ_7745c5c3_Err != nil { 230 - return templ_7745c5c3_Err 204 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 32, Col: 121} 231 205 } 232 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary><code>") 206 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 233 207 if templ_7745c5c3_Err != nil { 234 208 return templ_7745c5c3_Err 235 209 } 236 - var templ_7745c5c3_Var18 string 237 - templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Signature) 238 - if templ_7745c5c3_Err != nil { 239 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 31, Col: 121} 240 - } 241 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 242 - if templ_7745c5c3_Err != nil { 243 - return templ_7745c5c3_Err 244 - } 245 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></details>") 210 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</code></details>") 246 211 if templ_7745c5c3_Err != nil { 247 212 return templ_7745c5c3_Err 248 213 } 249 214 } 250 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 215 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ") 251 216 if templ_7745c5c3_Err != nil { 252 217 return templ_7745c5c3_Err 253 218 } 254 219 if tag.Annotation != "" { 255 - _, 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\">") 256 221 if templ_7745c5c3_Err != nil { 257 222 return templ_7745c5c3_Err 258 223 } 259 - var templ_7745c5c3_Var19 string 260 - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Annotation) 224 + var templ_7745c5c3_Var12 string 225 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Annotation) 261 226 if templ_7745c5c3_Err != nil { 262 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 34, Col: 51} 227 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 35, Col: 51} 263 228 } 264 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 229 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 265 230 if templ_7745c5c3_Err != nil { 266 231 return templ_7745c5c3_Err 267 232 } 268 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 233 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>") 269 234 if templ_7745c5c3_Err != nil { 270 235 return templ_7745c5c3_Err 271 236 } 272 237 } 273 238 } 274 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 239 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>") 275 240 if templ_7745c5c3_Err != nil { 276 241 return templ_7745c5c3_Err 277 242 } 278 243 } 279 - if !templ_7745c5c3_IsBuffer { 280 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 281 - } 282 - return templ_7745c5c3_Err 244 + return nil 283 245 }) 284 246 templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 285 247 if templ_7745c5c3_Err != nil { 286 248 return templ_7745c5c3_Err 287 249 } 288 - if !templ_7745c5c3_IsBuffer { 289 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 290 - } 291 - return templ_7745c5c3_Err 250 + return nil 292 251 }) 293 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
+88 -99
internal/html/repo_search_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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 65 75 } 66 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 67 - if templ_7745c5c3_Err != nil { 68 - return templ_7745c5c3_Err 69 - } 70 76 for _, results := range sc.DedupeResults() { 71 77 templ_7745c5c3_Err = repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results).Render(ctx, templ_7745c5c3_Buffer) 72 78 if templ_7745c5c3_Err != nil { 73 79 return templ_7745c5c3_Err 74 80 } 75 81 } 76 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 82 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 77 83 if templ_7745c5c3_Err != nil { 78 84 return templ_7745c5c3_Err 79 85 } 80 86 if len(sc.DedupeResults()) == 0 { 81 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-text mt-5 text-lg\">") 82 - if templ_7745c5c3_Err != nil { 83 - return templ_7745c5c3_Err 84 - } 85 - templ_7745c5c3_Var3 := `No results` 86 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) 87 - if templ_7745c5c3_Err != nil { 88 - return templ_7745c5c3_Err 89 - } 90 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p>") 87 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"text-text mt-5 text-lg\">No results</p>") 91 88 if templ_7745c5c3_Err != nil { 92 89 return templ_7745c5c3_Err 93 90 } 94 91 } 95 - if !templ_7745c5c3_IsBuffer { 96 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 97 - } 98 - return templ_7745c5c3_Err 92 + return nil 99 93 }) 100 94 templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 101 95 if templ_7745c5c3_Err != nil { 102 96 return templ_7745c5c3_Err 103 97 } 104 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>") 105 - if templ_7745c5c3_Err != nil { 106 - return templ_7745c5c3_Err 107 - } 108 - templ_7745c5c3_Var4 := ` 109 - const search = new URLSearchParams(window.location.search).get("q"); 110 - if (search !== "") document.querySelector("#search").value = search; 111 - ` 112 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4) 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>") 113 99 if templ_7745c5c3_Err != nil { 114 100 return templ_7745c5c3_Err 115 101 } 116 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</script>") 117 - if templ_7745c5c3_Err != nil { 118 - return templ_7745c5c3_Err 119 - } 120 - if !templ_7745c5c3_IsBuffer { 121 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 122 - } 123 - return templ_7745c5c3_Err 102 + return nil 124 103 }) 125 104 } 126 105 127 106 func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Component { 128 - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 129 - 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) 130 113 if !templ_7745c5c3_IsBuffer { 131 - templ_7745c5c3_Buffer = templ.GetBuffer() 132 - 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 + }() 133 120 } 134 121 ctx = templ.InitializeContext(ctx) 135 - templ_7745c5c3_Var5 := templ.GetChildren(ctx) 136 - if templ_7745c5c3_Var5 == nil { 137 - templ_7745c5c3_Var5 = templ.NopComponent 122 + templ_7745c5c3_Var3 := templ.GetChildren(ctx) 123 + if templ_7745c5c3_Var3 == nil { 124 + templ_7745c5c3_Var3 = templ.NopComponent 138 125 } 139 126 ctx = templ.ClearChildren(ctx) 140 - _, 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=\"") 141 128 if templ_7745c5c3_Err != nil { 142 129 return templ_7745c5c3_Err 143 130 } 144 - var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)) 145 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6))) 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)) 146 137 if templ_7745c5c3_Err != nil { 147 138 return templ_7745c5c3_Err 148 139 } 149 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 140 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 150 141 if templ_7745c5c3_Err != nil { 151 142 return templ_7745c5c3_Err 152 143 } 153 - var templ_7745c5c3_Var7 string 154 - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 144 + var templ_7745c5c3_Var5 string 145 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 155 146 if templ_7745c5c3_Err != nil { 156 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 49, Col: 230} 147 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 230} 157 148 } 158 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 149 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 159 150 if templ_7745c5c3_Err != nil { 160 151 return templ_7745c5c3_Err 161 152 } 162 - _, 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\">") 163 154 if templ_7745c5c3_Err != nil { 164 155 return templ_7745c5c3_Err 165 156 } ··· 167 158 if templ_7745c5c3_Err != nil { 168 159 return templ_7745c5c3_Err 169 160 } 170 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 171 162 if templ_7745c5c3_Err != nil { 172 163 return templ_7745c5c3_Err 173 164 } 174 165 if len(results) > 1 { 175 - _, 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>") 176 167 if templ_7745c5c3_Err != nil { 177 168 return templ_7745c5c3_Err 178 169 } 179 - var templ_7745c5c3_Var8 string 180 - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:]))) 170 + var templ_7745c5c3_Var6 string 171 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:]))) 181 172 if templ_7745c5c3_Err != nil { 182 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 55, Col: 50} 173 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 54, Col: 50} 183 174 } 184 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 175 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 185 176 if templ_7745c5c3_Err != nil { 186 177 return templ_7745c5c3_Err 187 178 } 188 - templ_7745c5c3_Var9 := `more` 189 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9) 190 - if templ_7745c5c3_Err != nil { 191 - return templ_7745c5c3_Err 192 - } 193 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary> ") 179 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "more</summary> ") 194 180 if templ_7745c5c3_Err != nil { 195 181 return templ_7745c5c3_Err 196 182 } 197 183 for _, result := range results[1:] { 198 - _, 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=\"") 199 185 if templ_7745c5c3_Err != nil { 200 186 return templ_7745c5c3_Err 201 187 } 202 - var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)) 203 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10))) 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)) 204 194 if templ_7745c5c3_Err != nil { 205 195 return templ_7745c5c3_Err 206 196 } 207 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">") 208 198 if templ_7745c5c3_Err != nil { 209 199 return templ_7745c5c3_Err 210 200 } 211 - var templ_7745c5c3_Var11 string 212 - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 201 + var templ_7745c5c3_Var8 string 202 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 213 203 if templ_7745c5c3_Err != nil { 214 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 57, Col: 230} 204 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 230} 215 205 } 216 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 206 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 217 207 if templ_7745c5c3_Err != nil { 218 208 return templ_7745c5c3_Err 219 209 } 220 - _, 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\">") 221 211 if templ_7745c5c3_Err != nil { 222 212 return templ_7745c5c3_Err 223 213 } ··· 225 215 if templ_7745c5c3_Err != nil { 226 216 return templ_7745c5c3_Err 227 217 } 228 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 218 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>") 229 219 if templ_7745c5c3_Err != nil { 230 220 return templ_7745c5c3_Err 231 221 } 232 222 } 233 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</details>") 223 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</details>") 234 224 if templ_7745c5c3_Err != nil { 235 225 return templ_7745c5c3_Err 236 226 } 237 227 } 238 - if !templ_7745c5c3_IsBuffer { 239 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 240 - } 241 - return templ_7745c5c3_Err 228 + return nil 242 229 }) 243 230 } 231 + 232 + var _ = templruntime.GeneratedTemplate
+103 -72
internal/html/repo_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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 ··· 17 15 Ref string 18 16 Description string 19 17 CloneURL string 18 + Tags []string 20 19 } 21 20 22 21 func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component { 23 - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 24 - 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) 25 28 if !templ_7745c5c3_IsBuffer { 26 - templ_7745c5c3_Buffer = templ.GetBuffer() 27 - 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 + }() 28 35 } 29 36 ctx = templ.InitializeContext(ctx) 30 37 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 32 39 templ_7745c5c3_Var1 = templ.NopComponent 33 40 } 34 41 ctx = templ.ClearChildren(ctx) 35 - _, 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=\"") 36 43 if templ_7745c5c3_Err != nil { 37 44 return templ_7745c5c3_Err 38 45 } 39 - var templ_7745c5c3_Var2 templ.SafeURL = templ.SafeURL("/" + rhcc.Name) 40 - _, 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)) 41 52 if templ_7745c5c3_Err != nil { 42 53 return templ_7745c5c3_Err 43 54 } 44 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 55 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">") 45 56 if templ_7745c5c3_Err != nil { 46 57 return templ_7745c5c3_Err 47 58 } 48 59 var templ_7745c5c3_Var3 string 49 60 templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Name) 50 61 if templ_7745c5c3_Err != nil { 51 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 13, Col: 142} 62 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 142} 52 63 } 53 64 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 54 65 if templ_7745c5c3_Err != nil { 55 66 return templ_7745c5c3_Err 56 67 } 57 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 68 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</a> ") 58 69 if templ_7745c5c3_Err != nil { 59 70 return templ_7745c5c3_Err 60 71 } ··· 62 73 var templ_7745c5c3_Var4 string 63 74 templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 64 75 if templ_7745c5c3_Err != nil { 65 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 8} 76 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 17, Col: 8} 66 77 } 67 78 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 68 79 if templ_7745c5c3_Err != nil { 69 80 return templ_7745c5c3_Err 70 81 } 71 - _, 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=\"") 72 83 if templ_7745c5c3_Err != nil { 73 84 return templ_7745c5c3_Err 74 85 } 75 - var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)) 76 - _, 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)) 77 92 if templ_7745c5c3_Err != nil { 78 93 return templ_7745c5c3_Err 79 94 } 80 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 95 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 81 96 if templ_7745c5c3_Err != nil { 82 97 return templ_7745c5c3_Err 83 98 } 84 99 var templ_7745c5c3_Var6 string 85 100 templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("@" + rhcc.Ref) 86 101 if templ_7745c5c3_Err != nil { 87 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 16, Col: 194} 102 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 194} 88 103 } 89 104 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 90 105 if templ_7745c5c3_Err != nil { 91 106 return templ_7745c5c3_Err 92 107 } 93 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>") 108 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 94 109 if templ_7745c5c3_Err != nil { 95 110 return templ_7745c5c3_Err 96 111 } ··· 98 113 var templ_7745c5c3_Var7 string 99 114 templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 100 115 if templ_7745c5c3_Err != nil { 101 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 9} 116 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 20, Col: 9} 102 117 } 103 118 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 104 119 if templ_7745c5c3_Err != nil { 105 120 return templ_7745c5c3_Err 106 121 } 107 - _, 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=\"") 108 123 if templ_7745c5c3_Err != nil { 109 124 return templ_7745c5c3_Err 110 125 } 111 - var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name)) 112 - _, 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)) 113 132 if templ_7745c5c3_Err != nil { 114 133 return templ_7745c5c3_Err 115 134 } 116 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">refs</a> ") 117 136 if templ_7745c5c3_Err != nil { 118 137 return templ_7745c5c3_Err 119 138 } 120 - templ_7745c5c3_Var9 := `refs` 121 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9) 139 + var templ_7745c5c3_Var9 string 140 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 141 + if templ_7745c5c3_Err != nil { 142 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 22, Col: 9} 143 + } 144 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 122 145 if templ_7745c5c3_Err != nil { 123 146 return templ_7745c5c3_Err 124 147 } 125 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 148 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 126 149 if templ_7745c5c3_Err != nil { 127 150 return templ_7745c5c3_Err 128 151 } 129 - var templ_7745c5c3_Var10 string 130 - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 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))) 131 154 if templ_7745c5c3_Err != nil { 132 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 20, Col: 9} 155 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 23, Col: 151} 133 156 } 134 157 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 135 158 if templ_7745c5c3_Err != nil { 136 159 return templ_7745c5c3_Err 137 160 } 138 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">log</a> ") 139 162 if templ_7745c5c3_Err != nil { 140 163 return templ_7745c5c3_Err 141 164 } 142 - var templ_7745c5c3_Var11 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)) 143 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var11))) 165 + var templ_7745c5c3_Var11 string 166 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 167 + if templ_7745c5c3_Err != nil { 168 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9} 169 + } 170 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 144 171 if templ_7745c5c3_Err != nil { 145 172 return templ_7745c5c3_Err 146 173 } 147 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 174 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<form class=\"inline-block\" action=\"") 148 175 if templ_7745c5c3_Err != nil { 149 176 return templ_7745c5c3_Err 150 177 } 151 - templ_7745c5c3_Var12 := `log` 152 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(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)) 153 184 if templ_7745c5c3_Err != nil { 154 185 return templ_7745c5c3_Err 155 186 } 156 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ") 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>") 157 188 if templ_7745c5c3_Err != nil { 158 189 return templ_7745c5c3_Err 159 190 } 160 191 var templ_7745c5c3_Var13 string 161 192 templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 162 193 if templ_7745c5c3_Err != nil { 163 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 22, Col: 9} 194 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 26, Col: 9} 164 195 } 165 196 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 166 197 if templ_7745c5c3_Err != nil { 167 198 return templ_7745c5c3_Err 168 199 } 169 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form class=\"inline-block\" action=\"") 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\">") 170 201 if templ_7745c5c3_Err != nil { 171 202 return templ_7745c5c3_Err 172 203 } 173 - var templ_7745c5c3_Var14 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)) 174 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var14))) 204 + var templ_7745c5c3_Var14 string 205 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name)) 175 206 if templ_7745c5c3_Err != nil { 176 - return templ_7745c5c3_Err 207 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 131} 177 208 } 178 - _, 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>") 209 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 179 210 if templ_7745c5c3_Err != nil { 180 211 return templ_7745c5c3_Err 181 212 } 182 - var templ_7745c5c3_Var15 string 183 - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 213 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</pre></div><div class=\"text-subtext0 mb-1\">") 184 214 if templ_7745c5c3_Err != nil { 185 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9} 215 + return templ_7745c5c3_Err 186 216 } 187 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 188 - if templ_7745c5c3_Err != nil { 189 - return templ_7745c5c3_Err 217 + for _, tag := range rhcc.Tags { 218 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<span class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">") 219 + if templ_7745c5c3_Err != nil { 220 + return templ_7745c5c3_Err 221 + } 222 + var templ_7745c5c3_Var15 string 223 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(tag) 224 + if templ_7745c5c3_Err != nil { 225 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 31, Col: 102} 226 + } 227 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 228 + if templ_7745c5c3_Err != nil { 229 + return templ_7745c5c3_Err 230 + } 231 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</span>") 232 + if templ_7745c5c3_Err != nil { 233 + return templ_7745c5c3_Err 234 + } 190 235 } 191 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">") 236 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"text-text/80 mb-1\">") 192 237 if templ_7745c5c3_Err != nil { 193 238 return templ_7745c5c3_Err 194 239 } 195 240 var templ_7745c5c3_Var16 string 196 - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name)) 241 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description) 197 242 if templ_7745c5c3_Err != nil { 198 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 25, Col: 131} 243 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 34, Col: 50} 199 244 } 200 245 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 201 246 if templ_7745c5c3_Err != nil { 202 247 return templ_7745c5c3_Err 203 248 } 204 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</pre></div><div class=\"text-text/80 mb-1\">") 249 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>") 205 250 if templ_7745c5c3_Err != nil { 206 251 return templ_7745c5c3_Err 207 252 } 208 - var templ_7745c5c3_Var17 string 209 - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description) 210 - if templ_7745c5c3_Err != nil { 211 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 50} 212 - } 213 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 214 - if templ_7745c5c3_Err != nil { 215 - return templ_7745c5c3_Err 216 - } 217 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") 218 - if templ_7745c5c3_Err != nil { 219 - return templ_7745c5c3_Err 220 - } 221 - if !templ_7745c5c3_IsBuffer { 222 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 223 - } 224 - return templ_7745c5c3_Err 253 + return nil 225 254 }) 226 255 } 256 + 257 + var _ = templruntime.GeneratedTemplate
+16 -15
internal/html/repo_tree.templ
··· 1 1 package html 2 2 3 3 import ( 4 - "fmt" 5 - "go.jolheiser.com/ugit/internal/git" 4 + "fmt" 5 + "go.jolheiser.com/ugit/internal/git" 6 6 ) 7 7 8 8 type RepoTreeContext struct { 9 - BaseContext 9 + BaseContext 10 10 RepoHeaderComponentContext 11 - RepoTreeComponentContext 12 - ReadmeComponentContext 13 - Description string 11 + RepoBreadcrumbComponentContext 12 + RepoTreeComponentContext 13 + ReadmeComponentContext 14 + Description string 14 15 } 15 16 16 17 templ RepoTree(rtc RepoTreeContext) { 17 18 @base(rtc.BaseContext) { 18 19 @repoHeaderComponent(rtc.RepoHeaderComponentContext) 20 + @repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext) 19 21 @repoTreeComponent(rtc.RepoTreeComponentContext) 20 22 @readmeComponent(rtc.ReadmeComponentContext) 21 23 } 22 24 } 23 25 24 26 type RepoTreeComponentContext struct { 25 - Repo string 26 - Ref string 27 - Tree []git.FileInfo 28 - Back string 27 + Repo string 28 + Ref string 29 + Tree []git.FileInfo 30 + Back string 29 31 } 30 32 31 33 func slashDir(name string, isDir bool) string { 32 - if isDir { 33 - return name + "/" 34 - } 35 - return name 34 + if isDir { 35 + return name + "/" 36 + } 37 + return name 36 38 } 37 39 38 40 templ repoTreeComponent(rtcc RepoTreeComponentContext) { ··· 48 50 } 49 51 </div> 50 52 } 51 -
+83 -62
internal/html/repo_tree_templ.go
··· 1 1 // Code generated by templ - DO NOT EDIT. 2 2 3 - // templ: version: v0.2.501 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" ··· 18 16 type RepoTreeContext struct { 19 17 BaseContext 20 18 RepoHeaderComponentContext 19 + RepoBreadcrumbComponentContext 21 20 RepoTreeComponentContext 22 21 ReadmeComponentContext 23 22 Description string 24 23 } 25 24 26 25 func RepoTree(rtc RepoTreeContext) templ.Component { 27 - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 28 - 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) 29 32 if !templ_7745c5c3_IsBuffer { 30 - templ_7745c5c3_Buffer = templ.GetBuffer() 31 - 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 + }() 32 39 } 33 40 ctx = templ.InitializeContext(ctx) 34 41 templ_7745c5c3_Var1 := templ.GetChildren(ctx) ··· 36 43 templ_7745c5c3_Var1 = templ.NopComponent 37 44 } 38 45 ctx = templ.ClearChildren(ctx) 39 - templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 40 - 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) 41 49 if !templ_7745c5c3_IsBuffer { 42 - templ_7745c5c3_Buffer = templ.GetBuffer() 43 - 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 + }() 44 56 } 57 + ctx = templ.InitializeContext(ctx) 45 58 templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 46 59 if templ_7745c5c3_Err != nil { 47 60 return templ_7745c5c3_Err 48 61 } 49 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 62 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 63 + if templ_7745c5c3_Err != nil { 64 + return templ_7745c5c3_Err 65 + } 66 + templ_7745c5c3_Err = repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer) 67 + if templ_7745c5c3_Err != nil { 68 + return templ_7745c5c3_Err 69 + } 70 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") 50 71 if templ_7745c5c3_Err != nil { 51 72 return templ_7745c5c3_Err 52 73 } ··· 54 75 if templ_7745c5c3_Err != nil { 55 76 return templ_7745c5c3_Err 56 77 } 57 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") 78 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") 58 79 if templ_7745c5c3_Err != nil { 59 80 return templ_7745c5c3_Err 60 81 } ··· 62 83 if templ_7745c5c3_Err != nil { 63 84 return templ_7745c5c3_Err 64 85 } 65 - if !templ_7745c5c3_IsBuffer { 66 - _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) 67 - } 68 - return templ_7745c5c3_Err 86 + return nil 69 87 }) 70 88 templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 71 89 if templ_7745c5c3_Err != nil { 72 90 return templ_7745c5c3_Err 73 91 } 74 - if !templ_7745c5c3_IsBuffer { 75 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) 76 - } 77 - return templ_7745c5c3_Err 92 + return nil 78 93 }) 79 94 } 80 95 ··· 93 108 } 94 109 95 110 func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component { 96 - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { 97 - 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) 98 117 if !templ_7745c5c3_IsBuffer { 99 - templ_7745c5c3_Buffer = templ.GetBuffer() 100 - 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 + }() 101 124 } 102 125 ctx = templ.InitializeContext(ctx) 103 126 templ_7745c5c3_Var3 := templ.GetChildren(ctx) ··· 105 128 templ_7745c5c3_Var3 = templ.NopComponent 106 129 } 107 130 ctx = templ.ClearChildren(ctx) 108 - _, 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\">") 109 132 if templ_7745c5c3_Err != nil { 110 133 return templ_7745c5c3_Err 111 134 } 112 135 if rtcc.Back != "" { 113 - _, 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=\"") 114 - if templ_7745c5c3_Err != nil { 115 - return templ_7745c5c3_Err 116 - } 117 - var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)) 118 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4))) 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=\"") 119 137 if templ_7745c5c3_Err != nil { 120 138 return templ_7745c5c3_Err 121 139 } 122 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") 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))) 123 142 if templ_7745c5c3_Err != nil { 124 - return templ_7745c5c3_Err 143 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 44, Col: 194} 125 144 } 126 - templ_7745c5c3_Var5 := `..` 127 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5) 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 } 141 - var templ_7745c5c3_Var6 string 142 - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode) 159 + var templ_7745c5c3_Var5 string 160 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode) 143 161 if templ_7745c5c3_Err != nil { 144 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 44, Col: 50} 162 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50} 145 163 } 146 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 164 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 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 } 154 - var templ_7745c5c3_Var7 string 155 - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size) 172 + var templ_7745c5c3_Var6 string 173 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size) 156 174 if templ_7745c5c3_Err != nil { 157 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 45, Col: 50} 175 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 50} 158 176 } 159 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 177 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 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_Var8 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_Var8))) 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 } 176 - var templ_7745c5c3_Var9 string 177 - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir)) 198 + var templ_7745c5c3_Var8 string 199 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir)) 178 200 if templ_7745c5c3_Err != nil { 179 - return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 46, Col: 256} 201 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 256} 180 202 } 181 - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 203 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 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-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}.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-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.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-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 }
+17 -3
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, 129 + Tags: repo.Meta.Tags.Slice(), 130 + } 131 + } 132 + 133 + func (rh repoHandler) repoBreadcrumbContext(repo *git.Repo, r *http.Request, path string) html.RepoBreadcrumbComponentContext { 134 + ref := chi.URLParam(r, "ref") 135 + if ref == "" { 136 + ref, _ = repo.DefaultBranch() 137 + } 138 + return html.RepoBreadcrumbComponentContext{ 139 + Repo: chi.URLParam(r, "repo"), 140 + Ref: ref, 141 + Path: path, 128 142 } 129 143 } 130 144
+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 + }
+12 -2
internal/http/index.go
··· 18 18 return httperr.Error(err) 19 19 } 20 20 21 + tagFilter := r.URL.Query().Get("tag") 22 + 21 23 repos := make([]*git.Repo, 0, len(repoPaths)) 22 24 for _, repoName := range repoPaths { 23 25 if !strings.HasSuffix(repoName.Name(), ".git") { ··· 27 29 if err != nil { 28 30 return httperr.Error(err) 29 31 } 30 - if !repo.Meta.Private { 31 - repos = append(repos, repo) 32 + if repo.Meta.Private { 33 + if !rh.s.ShowPrivate { 34 + continue 35 + } 36 + repo.Meta.Tags.Add("private") 32 37 } 38 + 39 + if tagFilter != "" && !repo.Meta.Tags.Contains(strings.ToLower(tagFilter)) { 40 + continue 41 + } 42 + repos = append(repos, repo) 33 43 } 34 44 sort.Slice(repos, func(i, j int) bool { 35 45 var when1, when2 time.Time
+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)
+20 -10
internal/http/repo.go
··· 48 48 back = filepath.Dir(path) 49 49 } 50 50 if err := html.RepoTree(html.RepoTreeContext{ 51 - Description: repo.Meta.Description, 52 - BaseContext: rh.baseContext(), 53 - RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 51 + Description: repo.Meta.Description, 52 + BaseContext: rh.baseContext(), 53 + RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 54 + RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 54 55 RepoTreeComponentContext: html.RepoTreeComponentContext{ 55 56 Repo: repo.Name(), 56 57 Ref: ref, ··· 87 88 } 88 89 89 90 var buf bytes.Buffer 90 - 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 { 91 92 return httperr.Error(err) 92 93 } 93 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 + 94 103 if err := html.RepoFile(html.RepoFileContext{ 95 - BaseContext: rh.baseContext(), 96 - RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 97 - Code: buf.String(), 98 - Path: path, 104 + BaseContext: rh.baseContext(), 105 + RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 106 + RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 107 + Code: buf.String(), 108 + Commit: commit, 109 + Path: path, 99 110 }).Render(r.Context(), w); err != nil { 100 111 return httperr.Error(err) 101 112 } ··· 157 168 158 169 for idx, p := range commit.Files { 159 170 var patch bytes.Buffer 160 - 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 { 161 172 return httperr.Error(err) 162 173 } 163 174 commit.Files[idx].Patch = patch.String() ··· 205 216 } 206 217 results[idx].Content = buf.String() 207 218 } 208 - 209 219 } 210 220 211 221 if err := html.RepoSearch(html.SearchContext{
+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
+18 -5
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 + "text/tabwriter" 11 13 12 14 "go.jolheiser.com/ugit/internal/git" 13 15 14 - "github.com/charmbracelet/log" 15 16 "github.com/charmbracelet/ssh" 16 17 "github.com/charmbracelet/wish" 17 18 ) ··· 90 91 if errors.Is(err, ErrInvalidRepo) { 91 92 Fatal(s, ErrInvalidRepo) 92 93 } 93 - log.Error("unknown git error", "error", err) 94 + slog.Error("unknown git error", "error", err) 94 95 Fatal(s, ErrSystemMalfunction) 95 96 } 96 97 gh.Fetch(repo, pk) ··· 102 103 if len(cmd) == 0 { 103 104 des, err := os.ReadDir(repoDir) 104 105 if err != nil && err != fs.ErrNotExist { 105 - log.Error("invalid repository", "error", err) 106 + slog.Error("invalid repository", "error", err) 106 107 } 108 + tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 107 109 for _, de := range des { 108 - fmt.Fprintln(s, de.Name()) 109 - fmt.Fprintf(s, "\tgit clone %s/%s\n", cloneURL, de.Name()) 110 + if filepath.Ext(de.Name()) != ".git" { 111 + continue 112 + } 113 + repo, err := git.NewRepo(repoDir, de.Name()) 114 + visibility := "โ“" 115 + if err == nil { 116 + visibility = "๐Ÿ”“" 117 + if repo.Meta.Private { 118 + visibility = "๐Ÿ”’" 119 + } 120 + } 121 + fmt.Fprintf(tw, "%[1]s\t%[3]s\t%[2]s/%[1]s.git\n", strings.TrimSuffix(de.Name(), ".git"), cloneURL, visibility) 110 122 } 123 + tw.Flush() 111 124 } 112 125 sh(s) 113 126 }
+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 + }