From d08b6dc2224f4a3b57e29c833db0642c55a40f98 Mon Sep 17 00:00:00 2001 From: Aykhan Shahsuvarov Date: Mon, 17 Aug 2026 17:21:13 +0400 Subject: [PATCH] refactor: migrate Charm libraries to v2 Import paths moved to charm.land/*/v2 and the v1 paths no longer resolve. Ports View() -> tea.View, AltScreen/MouseMode to View fields, KeyPressMsg, and the new progress/viewport constructors. Styled output outside Bubble Tea switched to lipgloss.Print* because v2 downsamples colour at the output layer. vendorHash refreshed. --- .golangci.yaml | 18 ++++++++++++ cmd/cli/main.go | 11 +++---- go.mod | 21 ++++++-------- go.sum | 54 +++++++++++++--------------------- internal/config/config.go | 59 +++++++++++++++++++++----------------- internal/sarin/response.go | 7 ++--- internal/sarin/stop.go | 2 +- internal/sarin/tui.go | 30 +++++++++---------- nix/package.nix | 2 +- 9 files changed, 105 insertions(+), 99 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index ffafa1d..261e3f9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -55,6 +55,17 @@ linters: - wastedassign settings: + errcheck: + # Lip Gloss print helpers wrap fmt.Fprint* and fail only on unactionable + # write errors (broken pipe, full disk). errcheck excludes the fmt + # equivalents by default; these are excluded for the same reason. + exclude-functions: + - charm.land/lipgloss/v2.Print + - charm.land/lipgloss/v2.Printf + - charm.land/lipgloss/v2.Println + - charm.land/lipgloss/v2.Fprint + - charm.land/lipgloss/v2.Fprintf + - charm.land/lipgloss/v2.Fprintln staticcheck: checks: - "all" @@ -81,6 +92,13 @@ linters: - staticcheck text: "SA5011" + # Counterpart to the errcheck exclusions above: gosec's G104 keeps its + # own allowlist, which covers fmt but not the Lip Gloss print helpers. + - linters: + - gosec + text: "G104" + source: "lipgloss\\.(Print|Printf|Println|Fprint|Fprintf|Fprintln)\\(" + formatters: enable: - gofmt diff --git a/cmd/cli/main.go b/cmd/cli/main.go index ab12589..3d1f4f5 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -7,6 +7,7 @@ import ( "os/signal" "syscall" + "charm.land/lipgloss/v2" "go.aykhans.me/sarin/internal/config" "go.aykhans.me/sarin/internal/sarin" "go.aykhans.me/sarin/internal/types" @@ -32,11 +33,11 @@ func main() { utilsErr.OnType(func(err types.FieldValidationErrors) error { for _, fieldErr := range err.Errors { if fieldErr.Value == "" { - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, config.StyleYellow.Render(fmt.Sprintf("[VALIDATION] Field '%s': ", fieldErr.Field))+fieldErr.Err.Error(), ) } else { - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, config.StyleYellow.Render(fmt.Sprintf("[VALIDATION] Field '%s' (%s): ", fieldErr.Field, fieldErr.Value))+fieldErr.Err.Error(), ) } @@ -58,17 +59,17 @@ func main() { ) _ = utilsErr.MustHandle(err, utilsErr.OnType(func(err types.ProxyDialError) error { - fmt.Fprintln(os.Stderr, config.StyleRed.Render("[PROXY] ")+err.Error()) + lipgloss.Fprintln(os.Stderr, config.StyleRed.Render("[PROXY] ")+err.Error()) os.Exit(1) return nil }), utilsErr.OnSentinel(types.ErrScriptEmpty, func(err error) error { - fmt.Fprintln(os.Stderr, config.StyleRed.Render("[SCRIPT] ")+err.Error()) + lipgloss.Fprintln(os.Stderr, config.StyleRed.Render("[SCRIPT] ")+err.Error()) os.Exit(1) return nil }), utilsErr.OnType(func(err types.ScriptLoadError) error { - fmt.Fprintln(os.Stderr, config.StyleRed.Render("[SCRIPT] ")+err.Error()) + lipgloss.Fprintln(os.Stderr, config.StyleRed.Render("[SCRIPT] ")+err.Error()) os.Exit(1) return nil }), diff --git a/go.mod b/go.mod index d543f2b..a534df7 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module go.aykhans.me/sarin go 1.26.5 require ( + charm.land/bubbles/v2 v2.1.1 + charm.land/bubbletea/v2 v2.0.8 + charm.land/glamour/v2 v2.0.1 + charm.land/lipgloss/v2 v2.0.6 github.com/brianvoe/gofakeit/v7 v7.15.0 - github.com/charmbracelet/bubbles v1.0.0 - github.com/charmbracelet/bubbletea v1.3.10 - github.com/charmbracelet/glamour v1.0.0 - github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 github.com/charmbracelet/x/term v0.2.2 github.com/dop251/goja v0.0.0-20260806115107-493f22071ef6 github.com/joho/godotenv v1.5.1 @@ -21,38 +21,33 @@ require ( require ( github.com/alecthomas/chroma/v2 v2.27.0 // indirect github.com/andybalholm/brotli v1.2.2 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/colorprofile v0.4.3 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 // indirect github.com/charmbracelet/x/ansi v0.11.8 // indirect - github.com/charmbracelet/x/cellbuf v0.0.15 // indirect github.com/charmbracelet/x/exp/slice v0.0.0-20260816001655-68d539dca504 // indirect + github.com/charmbracelet/x/termios v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2/v2 v2.7.1 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/google/pprof v0.0.0-20260802141513-ef3492d7dac3 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/klauspost/compress v1.19.2 // indirect github.com/lucasb-eyer/go-colorful v1.4.1 // indirect - github.com/mattn/go-isatty v0.0.24 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.27 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.16.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/xo/terminfo v1.0.0 // indirect github.com/yuin/goldmark v1.8.5 // indirect github.com/yuin/goldmark-emoji v1.0.6 // indirect + golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect - golang.org/x/term v0.45.0 // indirect golang.org/x/text v0.41.0 // indirect ) diff --git a/go.sum b/go.sum index 4e8dbdb..4a4af1e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,11 @@ +charm.land/bubbles/v2 v2.1.1 h1:7r55WzBxpo/R3z98hGmY7KKPd3ET6vsf0Fb9sDHOV60= +charm.land/bubbles/v2 v2.1.1/go.mod h1:GE6M31gaWZVXzGw73OeuTTgy4lX+OtkH0E5ymnNsHxo= +charm.land/bubbletea/v2 v2.0.8 h1:SxTJMhCAI3lbPmy4SgX5LWZ24AdINr4I6UEqzZvYJuY= +charm.land/bubbletea/v2 v2.0.8/go.mod h1:2SkdgoTXluXJHOUwAoRlRXF/28vklb1rFl6GcgV1/ss= +charm.land/glamour/v2 v2.0.1 h1:xl+r00A4aJWU0z8fgwKd9fQQ4rsphqGUzuEiXZP5n+c= +charm.land/glamour/v2 v2.0.1/go.mod h1:jo9z8XqVKPeEFMVdvCRLGk++RyJ3CdUwgNr7EvXLw3k= +charm.land/lipgloss/v2 v2.0.6 h1:EaGKeuA8FvF+v2BT5VmZd2LoYLaMZJXA5n34th8nCIQ= +charm.land/lipgloss/v2 v2.0.6/go.mod h1:ipDDJNSGa1hlwDtSfW1s2/xR8Vdhbut4PXh2zEKZd0Q= github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= @@ -8,36 +16,30 @@ github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM= github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= -github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= +github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o= +github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/brianvoe/gofakeit/v7 v7.15.0 h1:kGLYAWN8tnmxq2PelKVK6zwpM7kMxdz9SGPH31mFkNs= github.com/brianvoe/gofakeit/v7 v7.15.0/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= -github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc= -github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E= -github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= -github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/glamour v1.0.0 h1:AWMLOVFHTsysl4WV8T8QgkQ0s/ZNZo7CiE4WKhk8l08= -github.com/charmbracelet/glamour v1.0.0/go.mod h1:DSdohgOBkMr2ZQNhw4LZxSGpx3SvpeujNoXrQyH2hxo= github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE= -github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 h1:rdnVWKgJpTVXKuKuJyxDJ+NFJdUaUqGvyGy61OcvlbA= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886/go.mod h1:nAw0d9PhFp1qdzi2xhQU5YOu5sVpDIHWlaW2Uz/bCro= github.com/charmbracelet/x/ansi v0.11.8 h1:JMFwp0CgDC2+jcOB162HH5k7I3FVbgFSMMYg7dSPBQQ= github.com/charmbracelet/x/ansi v0.11.8/go.mod h1:ZNN+3mXny/516oTQPLMPIBeSINvNJJQ8uQXDgbeJxY0= -github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= -github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= -github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= github.com/charmbracelet/x/exp/slice v0.0.0-20260816001655-68d539dca504 h1:Z0hBPQ9hslsfpFRRdMn+4cjnb3LK6FQH58hQkXrXv0A= github.com/charmbracelet/x/exp/slice v0.0.0-20260816001655-68d539dca504/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= +github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= +github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= +github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= +github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= @@ -48,8 +50,6 @@ github.com/dlclark/regexp2/v2 v2.7.1 h1:yqDtwI1ptXXvEUNpYTk2lad4jLtAcKqkzepn4sav github.com/dlclark/regexp2/v2 v2.7.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/dop251/goja v0.0.0-20260806115107-493f22071ef6 h1:Oh2rRG1un7tLlC3/NJDzKppZ4CeZGkVFJCUOTRwLpfw= github.com/dop251/goja v0.0.0-20260806115107-493f22071ef6/go.mod h1:LiIEzozrcvNXorsG/3+ypGqdTUAqZryhzSsqi0oU/Qg= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= @@ -66,27 +66,14 @@ github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss= github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= -github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.27 h1:Feg/Oou5zI/wnpgDF6omIU0OokC9GxLC/WRknhVlIR0= github.com/mattn/go-runewidth v0.0.27/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -113,11 +100,10 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= -golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/config/config.go b/internal/config/config.go index 2694622..c8150a0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,11 +12,11 @@ import ( "strings" "time" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/glamour" - "github.com/charmbracelet/glamour/styles" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/viewport" + tea "charm.land/bubbletea/v2" + "charm.land/glamour/v2" + "charm.land/glamour/v2/styles" + "charm.land/lipgloss/v2" "github.com/charmbracelet/x/term" "go.aykhans.me/sarin/internal/sarin" "go.aykhans.me/sarin/internal/script" @@ -249,7 +249,7 @@ func (config Config) MarshalYAML() (any, error) { func (config Config) Print() bool { configYAML, err := yaml.Marshal(config) if err != nil { - fmt.Fprintln(os.Stderr, StyleRed.Render("Error marshaling config to yaml: "+err.Error())) + lipgloss.Fprintln(os.Stderr, StyleRed.Render("Error marshaling config to yaml: "+err.Error())) os.Exit(1) } @@ -268,25 +268,23 @@ func (config Config) Print() bool { glamour.WithWordWrap(0), ) if err != nil { - fmt.Fprintln(os.Stderr, StyleRed.Render(err.Error())) + lipgloss.Fprintln(os.Stderr, StyleRed.Render(err.Error())) os.Exit(1) } content, err := renderer.Render("```yaml\n" + string(configYAML) + "```") if err != nil { - fmt.Fprintln(os.Stderr, StyleRed.Render(err.Error())) + lipgloss.Fprintln(os.Stderr, StyleRed.Render(err.Error())) os.Exit(1) } p := tea.NewProgram( printConfigModel{content: strings.Trim(content, "\n"), rawContent: configYAML}, - tea.WithAltScreen(), - tea.WithMouseCellMotion(), ) m, err := p.Run() if err != nil { - fmt.Fprintln(os.Stderr, StyleRed.Render(err.Error())) + lipgloss.Fprintln(os.Stderr, StyleRed.Render(err.Error())) os.Exit(1) } @@ -616,7 +614,7 @@ func ReadAllConfigs() *Config { _ = utilsErr.MustHandle(err, utilsErr.OnType(func(err types.CLIUnexpectedArgsError) error { cliParser.PrintHelp() - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, StyleYellow.Render( "\nUnexpected CLI arguments provided: ", )+strings.Join(err.Args, ", "), @@ -638,7 +636,7 @@ func ReadAllConfigs() *Config { _ = utilsErr.MustHandle(err, utilsErr.OnType(func(err types.ConfigFileReadError) error { cliParser.PrintHelp() - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, StyleYellow.Render( fmt.Sprintf("\nFailed to read config file (%s): ", configFile.Path())+err.Error(), ), @@ -647,7 +645,7 @@ func ReadAllConfigs() *Config { return nil }), utilsErr.OnType(func(err types.UnmarshalError) error { - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, StyleYellow.Render( fmt.Sprintf("\nFailed to parse config file (%s): ", configFile.Path())+err.Error(), ), @@ -754,11 +752,11 @@ func validateScriptSource(script string) error { func printParseErrors(parserName string, errors ...types.FieldParseError) { for _, fieldErr := range errors { if fieldErr.Value == "" { - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, StyleYellow.Render(fmt.Sprintf("[%s] Field '%s': ", parserName, fieldErr.Field))+fieldErr.Err.Error(), ) } else { - fmt.Fprintln(os.Stderr, + lipgloss.Fprintln(os.Stderr, StyleYellow.Render(fmt.Sprintf("[%s] Field '%s' (%s): ", parserName, fieldErr.Field, fieldErr.Value))+fieldErr.Err.Error(), ) } @@ -801,7 +799,7 @@ func (m printConfigModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch msg.String() { case "ctrl+c", "esc": return m, tea.Quit @@ -824,13 +822,22 @@ func (m printConfigModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (m printConfigModel) View() string { +func (m printConfigModel) View() tea.View { + // AltScreen and MouseMode were program options in bubbletea v1; in v2 they + // are view properties, so every return path has to declare them. + newView := func(s string) tea.View { + v := tea.NewView(s) + v.AltScreen = true + v.MouseMode = tea.MouseModeCellMotion + return v + } + if !m.ready { - return "\n Initializing..." + return newView("\n Initializing...") } content := lipgloss.JoinHorizontal(lipgloss.Top, m.viewport.View(), m.scrollbar()) - return fmt.Sprintf("%s\n%s\n%s", m.headerView(), content, m.footerView()) + return newView(fmt.Sprintf("%s\n%s\n%s", m.headerView(), content, m.footerView())) } func (m *printConfigModel) saveContent() (printConfigModel, tea.Cmd) { @@ -850,12 +857,12 @@ func (m *printConfigModel) handleResize(msg tea.WindowSizeMsg) { width := msg.Width - scrollbarWidth if !m.ready { - m.viewport = viewport.New(width, height) + m.viewport = viewport.New(viewport.WithWidth(width), viewport.WithHeight(height)) m.viewport.SetContent(m.contentWithLineNumbers()) m.ready = true } else { - m.viewport.Width = width - m.viewport.Height = height + m.viewport.SetWidth(width) + m.viewport.SetHeight(height) } } @@ -870,12 +877,12 @@ func (m printConfigModel) headerView() string { printConfigKeyStyle.Render("ESC") + printConfigDescStyle.Render(" exit") title = printConfigHelpStyle.Render(help) } - line := strings.Repeat("─", max(0, m.viewport.Width+scrollbarWidth-lipgloss.Width(title))) + line := strings.Repeat("─", max(0, m.viewport.Width()+scrollbarWidth-lipgloss.Width(title))) return lipgloss.JoinHorizontal(lipgloss.Center, title, line) } func (m printConfigModel) footerView() string { - return strings.Repeat("─", m.viewport.Width+scrollbarWidth) + return strings.Repeat("─", m.viewport.Width()+scrollbarWidth) } func (m printConfigModel) contentWithLineNumbers() string { @@ -897,7 +904,7 @@ func (m printConfigModel) contentWithLineNumbers() string { } func (m printConfigModel) scrollbar() string { - height := m.viewport.Height + height := m.viewport.Height() trackHeight := height - scrollbarBottomSpace totalLines := m.viewport.TotalLineCount() diff --git a/internal/sarin/response.go b/internal/sarin/response.go index 3c62a8b..fef21a3 100644 --- a/internal/sarin/response.go +++ b/internal/sarin/response.go @@ -2,7 +2,6 @@ package sarin import ( "encoding/json" - "fmt" "math/big" "os" "slices" @@ -10,8 +9,8 @@ import ( "sync" "time" - "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/lipgloss/table" + "charm.land/lipgloss/v2" + "charm.land/lipgloss/v2/table" "go.yaml.in/yaml/v4" ) @@ -159,7 +158,7 @@ func (data *SarinResponseData) PrintTable() { return cellStyle }) - fmt.Println(tbl) + lipgloss.Println(tbl) } func (data *SarinResponseData) PrintJSON() { diff --git a/internal/sarin/stop.go b/internal/sarin/stop.go index f43ea26..3a563a4 100644 --- a/internal/sarin/stop.go +++ b/internal/sarin/stop.go @@ -6,7 +6,7 @@ import ( "sync" "sync/atomic" - tea "github.com/charmbracelet/bubbletea" + tea "charm.land/bubbletea/v2" ) const forceExitCode = 130 diff --git a/internal/sarin/tui.go b/internal/sarin/tui.go index adbd2d9..8128155 100644 --- a/internal/sarin/tui.go +++ b/internal/sarin/tui.go @@ -7,10 +7,10 @@ import ( "sync/atomic" "time" - "github.com/charmbracelet/bubbles/progress" - "github.com/charmbracelet/bubbles/spinner" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" + "charm.land/bubbles/v2/progress" + "charm.land/bubbles/v2/spinner" + tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) type tickMsg time.Time @@ -82,15 +82,15 @@ func (m progressModel) Init() tea.Cmd { func (m progressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case tea.KeyMsg: - if msg.Type == tea.KeyCtrlC { + case tea.KeyPressMsg: + if msg.String() == "ctrl+c" { m.cancelling = true m.stop() } return m, nil case tea.WindowSizeMsg: - m.progress.Width = max(10, msg.Width-1) + m.progress.SetWidth(max(10, msg.Width-1)) if m.ctx.Err() != nil { return m, tea.Quit } @@ -117,7 +117,7 @@ func (m progressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } -func (m progressModel) View() string { +func (m progressModel) View() tea.View { var b strings.Builder if box := renderLogBox(m.logs); box != "" { b.WriteString(box) @@ -138,7 +138,7 @@ func (m progressModel) View() string { b.WriteString("\n\n ") b.WriteString(helpLine(m.cancelling)) - return b.String() + return tea.NewView(b.String()) } func progressTickCmd() tea.Cmd { @@ -167,8 +167,8 @@ func (m infiniteProgressModel) Init() tea.Cmd { func (m infiniteProgressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case tea.KeyMsg: - if msg.Type == tea.KeyCtrlC { + case tea.KeyPressMsg: + if msg.String() == "ctrl+c" { m.cancelling = true m.stop() } @@ -193,7 +193,7 @@ func (m infiniteProgressModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } -func (m infiniteProgressModel) View() string { +func (m infiniteProgressModel) View() tea.View { var b strings.Builder if box := renderLogBox(m.logs); box != "" { b.WriteString(box) @@ -206,7 +206,7 @@ func (m infiniteProgressModel) View() string { b.WriteString("\n\n ") b.WriteString(helpLine(m.cancelling)) } - return b.String() + return tea.NewView(b.String()) } if m.quit { @@ -227,7 +227,7 @@ func (m infiniteProgressModel) View() string { b.WriteString("\n\n ") b.WriteString(helpLine(m.cancelling)) } - return b.String() + return tea.NewView(b.String()) } func (s sarin) streamProgress( @@ -242,7 +242,7 @@ func (s sarin) streamProgress( var program *tea.Program if total > 0 { model := progressModel{ - progress: progress.New(progress.WithGradient("#151594", "#00D4FF")), + progress: progress.New(progress.WithColors(lipgloss.Color("#151594"), lipgloss.Color("#00D4FF"))), startTime: time.Now(), logs: make([]string, 8), counter: counter, diff --git a/nix/package.nix b/nix/package.nix index b765a37..86e8937 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -11,7 +11,7 @@ src = lib.cleanSource ../.; - vendorHash = "sha256-aVQ/Wsf72md9v55hZ/ig9MqBvV70msmYswUw/yIdlmk="; + vendorHash = "sha256-hGrS/drQiBOcqwloi15vqOdiTbweo0Oya+fF9SLM3so="; subPackages = [ "cmd/cli" ];