diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..d5273520ad5ecc37dd839a3077803b2c6581b2a1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.golden linguist-generated=true -text diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 1e271bbb6e180557b241a6ab5e40acf7b82705df..2589af4376279ce3fc5902d370f7b85bad1dcff6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -6,7 +6,26 @@ on: workflow_dispatch: # allows manual triggering jobs: + check: + runs-on: ubuntu-latest + outputs: + should_run: ${{ steps.check.outputs.should_run }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - id: check + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + if gh run list --workflow nightly.yml -c $(git rev-parse HEAD) -s success | grep 'completed'; then + echo "should_run=false" >> $GITHUB_OUTPUT + else + echo "should_run=true" >> $GITHUB_OUTPUT + fi nightly: + needs: check + if: needs.check.outputs.should_run == 'true' uses: charmbracelet/meta/.github/workflows/nightly.yml@main secrets: goreleaser_key: ${{ secrets.GORELEASER_KEY }} diff --git a/.gitignore b/.gitignore index b28e5a0c727163e8f3585522e680d1df2ad6e621..2f16f744432d89e0a72fd6ea8e359678a64b6d42 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ # Go workspace file go.work +go.work.sum # IDE specific files .idea/ diff --git a/.goreleaser.yml b/.goreleaser.yml index 10a40960e47f7648f8ce790d26f5eb9656323e79..08bf77c7feb1a1938909234efe913fa63f26b0cc 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -36,8 +36,8 @@ before: - sh -c 'go run . completion fish >./completions/crush.fish' - sh -c 'go run . man | gzip -c >./manpages/crush.1.gz' -gomod: - proxy: true +# gomod: +# proxy: true builds: - env: diff --git a/cmd/root.go b/cmd/root.go index 20c92f19357ed3350a36633c9b1be7bd91cd7ce0..9ae26b993dd1be7374907305ae4cc90036cb05d6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,17 +6,14 @@ import ( "io" "log/slog" "os" - "sync" "time" tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/app" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/db" - "github.com/charmbracelet/crush/internal/format" "github.com/charmbracelet/crush/internal/llm/agent" "github.com/charmbracelet/crush/internal/log" - "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/tui" "github.com/charmbracelet/crush/internal/version" "github.com/charmbracelet/fang" @@ -54,14 +51,8 @@ to assist developers in writing, debugging, and understanding code directly from debug, _ := cmd.Flags().GetBool("debug") cwd, _ := cmd.Flags().GetString("cwd") prompt, _ := cmd.Flags().GetString("prompt") - outputFormat, _ := cmd.Flags().GetString("output-format") quiet, _ := cmd.Flags().GetBool("quiet") - // Validate format option - if !format.IsValid(outputFormat) { - return fmt.Errorf("invalid format option: %s\n%s", outputFormat, format.GetHelpText()) - } - if cwd != "" { err := os.Chdir(cwd) if err != nil { @@ -81,9 +72,7 @@ to assist developers in writing, debugging, and understanding code directly from return err } - // Create main context for the application - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := cmd.Context() // Connect DB, this will also run migrations conn, err := db.Connect(ctx, cfg.Options.DataDirectory) @@ -111,7 +100,7 @@ to assist developers in writing, debugging, and understanding code directly from // Non-interactive mode if prompt != "" { // Run non-interactive flow using the App method - return app.RunNonInteractive(ctx, prompt, outputFormat, quiet) + return app.RunNonInteractive(ctx, prompt, quiet) } // Set up the TUI @@ -124,76 +113,17 @@ to assist developers in writing, debugging, and understanding code directly from tea.WithFilter(tui.MouseEventFilter), // Filter mouse events based on focus state ) - // Setup the subscriptions, this will send services events to the TUI - ch, cancelSubs := setupSubscriptions(app, ctx) - - // Create a context for the TUI message handler - tuiCtx, tuiCancel := context.WithCancel(ctx) - var tuiWg sync.WaitGroup - tuiWg.Add(1) - - // Set up message handling for the TUI - go func() { - defer tuiWg.Done() - defer log.RecoverPanic("TUI-message-handler", func() { - attemptTUIRecovery(program) - }) - - for { - select { - case <-tuiCtx.Done(): - slog.Info("TUI message handler shutting down") - return - case msg, ok := <-ch: - if !ok { - slog.Info("TUI message channel closed") - return - } - program.Send(msg) - } - } - }() - - // Cleanup function for when the program exits - cleanup := func() { - // Shutdown the app - app.Shutdown() - - // Cancel subscriptions first - cancelSubs() - - // Then cancel TUI message handler - tuiCancel() + go app.Subscribe(program) - // Wait for TUI message handler to finish - tuiWg.Wait() - - slog.Info("All goroutines cleaned up") - } - - // Run the TUI - result, err := program.Run() - cleanup() - - if err != nil { + if _, err := program.Run(); err != nil { slog.Error(fmt.Sprintf("TUI run error: %v", err)) return fmt.Errorf("TUI error: %v", err) } - - slog.Info(fmt.Sprintf("TUI exited with result: %v", result)) + app.Shutdown() return nil }, } -// attemptTUIRecovery tries to recover the TUI after a panic -func attemptTUIRecovery(program *tea.Program) { - slog.Info("Attempting to recover TUI after panic") - - // We could try to restart the TUI or gracefully exit - // For now, we'll just quit the program to avoid further issues - program.Quit() -} - func initMCPTools(ctx context.Context, app *app.App, cfg *config.Config) { go func() { defer log.RecoverPanic("MCP-goroutine", nil) @@ -208,86 +138,12 @@ func initMCPTools(ctx context.Context, app *app.App, cfg *config.Config) { }() } -func setupSubscriber[T any]( - ctx context.Context, - wg *sync.WaitGroup, - name string, - subscriber func(context.Context) <-chan pubsub.Event[T], - outputCh chan<- tea.Msg, -) { - wg.Add(1) - go func() { - defer wg.Done() - defer log.RecoverPanic(fmt.Sprintf("subscription-%s", name), nil) - - subCh := subscriber(ctx) - - for { - select { - case event, ok := <-subCh: - if !ok { - slog.Info("subscription channel closed", "name", name) - return - } - - var msg tea.Msg = event - - select { - case outputCh <- msg: - case <-time.After(2 * time.Second): - slog.Warn("message dropped due to slow consumer", "name", name) - case <-ctx.Done(): - slog.Info("subscription cancelled", "name", name) - return - } - case <-ctx.Done(): - slog.Info("subscription cancelled", "name", name) - return - } - } - }() -} - -func setupSubscriptions(app *app.App, parentCtx context.Context) (chan tea.Msg, func()) { - ch := make(chan tea.Msg, 100) - - wg := sync.WaitGroup{} - ctx, cancel := context.WithCancel(parentCtx) // Inherit from parent context - - setupSubscriber(ctx, &wg, "sessions", app.Sessions.Subscribe, ch) - setupSubscriber(ctx, &wg, "messages", app.Messages.Subscribe, ch) - setupSubscriber(ctx, &wg, "permissions", app.Permissions.Subscribe, ch) - setupSubscriber(ctx, &wg, "coderAgent", app.CoderAgent.Subscribe, ch) - setupSubscriber(ctx, &wg, "history", app.History.Subscribe, ch) - - cleanupFunc := func() { - slog.Info("Cancelling all subscriptions") - cancel() // Signal all goroutines to stop - - waitCh := make(chan struct{}) - go func() { - defer log.RecoverPanic("subscription-cleanup", nil) - wg.Wait() - close(waitCh) - }() - - select { - case <-waitCh: - slog.Info("All subscription goroutines completed successfully") - close(ch) // Only close after all writers are confirmed done - case <-time.After(5 * time.Second): - slog.Warn("Timed out waiting for some subscription goroutines to complete") - close(ch) - } - } - return ch, cleanupFunc -} - func Execute() { if err := fang.Execute( context.Background(), rootCmd, fang.WithVersion(version.Version), + fang.WithNotifySignal(os.Interrupt), ); err != nil { os.Exit(1) } @@ -300,17 +156,8 @@ func init() { rootCmd.Flags().BoolP("debug", "d", false, "Debug") rootCmd.Flags().StringP("prompt", "p", "", "Prompt to run in non-interactive mode") - // Add format flag with validation logic - rootCmd.Flags().StringP("output-format", "f", format.Text.String(), - "Output format for non-interactive mode (text, json)") - // Add quiet flag to hide spinner in non-interactive mode rootCmd.Flags().BoolP("quiet", "q", false, "Hide spinner in non-interactive mode") - - // Register custom validation for the format flag - rootCmd.RegisterFlagCompletionFunc("output-format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return format.SupportedFormats, cobra.ShellCompDirectiveNoFileComp - }) } func maybePrependStdin(prompt string) (string, error) { diff --git a/go.mod b/go.mod index 7f4d7493c34e10a1d62bb311afc71b12e930ecd1..d510a774a03c27ceca623400257228763cc2e9a1 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,9 @@ module github.com/charmbracelet/crush go 1.24.3 -replace github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891 +replace github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595 -replace github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093 +replace github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 @@ -16,20 +16,20 @@ require ( github.com/aymanbagabas/go-udiff v0.3.1 github.com/bmatcuk/doublestar/v4 v4.8.1 github.com/charlievieth/fastwalk v1.0.11 - github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e + github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250710161907-a4c42b579198 github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 - github.com/charmbracelet/fang v0.1.0 + github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674 github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe - github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 + github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3 github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706 github.com/charmbracelet/x/ansi v0.9.3 - github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c + github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec github.com/fsnotify/fsnotify v1.8.0 github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 - github.com/mark3labs/mcp-go v0.32.0 + github.com/mark3labs/mcp-go v0.33.0 github.com/muesli/termenv v0.16.0 github.com/ncruces/go-sqlite3 v0.25.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 @@ -43,22 +43,12 @@ require ( github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef github.com/stretchr/testify v1.10.0 + github.com/tidwall/sjson v1.2.5 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 gopkg.in/natefinch/lumberjack.v2 v2.2.1 mvdan.cc/sh/v3 v3.11.0 ) -require ( - github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/spf13/cast v1.7.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect -) - -require ( - github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 // indirect - github.com/charmbracelet/x/termios v0.1.1 // indirect -) - require ( cloud.google.com/go v0.116.0 // indirect cloud.google.com/go/auth v0.13.0 // indirect @@ -85,15 +75,18 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/colorprofile v0.3.1 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 // indirect github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa // indirect github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef github.com/charmbracelet/x/term v0.2.1 + github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/disintegration/gift v1.1.2 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect @@ -121,12 +114,12 @@ require ( github.com/rivo/uniseg v0.4.7 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect + github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/tetratelabs/wazero v1.9.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/sjson v1.2.5 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yuin/goldmark v1.7.8 // indirect @@ -148,5 +141,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/grpc v1.71.0 // indirect google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d35233348b9c20b1d5556294a2f2bce4b2f9e2a9..d7004401154b86ce0658162c06bfc610a0c77126 100644 --- a/go.sum +++ b/go.sum @@ -68,18 +68,18 @@ github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/charlievieth/fastwalk v1.0.11 h1:5sLT/q9+d9xMdpKExawLppqvXFZCVKf6JHnr2u/ufj8= github.com/charlievieth/fastwalk v1.0.11/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI= -github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e h1:99Ugtt633rqauFsXjZobZmtkNpeaWialfj8dl6COC6A= -github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw= -github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891 h1:wh6N1dR4XkDh6XsiZh1/tImJAZvYB0yVLmaUKvJXvK0= -github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891/go.mod h1:SwBB+WoaQVMMOM9hknbN/7FNT86kgKG0LSHGTmLphX8= +github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250710161907-a4c42b579198 h1:CkMS9Ah9ac1Ego5JDC5NJyZyAAqu23Z+O0yDwsa3IxM= +github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250710161907-a4c42b579198/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw= +github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595 h1:wLMjzOqrwoM7Em9UR9sGbn4375G8WuxcwFB3kjZiqHo= +github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595/go.mod h1:+Tl7rePElw6OKt382t04zXwtPFoPXxAaJzNrYmtsLds= github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= -github.com/charmbracelet/fang v0.1.0 h1:SlZS2crf3/zQh7Mr4+W+7QR1k+L08rrPX5rm5z3d7Wg= -github.com/charmbracelet/fang v0.1.0/go.mod h1:Zl/zeUQ8EtQuGyiV0ZKZlZPDowKRTzu8s/367EpN/fc= +github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674 h1:+Cz+VfxD5DO+JT1LlswXWhre0HYLj6l2HW8HVGfMuC0= +github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674/go.mod h1:9gCUAHmVx5BwSafeyNr3GI0GgvlB1WYjL21SkPp1jyU= github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe h1:i6ce4CcAlPpTj2ER69m1DBeLZ3RRcHnKExuwhKa3GfY= github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe/go.mod h1:p3Q+aN4eQKeM5jhrmXPMgPrlKbmc59rWSnMsSA3udhk= -github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093 h1:c9vOmNJQUwy/lp/pNOB5ZDMhOuXJ3Y2LL9uZMYGgJxQ= -github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093/go.mod h1:XmxjFJcMEfYIHa4Mw4ra+uMjploDkTlkKIs7wLt9v4Q= +github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb h1:lswj7CYZVYbLn2OhYJsXOMRQQGdRIfyuSnh5FdVSMr0= +github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb/go.mod h1:wEc/TRrTAIDJYjVCg3+y8WeKaN+F88gpYfGbUuP6W3A= github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706 h1:WkwO6Ks3mSIGnGuSdKl9qDSyfbYK50z2wc2gGMggegE= github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706/go.mod h1:mjJGp00cxcfvD5xdCa+bso251Jt4owrQvuimJtVmEmM= github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 h1:+LLFCLxtb/sHegwY3zYdFAbaOgI/I9pv/pxdUlI1Q9s= @@ -88,8 +88,8 @@ github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa h1:lphz0Z3rsiOtMYiz8axkT24i9yFiueDhJbzyNUADmME= github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa/go.mod h1:xBlh2Yi3DL3zy/2n15kITpg0YZardf/aa/hgUaIM6Rk= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c h1:2GELBLPgfSbHU53bsQhR9XIgNuVZ6w+Rz8RWV5Lq+A4= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1xwHZg6eMZ9Wv5TE1UGub6ARubyOd1Lo5kPUI/6VL50= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0= github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw= github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef h1:v7qwsZ2OxzlwvpKwz8dtZXp7fIJlcDEUOyFBNE4fz4Q= @@ -165,8 +165,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mark3labs/mcp-go v0.32.0 h1:fgwmbfL2gbd67obg57OfV2Dnrhs1HtSdlY/i5fn7MU8= -github.com/mark3labs/mcp-go v0.32.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc= +github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= diff --git a/internal/app/app.go b/internal/app/app.go index da014df81367665caf1df793760e3d832c223648..c3dae3d88a2be7c4cd5491e089b97695b08a7a23 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -10,11 +10,14 @@ import ( "sync" "time" + tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/db" "github.com/charmbracelet/crush/internal/format" "github.com/charmbracelet/crush/internal/history" "github.com/charmbracelet/crush/internal/llm/agent" + "github.com/charmbracelet/crush/internal/log" + "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/lsp" "github.com/charmbracelet/crush/internal/message" @@ -36,9 +39,18 @@ type App struct { watcherCancelFuncs []context.CancelFunc cancelFuncsMutex sync.Mutex - watcherWG sync.WaitGroup + lspWatcherWG sync.WaitGroup config *config.Config + + serviceEventsWG *sync.WaitGroup + eventsCtx context.Context + events chan tea.Msg + tuiWG *sync.WaitGroup + + // global context and cleanup functions + globalCtx context.Context + cleanupFuncs []func() } func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) { @@ -53,46 +65,53 @@ func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) { History: files, Permissions: permission.NewPermissionService(cfg.WorkingDir()), LSPClients: make(map[string]*lsp.Client), - config: cfg, + + globalCtx: ctx, + + config: cfg, + + events: make(chan tea.Msg, 100), + serviceEventsWG: &sync.WaitGroup{}, + tuiWG: &sync.WaitGroup{}, } + app.setupEvents() + // Initialize LSP clients in the background go app.initLSPClients(ctx) // TODO: remove the concept of agent config most likely - coderAgentCfg := cfg.Agents["coder"] - if coderAgentCfg.ID == "" { - return nil, fmt.Errorf("coder agent configuration is missing") - } - - var err error - app.CoderAgent, err = agent.NewAgent( - coderAgentCfg, - app.Permissions, - app.Sessions, - app.Messages, - app.History, - app.LSPClients, - ) - if err != nil { - slog.Error("Failed to create coder agent", "err", err) - return nil, err + if cfg.IsConfigured() { + if err := app.InitCoderAgent(); err != nil { + return nil, fmt.Errorf("failed to initialize coder agent: %w", err) + } + } else { + slog.Warn("No agent configuration found") } - return app, nil } // RunNonInteractive handles the execution flow when a prompt is provided via CLI flag. -func (a *App) RunNonInteractive(ctx context.Context, prompt string, outputFormat string, quiet bool) error { +func (a *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) error { slog.Info("Running in non-interactive mode") + ctx, cancel := context.WithCancel(ctx) + defer cancel() + // Start spinner if not in quiet mode var spinner *format.Spinner if !quiet { - spinner = format.NewSpinner("Thinking...") + spinner = format.NewSpinner(ctx, cancel, "Generating") spinner.Start() - defer spinner.Stop() } + // Helper function to stop spinner once + stopSpinner := func() { + if !quiet && spinner != nil { + spinner.Stop() + spinner = nil + } + } + defer stopSpinner() const maxPromptLengthForTitle = 100 titlePrefix := "Non-interactive: " @@ -119,59 +138,176 @@ func (a *App) RunNonInteractive(ctx context.Context, prompt string, outputFormat return fmt.Errorf("failed to start agent processing stream: %w", err) } - result := <-done - if result.Error != nil { - if errors.Is(result.Error, context.Canceled) || errors.Is(result.Error, agent.ErrRequestCancelled) { - slog.Info("Agent processing cancelled", "session_id", sess.ID) + messageEvents := a.Messages.Subscribe(ctx) + readBts := 0 + + for { + select { + case result := <-done: + stopSpinner() + + if result.Error != nil { + if errors.Is(result.Error, context.Canceled) || errors.Is(result.Error, agent.ErrRequestCancelled) { + slog.Info("Agent processing cancelled", "session_id", sess.ID) + return nil + } + return fmt.Errorf("agent processing failed: %w", result.Error) + } + + part := result.Message.Content().String()[readBts:] + fmt.Println(part) + + slog.Info("Non-interactive run completed", "session_id", sess.ID) return nil + + case event := <-messageEvents: + msg := event.Payload + if msg.SessionID == sess.ID && msg.Role == message.Assistant && len(msg.Parts) > 0 { + stopSpinner() + part := msg.Content().String()[readBts:] + fmt.Print(part) + readBts += len(part) + } + + case <-ctx.Done(): + stopSpinner() + return ctx.Err() } - return fmt.Errorf("agent processing failed: %w", result.Error) } +} - // Stop spinner before printing output - if !quiet && spinner != nil { - spinner.Stop() - } +func (app *App) UpdateAgentModel() error { + return app.CoderAgent.UpdateModel() +} - // Get the text content from the response - content := "No content available" - if result.Message.Content().String() != "" { - content = result.Message.Content().String() +func (app *App) setupEvents() { + ctx, cancel := context.WithCancel(app.globalCtx) + app.eventsCtx = ctx + setupSubscriber(ctx, app.serviceEventsWG, "sessions", app.Sessions.Subscribe, app.events) + setupSubscriber(ctx, app.serviceEventsWG, "messages", app.Messages.Subscribe, app.events) + setupSubscriber(ctx, app.serviceEventsWG, "permissions", app.Permissions.Subscribe, app.events) + setupSubscriber(ctx, app.serviceEventsWG, "history", app.History.Subscribe, app.events) + cleanupFunc := func() { + cancel() + app.serviceEventsWG.Wait() } + app.cleanupFuncs = append(app.cleanupFuncs, cleanupFunc) +} - fmt.Println(format.FormatOutput(content, outputFormat)) - - slog.Info("Non-interactive run completed", "session_id", sess.ID) +func setupSubscriber[T any]( + ctx context.Context, + wg *sync.WaitGroup, + name string, + subscriber func(context.Context) <-chan pubsub.Event[T], + outputCh chan<- tea.Msg, +) { + wg.Add(1) + go func() { + defer wg.Done() + subCh := subscriber(ctx) + for { + select { + case event, ok := <-subCh: + if !ok { + slog.Debug("subscription channel closed", "name", name) + return + } + var msg tea.Msg = event + select { + case outputCh <- msg: + case <-time.After(2 * time.Second): + slog.Warn("message dropped due to slow consumer", "name", name) + case <-ctx.Done(): + slog.Debug("subscription cancelled", "name", name) + return + } + case <-ctx.Done(): + slog.Debug("subscription cancelled", "name", name) + return + } + } + }() +} +func (app *App) InitCoderAgent() error { + coderAgentCfg := app.config.Agents["coder"] + if coderAgentCfg.ID == "" { + return fmt.Errorf("coder agent configuration is missing") + } + var err error + app.CoderAgent, err = agent.NewAgent( + coderAgentCfg, + app.Permissions, + app.Sessions, + app.Messages, + app.History, + app.LSPClients, + ) + if err != nil { + slog.Error("Failed to create coder agent", "err", err) + return err + } + setupSubscriber(app.eventsCtx, app.serviceEventsWG, "coderAgent", app.CoderAgent.Subscribe, app.events) return nil } +func (app *App) Subscribe(program *tea.Program) { + defer log.RecoverPanic("app.Subscribe", func() { + slog.Info("TUI subscription panic - attempting graceful shutdown") + program.Quit() + }) + + app.tuiWG.Add(1) + tuiCtx, tuiCancel := context.WithCancel(app.globalCtx) + app.cleanupFuncs = append(app.cleanupFuncs, func() { + slog.Debug("Cancelling TUI message handler") + tuiCancel() + app.tuiWG.Wait() + }) + defer app.tuiWG.Done() + for { + select { + case <-tuiCtx.Done(): + slog.Debug("TUI message handler shutting down") + return + case msg, ok := <-app.events: + if !ok { + slog.Debug("TUI message channel closed") + return + } + program.Send(msg) + } + } +} + // Shutdown performs a clean shutdown of the application func (app *App) Shutdown() { - // Cancel all watcher goroutines app.cancelFuncsMutex.Lock() for _, cancel := range app.watcherCancelFuncs { cancel() } app.cancelFuncsMutex.Unlock() - app.watcherWG.Wait() + app.lspWatcherWG.Wait() - // Perform additional cleanup for LSP clients app.clientsMutex.RLock() clients := make(map[string]*lsp.Client, len(app.LSPClients)) maps.Copy(clients, app.LSPClients) app.clientsMutex.RUnlock() for name, client := range clients { - shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + shutdownCtx, cancel := context.WithTimeout(app.globalCtx, 5*time.Second) if err := client.Shutdown(shutdownCtx); err != nil { slog.Error("Failed to shutdown LSP client", "name", name, "error", err) } cancel() } - app.CoderAgent.CancelAll() -} + if app.CoderAgent != nil { + app.CoderAgent.CancelAll() + } -func (app *App) UpdateAgentModel() error { - return app.CoderAgent.UpdateModel() + for _, cleanup := range app.cleanupFuncs { + if cleanup != nil { + cleanup() + } + } } diff --git a/internal/app/lsp.go b/internal/app/lsp.go index 1777a653a4153dc42cc87444f6122df01e82cedd..33506016690645dd714c682ddd2e65e992d2d1f9 100644 --- a/internal/app/lsp.go +++ b/internal/app/lsp.go @@ -59,11 +59,8 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, comman // Create a child context that can be canceled when the app is shutting down watchCtx, cancelFunc := context.WithCancel(ctx) - // Create a context with the server name for better identification - watchCtx = context.WithValue(watchCtx, "serverName", name) - // Create the workspace watcher - workspaceWatcher := watcher.NewWorkspaceWatcher(lspClient) + workspaceWatcher := watcher.NewWorkspaceWatcher(name, lspClient) // Store the cancel function to be called during cleanup app.cancelFuncsMutex.Lock() @@ -71,7 +68,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, comman app.cancelFuncsMutex.Unlock() // Add the watcher to a WaitGroup to track active goroutines - app.watcherWG.Add(1) + app.lspWatcherWG.Add(1) // Add to map with mutex protection before starting goroutine app.clientsMutex.Lock() @@ -83,7 +80,7 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, comman // runWorkspaceWatcher executes the workspace watcher for an LSP client func (app *App) runWorkspaceWatcher(ctx context.Context, name string, workspaceWatcher *watcher.WorkspaceWatcher) { - defer app.watcherWG.Done() + defer app.lspWatcherWG.Done() defer log.RecoverPanic("LSP-"+name, func() { // Try to restart the client app.restartLSPClient(ctx, name) diff --git a/internal/config/config.go b/internal/config/config.go index a32d04f9b62cf6e734f98e35df01c6148e06573a..5108a5cbee1684b92f779243b35aa3a50f162e60 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,10 +2,12 @@ package config import ( "fmt" + "os" "slices" "strings" "github.com/charmbracelet/crush/internal/fur/provider" + "github.com/tidwall/sjson" ) const ( @@ -58,6 +60,8 @@ type SelectedModel struct { type ProviderConfig struct { // The provider's id. ID string `json:"id,omitempty"` + // The provider's name, used for display purposes. + Name string `json:"name,omitempty"` // The provider's API endpoint. BaseURL string `json:"base_url,omitempty"` // The provider type, e.g. "openai", "anthropic", etc. if empty it defaults to openai. @@ -68,7 +72,7 @@ type ProviderConfig struct { Disable bool `json:"disable,omitempty"` // Extra headers to send with each request to the provider. - ExtraHeaders map[string]string + ExtraHeaders map[string]string `json:"extra_headers,omitempty"` // Used to pass extra parameters to the provider. ExtraParams map[string]string `json:"-"` @@ -207,7 +211,9 @@ type Config struct { // TODO: most likely remove this concept when I come back to it Agents map[string]Agent `json:"-"` // TODO: find a better way to do this this should probably not be part of the config - resolver VariableResolver + resolver VariableResolver + dataConfigDir string `json:"-"` + knownProviders []provider.Provider `json:"-"` } func (c *Config) WorkingDir() string { @@ -275,6 +281,14 @@ func (c *Config) SmallModel() *provider.Model { return c.GetModel(model.Provider, model.Model) } +func (c *Config) SetCompactMode(enabled bool) error { + if c.Options == nil { + c.Options = &Options{} + } + c.Options.TUI.CompactMode = enabled + return c.SetConfigField("options.tui.compact_mode", enabled) +} + func (c *Config) Resolve(key string) (string, error) { if c.resolver == nil { return "", fmt.Errorf("no variable resolver configured") @@ -282,9 +296,109 @@ func (c *Config) Resolve(key string) (string, error) { return c.resolver.ResolveValue(key) } -// TODO: maybe handle this better -func UpdatePreferredModel(modelType SelectedModelType, model SelectedModel) error { - cfg := Get() - cfg.Models[modelType] = model +func (c *Config) UpdatePreferredModel(modelType SelectedModelType, model SelectedModel) error { + c.Models[modelType] = model + if err := c.SetConfigField(fmt.Sprintf("models.%s", modelType), model); err != nil { + return fmt.Errorf("failed to update preferred model: %w", err) + } + return nil +} + +func (c *Config) SetConfigField(key string, value any) error { + // read the data + data, err := os.ReadFile(c.dataConfigDir) + if err != nil { + if os.IsNotExist(err) { + data = []byte("{}") + } else { + return fmt.Errorf("failed to read config file: %w", err) + } + } + + newValue, err := sjson.Set(string(data), key, value) + if err != nil { + return fmt.Errorf("failed to set config field %s: %w", key, err) + } + if err := os.WriteFile(c.dataConfigDir, []byte(newValue), 0o644); err != nil { + return fmt.Errorf("failed to write config file: %w", err) + } + return nil +} + +func (c *Config) SetProviderAPIKey(providerID, apiKey string) error { + // First save to the config file + err := c.SetConfigField("providers."+providerID+".api_key", apiKey) + if err != nil { + return fmt.Errorf("failed to save API key to config file: %w", err) + } + + if c.Providers == nil { + c.Providers = make(map[string]ProviderConfig) + } + + providerConfig, exists := c.Providers[providerID] + if exists { + providerConfig.APIKey = apiKey + c.Providers[providerID] = providerConfig + return nil + } + + var foundProvider *provider.Provider + for _, p := range c.knownProviders { + if string(p.ID) == providerID { + foundProvider = &p + break + } + } + + if foundProvider != nil { + // Create new provider config based on known provider + providerConfig = ProviderConfig{ + ID: providerID, + Name: foundProvider.Name, + BaseURL: foundProvider.APIEndpoint, + Type: foundProvider.Type, + APIKey: apiKey, + Disable: false, + ExtraHeaders: make(map[string]string), + ExtraParams: make(map[string]string), + Models: foundProvider.Models, + } + } else { + return fmt.Errorf("provider with ID %s not found in known providers", providerID) + } + // Store the updated provider config + c.Providers[providerID] = providerConfig return nil } + +func (c *Config) SetupAgents() { + agents := map[string]Agent{ + "coder": { + ID: "coder", + Name: "Coder", + Description: "An agent that helps with executing coding tasks.", + Model: SelectedModelTypeLarge, + ContextPaths: c.Options.ContextPaths, + // All tools allowed + }, + "task": { + ID: "task", + Name: "Task", + Description: "An agent that helps with searching for context and finding implementation details.", + Model: SelectedModelTypeLarge, + ContextPaths: c.Options.ContextPaths, + AllowedTools: []string{ + "glob", + "grep", + "ls", + "sourcegraph", + "view", + }, + // NO MCPs or LSPs by default + AllowedMCP: map[string][]string{}, + AllowedLSP: []string{}, + }, + } + c.Agents = agents +} diff --git a/internal/config/init.go b/internal/config/init.go index 200359bff2bea913940cb78588c97733efb7a142..12b30efd75f88d438e0734571cbb5c634ba231bc 100644 --- a/internal/config/init.go +++ b/internal/config/init.go @@ -103,3 +103,11 @@ func MarkProjectInitialized() error { return nil } + +func HasInitialDataConfig() bool { + cfgPath := GlobalConfigData() + if _, err := os.Stat(cfgPath); err != nil { + return false + } + return true +} diff --git a/internal/config/load.go b/internal/config/load.go index 84585d05d56dddbac36d2d147cc5c4cada781c7e..81cb4398e5b3a7a2147ab5388b37088788ea041b 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -37,7 +37,7 @@ func Load(workingDir string, debug bool) (*Config, error) { // uses default config paths configPaths := []string{ globalConfig(), - globalConfigData(), + GlobalConfigData(), filepath.Join(workingDir, fmt.Sprintf("%s.json", appName)), filepath.Join(workingDir, fmt.Sprintf(".%s.json", appName)), } @@ -46,6 +46,8 @@ func Load(workingDir string, debug bool) (*Config, error) { return nil, fmt.Errorf("failed to load config from paths %v: %w", configPaths, err) } + cfg.dataConfigDir = GlobalConfigData() + cfg.setDefaults(workingDir) if debug { @@ -63,6 +65,7 @@ func Load(workingDir string, debug bool) (*Config, error) { if err != nil || len(providers) == 0 { return nil, fmt.Errorf("failed to load providers: %w", err) } + cfg.knownProviders = providers env := env.New() // Configure providers @@ -80,37 +83,7 @@ func Load(workingDir string, debug bool) (*Config, error) { if err := cfg.configureSelectedModels(providers); err != nil { return nil, fmt.Errorf("failed to configure selected models: %w", err) } - - // TODO: remove the agents concept from the config - agents := map[string]Agent{ - "coder": { - ID: "coder", - Name: "Coder", - Description: "An agent that helps with executing coding tasks.", - Model: SelectedModelTypeLarge, - ContextPaths: cfg.Options.ContextPaths, - // All tools allowed - }, - "task": { - ID: "task", - Name: "Task", - Description: "An agent that helps with searching for context and finding implementation details.", - Model: SelectedModelTypeLarge, - ContextPaths: cfg.Options.ContextPaths, - AllowedTools: []string{ - "glob", - "grep", - "ls", - "sourcegraph", - "view", - }, - // NO MCPs or LSPs by default - AllowedMCP: map[string][]string{}, - AllowedLSP: []string{}, - }, - } - cfg.Agents = agents - + cfg.SetupAgents() return cfg, nil } @@ -162,6 +135,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn } prepared := ProviderConfig{ ID: string(p.ID), + Name: p.Name, BaseURL: p.APIEndpoint, APIKey: p.APIKey, Type: p.Type, @@ -218,6 +192,9 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn // Make sure the provider ID is set providerConfig.ID = id + if providerConfig.Name == "" { + providerConfig.Name = id // Use ID as name if not set + } // default to OpenAI if not set if providerConfig.Type == "" { providerConfig.Type = provider.TypeOpenAI @@ -229,9 +206,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn continue } if providerConfig.APIKey == "" { - slog.Warn("Skipping custom provider due to missing API key", "provider", id) - delete(cfg.Providers, id) - continue + slog.Warn("Provider is missing API key, this might be OK for local providers", "provider", id) } if providerConfig.BaseURL == "" { slog.Warn("Skipping custom provider due to missing API endpoint", "provider", id) @@ -251,9 +226,7 @@ func (cfg *Config) configureProviders(env env.Env, resolver VariableResolver, kn apiKey, err := resolver.ResolveValue(providerConfig.APIKey) if apiKey == "" || err != nil { - slog.Warn("Skipping custom provider due to missing API key", "provider", id, "error", err) - delete(cfg.Providers, id) - continue + slog.Warn("Provider is missing API key, this might be OK for local providers", "provider", id) } baseURL, err := resolver.ResolveValue(providerConfig.BaseURL) if baseURL == "" || err != nil { @@ -328,6 +301,7 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la defaultSmallModel := cfg.GetModel(string(p.ID), p.DefaultSmallModelID) if defaultSmallModel == nil { err = fmt.Errorf("default small model %s not found for provider %s", p.DefaultSmallModelID, p.ID) + return } smallModel = SelectedModel{ Provider: string(p.ID), @@ -369,10 +343,11 @@ func (cfg *Config) defaultModelSelection(knownProviders []provider.Provider) (la } func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) error { - large, small, err := cfg.defaultModelSelection(knownProviders) + defaultLarge, defaultSmall, err := cfg.defaultModelSelection(knownProviders) if err != nil { return fmt.Errorf("failed to select default models: %w", err) } + large, small := defaultLarge, defaultSmall largeModelSelected, largeModelConfigured := cfg.Models[SelectedModelTypeLarge] if largeModelConfigured { @@ -384,17 +359,23 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e } model := cfg.GetModel(large.Provider, large.Model) if model == nil { - return fmt.Errorf("large model %s not found for provider %s", large.Model, large.Provider) - } - if largeModelSelected.MaxTokens > 0 { - large.MaxTokens = largeModelSelected.MaxTokens + large = defaultLarge + // override the model type to large + err := cfg.UpdatePreferredModel(SelectedModelTypeLarge, large) + if err != nil { + return fmt.Errorf("failed to update preferred large model: %w", err) + } } else { - large.MaxTokens = model.DefaultMaxTokens - } - if largeModelSelected.ReasoningEffort != "" { - large.ReasoningEffort = largeModelSelected.ReasoningEffort + if largeModelSelected.MaxTokens > 0 { + large.MaxTokens = largeModelSelected.MaxTokens + } else { + large.MaxTokens = model.DefaultMaxTokens + } + if largeModelSelected.ReasoningEffort != "" { + large.ReasoningEffort = largeModelSelected.ReasoningEffort + } + large.Think = largeModelSelected.Think } - large.Think = largeModelSelected.Think } smallModelSelected, smallModelConfigured := cfg.Models[SelectedModelTypeSmall] if smallModelConfigured { @@ -407,25 +388,21 @@ func (cfg *Config) configureSelectedModels(knownProviders []provider.Provider) e model := cfg.GetModel(small.Provider, small.Model) if model == nil { - return fmt.Errorf("large model %s not found for provider %s", large.Model, large.Provider) - } - if smallModelSelected.MaxTokens > 0 { - small.MaxTokens = smallModelSelected.MaxTokens + small = defaultSmall + // override the model type to small + err := cfg.UpdatePreferredModel(SelectedModelTypeSmall, small) + if err != nil { + return fmt.Errorf("failed to update preferred small model: %w", err) + } } else { - small.MaxTokens = model.DefaultMaxTokens + if smallModelSelected.MaxTokens > 0 { + small.MaxTokens = smallModelSelected.MaxTokens + } else { + small.MaxTokens = model.DefaultMaxTokens + } + small.ReasoningEffort = smallModelSelected.ReasoningEffort + small.Think = smallModelSelected.Think } - small.ReasoningEffort = smallModelSelected.ReasoningEffort - small.Think = smallModelSelected.Think - } - - // validate the selected models - largeModel := cfg.GetModel(large.Provider, large.Model) - if largeModel == nil { - return fmt.Errorf("large model %s not found for provider %s", large.Model, large.Provider) - } - smallModel := cfg.GetModel(small.Provider, small.Model) - if smallModel == nil { - return fmt.Errorf("small model %s not found for provider %s", small.Model, small.Provider) } cfg.Models[SelectedModelTypeLarge] = large cfg.Models[SelectedModelTypeSmall] = small @@ -512,9 +489,9 @@ func globalConfig() string { return filepath.Join(os.Getenv("HOME"), ".config", appName, fmt.Sprintf("%s.json", appName)) } -// globalConfigData returns the path to the main data directory for the application. +// GlobalConfigData returns the path to the main data directory for the application. // this config is used when the app overrides configurations instead of updating the global config. -func globalConfigData() string { +func GlobalConfigData() string { xdgDataHome := os.Getenv("XDG_DATA_HOME") if xdgDataHome != "" { return filepath.Join(xdgDataHome, appName, fmt.Sprintf("%s.json", appName)) @@ -533,3 +510,14 @@ func globalConfigData() string { return filepath.Join(os.Getenv("HOME"), ".local", "share", appName, fmt.Sprintf("%s.json", appName)) } + +func HomeDir() string { + homeDir := os.Getenv("HOME") + if homeDir == "" { + homeDir = os.Getenv("USERPROFILE") // For Windows compatibility + } + if homeDir == "" { + homeDir = os.Getenv("HOMEPATH") // Fallback for some environments + } + return homeDir +} diff --git a/internal/config/load_test.go b/internal/config/load_test.go index f397d704d638d05fb1de7a1f32475afc79f3f0c0..b96ca5e81cd265cbcd1bdf9d456603ad3f22c558 100644 --- a/internal/config/load_test.go +++ b/internal/config/load_test.go @@ -484,7 +484,7 @@ func TestConfig_configureProvidersWithDisabledProvider(t *testing.T) { } func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) { - t.Run("custom provider with missing API key is removed", func(t *testing.T) { + t.Run("custom provider with missing API key is allowed, but not known providers", func(t *testing.T) { cfg := &Config{ Providers: map[string]ProviderConfig{ "custom": { @@ -493,6 +493,9 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) { ID: "test-model", }}, }, + "openai": { + APIKey: "$MISSING", + }, }, } cfg.setDefaults("/tmp") @@ -502,9 +505,9 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) { err := cfg.configureProviders(env, resolver, []provider.Provider{}) assert.NoError(t, err) - assert.Len(t, cfg.Providers, 0) + assert.Len(t, cfg.Providers, 1) _, exists := cfg.Providers["custom"] - assert.False(t, exists) + assert.True(t, exists) }) t.Run("custom provider with missing BaseURL is removed", func(t *testing.T) { diff --git a/internal/config/resolve.go b/internal/config/resolve.go index 71eee9b0ea62b9c436bc4f8ce204ffa1583a840c..3c97a6456cf7fe5968311746d62b2772b21d6aaa 100644 --- a/internal/config/resolve.go +++ b/internal/config/resolve.go @@ -44,7 +44,7 @@ func (r *shellVariableResolver) ResolveValue(value string) (string, error) { if strings.HasPrefix(value, "$(") && strings.HasSuffix(value, ")") { command := strings.TrimSuffix(strings.TrimPrefix(value, "$("), ")") - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() stdout, _, err := r.shell.Exec(ctx, command) @@ -54,8 +54,8 @@ func (r *shellVariableResolver) ResolveValue(value string) (string, error) { return strings.TrimSpace(stdout), nil } - if strings.HasPrefix(value, "$") { - varName := strings.TrimPrefix(value, "$") + if after, ok := strings.CutPrefix(value, "$"); ok { + varName := after value = r.env.Get(varName) if value == "" { return "", fmt.Errorf("environment variable %q not set", varName) diff --git a/internal/format/format.go b/internal/format/format.go deleted file mode 100644 index f21da240868c541bc1fb0a29626cdc2305d103d1..0000000000000000000000000000000000000000 --- a/internal/format/format.go +++ /dev/null @@ -1,99 +0,0 @@ -package format - -import ( - "encoding/json" - "fmt" - "strings" -) - -// OutputFormat represents the output format type for non-interactive mode -type OutputFormat string - -const ( - // Text format outputs the AI response as plain text. - Text OutputFormat = "text" - - // JSON format outputs the AI response wrapped in a JSON object. - JSON OutputFormat = "json" -) - -// String returns the string representation of the OutputFormat -func (f OutputFormat) String() string { - return string(f) -} - -// SupportedFormats is a list of all supported output formats as strings -var SupportedFormats = []string{ - string(Text), - string(JSON), -} - -// Parse converts a string to an OutputFormat -func Parse(s string) (OutputFormat, error) { - s = strings.ToLower(strings.TrimSpace(s)) - - switch s { - case string(Text): - return Text, nil - case string(JSON): - return JSON, nil - default: - return "", fmt.Errorf("invalid format: %s", s) - } -} - -// IsValid checks if the provided format string is supported -func IsValid(s string) bool { - _, err := Parse(s) - return err == nil -} - -// GetHelpText returns a formatted string describing all supported formats -func GetHelpText() string { - return fmt.Sprintf(`Supported output formats: -- %s: Plain text output (default) -- %s: Output wrapped in a JSON object`, - Text, JSON) -} - -// FormatOutput formats the AI response according to the specified format -func FormatOutput(content string, formatStr string) string { - format, err := Parse(formatStr) - if err != nil { - // Default to text format on error - return content - } - - switch format { - case JSON: - return formatAsJSON(content) - case Text: - fallthrough - default: - return content - } -} - -// formatAsJSON wraps the content in a simple JSON object -func formatAsJSON(content string) string { - // Use the JSON package to properly escape the content - response := struct { - Response string `json:"response"` - }{ - Response: content, - } - - jsonBytes, err := json.MarshalIndent(response, "", " ") - if err != nil { - // In case of an error, return a manually formatted JSON - jsonEscaped := strings.ReplaceAll(content, "\\", "\\\\") - jsonEscaped = strings.ReplaceAll(jsonEscaped, "\"", "\\\"") - jsonEscaped = strings.ReplaceAll(jsonEscaped, "\n", "\\n") - jsonEscaped = strings.ReplaceAll(jsonEscaped, "\r", "\\r") - jsonEscaped = strings.ReplaceAll(jsonEscaped, "\t", "\\t") - - return fmt.Sprintf("{\n \"response\": \"%s\"\n}", jsonEscaped) - } - - return string(jsonBytes) -} diff --git a/internal/format/spinner.go b/internal/format/spinner.go index 739fac1b27c99b9c4c4da030943500eda79f957c..da64fb93ce262e04a0b5fb9da8c4aea8403d10d8 100644 --- a/internal/format/spinner.go +++ b/internal/format/spinner.go @@ -2,81 +2,69 @@ package format import ( "context" + "errors" "fmt" "os" - "github.com/charmbracelet/bubbles/v2/spinner" tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/crush/internal/tui/components/anim" + "github.com/charmbracelet/crush/internal/tui/styles" + "github.com/charmbracelet/x/ansi" ) // Spinner wraps the bubbles spinner for non-interactive mode type Spinner struct { - model spinner.Model - done chan struct{} - prog *tea.Program - ctx context.Context - cancel context.CancelFunc + done chan struct{} + prog *tea.Program } -// spinnerModel is the tea.Model for the spinner -type spinnerModel struct { - spinner spinner.Model - message string - quitting bool +type model struct { + cancel context.CancelFunc + anim anim.Anim } -func (m spinnerModel) Init() tea.Cmd { - return m.spinner.Tick -} +func (m model) Init() tea.Cmd { return m.anim.Init() } +func (m model) View() string { return m.anim.View() } -func (m spinnerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +// Update implements tea.Model. +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyPressMsg: - m.quitting = true - return m, tea.Quit - case spinner.TickMsg: - var cmd tea.Cmd - m.spinner, cmd = m.spinner.Update(msg) - return m, cmd - case quitMsg: - m.quitting = true - return m, tea.Quit - default: - return m, nil - } -} - -func (m spinnerModel) View() string { - if m.quitting { - return "" + switch msg.String() { + case "ctrl+c", "esc": + m.cancel() + return m, tea.Quit + } } - return fmt.Sprintf("%s %s", m.spinner.View(), m.message) + mm, cmd := m.anim.Update(msg) + m.anim = mm.(anim.Anim) + return m, cmd } -// quitMsg is sent when we want to quit the spinner -type quitMsg struct{} - // NewSpinner creates a new spinner with the given message -func NewSpinner(message string) *Spinner { - s := spinner.New() - s.Spinner = spinner.Dot - s.Style = s.Style.Foreground(s.Style.GetForeground()) - - ctx, cancel := context.WithCancel(context.Background()) - - model := spinnerModel{ - spinner: s, - message: message, +func NewSpinner(ctx context.Context, cancel context.CancelFunc, message string) *Spinner { + t := styles.CurrentTheme() + model := model{ + anim: anim.New(anim.Settings{ + Size: 10, + Label: message, + LabelColor: t.FgBase, + GradColorA: t.Primary, + GradColorB: t.Secondary, + CycleColors: true, + }), + cancel: cancel, } - prog := tea.NewProgram(model, tea.WithOutput(os.Stderr), tea.WithoutCatchPanics()) + prog := tea.NewProgram( + model, + tea.WithOutput(os.Stderr), + tea.WithContext(ctx), + ) return &Spinner{ - model: s, - done: make(chan struct{}), - prog: prog, - ctx: ctx, - cancel: cancel, + prog: prog, + done: make(chan struct{}, 1), } } @@ -84,12 +72,10 @@ func NewSpinner(message string) *Spinner { func (s *Spinner) Start() { go func() { defer close(s.done) - go func() { - <-s.ctx.Done() - s.prog.Send(quitMsg{}) - }() _, err := s.prog.Run() - if err != nil { + // ensures line is cleared + fmt.Fprint(os.Stderr, ansi.EraseEntireLine) + if err != nil && !errors.Is(err, context.Canceled) && !errors.Is(err, tea.ErrInterrupted) { fmt.Fprintf(os.Stderr, "Error running spinner: %v\n", err) } }() @@ -97,6 +83,6 @@ func (s *Spinner) Start() { // Stop ends the spinner animation func (s *Spinner) Stop() { - s.cancel() + s.prog.Quit() <-s.done } diff --git a/internal/fsext/fileutil.go b/internal/fsext/fileutil.go index c3678041de4239cf66247ebbd9cb084cb8eb6b8a..462dcc6761f261a5be02658317884eb64fb07ebc 100644 --- a/internal/fsext/fileutil.go +++ b/internal/fsext/fileutil.go @@ -17,23 +17,14 @@ import ( ignore "github.com/sabhiram/go-gitignore" ) -var ( - rgPath string - fzfPath string -) +var rgPath string func init() { var err error rgPath, err = exec.LookPath("rg") if err != nil { if log.Initialized() { - slog.Warn("Ripgrep (rg) not found in $PATH. Some features might be limited or slower.") - } - } - fzfPath, err = exec.LookPath("fzf") - if err != nil { - if log.Initialized() { - slog.Warn("FZF not found in $PATH. Some features might be limited or slower.") + slog.Warn("Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower.") } } } diff --git a/internal/fur/client/client.go b/internal/fur/client/client.go index 5f0ddeaeee708d4b5475403ce1874591f7e9bb2c..d007c9aee18f77c8b03fe804726b4196e474d0b4 100644 --- a/internal/fur/client/client.go +++ b/internal/fur/client/client.go @@ -10,7 +10,7 @@ import ( "github.com/charmbracelet/crush/internal/fur/provider" ) -const defaultURL = "https://fur.charmcli.dev" +const defaultURL = "https://fur.charm.sh" // Client represents a client for the fur service. type Client struct { diff --git a/internal/llm/agent/agent.go b/internal/llm/agent/agent.go index 6d9a825f600e79d3161c6b653669abe8773db116..fbb5b4fd8c6390ff0dfad0e072af35342355ba41 100644 --- a/internal/llm/agent/agent.go +++ b/internal/llm/agent/agent.go @@ -26,7 +26,7 @@ import ( // Common errors var ( - ErrRequestCancelled = errors.New("request cancelled by user") + ErrRequestCancelled = errors.New("request canceled by user") ErrSessionBusy = errors.New("session is currently processing another request") ) @@ -149,7 +149,7 @@ func NewAgent( } opts := []provider.ProviderClientOption{ provider.WithModel(agentCfg.Model), - provider.WithSystemMessage(prompt.GetPrompt(promptID, providerCfg.ID)), + provider.WithSystemMessage(prompt.GetPrompt(promptID, providerCfg.ID, config.Get().Options.ContextPaths...)), } agentProvider, err := provider.NewProvider(*providerCfg, opts...) if err != nil { @@ -827,7 +827,7 @@ func (a *agent) UpdateModel() error { opts := []provider.ProviderClientOption{ provider.WithModel(a.agentCfg.Model), - provider.WithSystemMessage(prompt.GetPrompt(promptID, currentProviderCfg.ID)), + provider.WithSystemMessage(prompt.GetPrompt(promptID, currentProviderCfg.ID, cfg.Options.ContextPaths...)), } newProvider, err := provider.NewProvider(*currentProviderCfg, opts...) diff --git a/internal/llm/prompt/initialize.go b/internal/llm/prompt/initialize.go new file mode 100644 index 0000000000000000000000000000000000000000..62a0f57c6122195490e2f989874cf5660f4a0da2 --- /dev/null +++ b/internal/llm/prompt/initialize.go @@ -0,0 +1,14 @@ +package prompt + +func Initialize() string { + return `Please analyze this codebase and create a **CRUSH.md** file containing: + +- Build/lint/test commands - especially for running a single test +- Code style guidelines including imports, formatting, types, naming conventions, error handling, etc. + +The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20-30 lines long. +If there's already a **CRUSH.md**, improve it. + +If there are Cursor rules` + " (in `.cursor/rules/` or `.cursorrules`) or Copilot rules (in `.github/copilot-instructions.md`), make sure to include them.\n" + + "Add the `.crush` directory to the `.gitignore` file if it's not already there." +} diff --git a/internal/llm/prompt/prompt.go b/internal/llm/prompt/prompt.go index 835279b4f4c0e08e46aaad271b7cb7f2a59b467f..4a2661bb9f663d9f93cf0371ac5d71dd513392c7 100644 --- a/internal/llm/prompt/prompt.go +++ b/internal/llm/prompt/prompt.go @@ -5,6 +5,9 @@ import ( "path/filepath" "strings" "sync" + + "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/env" ) type PromptID string @@ -21,7 +24,7 @@ func GetPrompt(promptID PromptID, provider string, contextPaths ...string) strin basePrompt := "" switch promptID { case PromptCoder: - basePrompt = CoderPrompt(provider) + basePrompt = CoderPrompt(provider, contextPaths...) case PromptTitle: basePrompt = TitlePrompt() case PromptTask: @@ -38,6 +41,32 @@ func getContextFromPaths(workingDir string, contextPaths []string) string { return processContextPaths(workingDir, contextPaths) } +// expandPath expands ~ and environment variables in file paths +func expandPath(path string) string { + // Handle tilde expansion + if strings.HasPrefix(path, "~/") { + homeDir, err := os.UserHomeDir() + if err == nil { + path = filepath.Join(homeDir, path[2:]) + } + } else if path == "~" { + homeDir, err := os.UserHomeDir() + if err == nil { + path = homeDir + } + } + + // Handle environment variable expansion using the same pattern as config + if strings.HasPrefix(path, "$") { + resolver := config.NewEnvironmentVariableResolver(env.New()) + if expanded, err := resolver.ResolveValue(path); err == nil { + path = expanded + } + } + + return path +} + func processContextPaths(workDir string, paths []string) string { var ( wg sync.WaitGroup @@ -53,8 +82,23 @@ func processContextPaths(workDir string, paths []string) string { go func(p string) { defer wg.Done() - if strings.HasSuffix(p, "/") { - filepath.WalkDir(filepath.Join(workDir, p), func(path string, d os.DirEntry, err error) error { + // Expand ~ and environment variables before processing + p = expandPath(p) + + // Use absolute path if provided, otherwise join with workDir + fullPath := p + if !filepath.IsAbs(p) { + fullPath = filepath.Join(workDir, p) + } + + // Check if the path is a directory using os.Stat + info, err := os.Stat(fullPath) + if err != nil { + return // Skip if path doesn't exist or can't be accessed + } + + if info.IsDir() { + filepath.WalkDir(fullPath, func(path string, d os.DirEntry, err error) error { if err != nil { return err } @@ -78,8 +122,7 @@ func processContextPaths(workDir string, paths []string) string { return nil }) } else { - fullPath := filepath.Join(workDir, p) - + // It's a file, process it directly // Check if we've already processed this file (case-insensitive) lowerPath := strings.ToLower(fullPath) diff --git a/internal/llm/prompt/prompt_test.go b/internal/llm/prompt/prompt_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ce7fa0fb35cfdf021b886a96a828202001588a7f --- /dev/null +++ b/internal/llm/prompt/prompt_test.go @@ -0,0 +1,113 @@ +package prompt + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestExpandPath(t *testing.T) { + tests := []struct { + name string + input string + expected func() string + }{ + { + name: "regular path unchanged", + input: "/absolute/path", + expected: func() string { + return "/absolute/path" + }, + }, + { + name: "tilde expansion", + input: "~/documents", + expected: func() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, "documents") + }, + }, + { + name: "tilde only", + input: "~", + expected: func() string { + home, _ := os.UserHomeDir() + return home + }, + }, + { + name: "environment variable expansion", + input: "$HOME", + expected: func() string { + return os.Getenv("HOME") + }, + }, + { + name: "relative path unchanged", + input: "relative/path", + expected: func() string { + return "relative/path" + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := expandPath(tt.input) + expected := tt.expected() + + // Skip test if environment variable is not set + if strings.HasPrefix(tt.input, "$") && expected == "" { + t.Skip("Environment variable not set") + } + + if result != expected { + t.Errorf("expandPath(%q) = %q, want %q", tt.input, result, expected) + } + }) + } +} + +func TestProcessContextPaths(t *testing.T) { + // Create a temporary directory and file for testing + tmpDir := t.TempDir() + testFile := filepath.Join(tmpDir, "test.txt") + testContent := "test content" + + err := os.WriteFile(testFile, []byte(testContent), 0o644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + // Test with absolute path to file + result := processContextPaths("", []string{testFile}) + expected := "# From:" + testFile + "\n" + testContent + + if result != expected { + t.Errorf("processContextPaths with absolute path failed.\nGot: %q\nWant: %q", result, expected) + } + + // Test with directory path (should process all files in directory) + result = processContextPaths("", []string{tmpDir}) + if !strings.Contains(result, testContent) { + t.Errorf("processContextPaths with directory path failed to include file content") + } + + // Test with tilde expansion (if we can create a file in home directory) + tmpDir = t.TempDir() + t.Setenv("HOME", tmpDir) + homeTestFile := filepath.Join(tmpDir, "crush_test_file.txt") + err = os.WriteFile(homeTestFile, []byte(testContent), 0o644) + if err == nil { + defer os.Remove(homeTestFile) // Clean up + + tildeFile := "~/crush_test_file.txt" + result = processContextPaths("", []string{tildeFile}) + expected = "# From:" + homeTestFile + "\n" + testContent + + if result != expected { + t.Errorf("processContextPaths with tilde expansion failed.\nGot: %q\nWant: %q", result, expected) + } + } +} diff --git a/internal/llm/provider/openai.go b/internal/llm/provider/openai.go index c51762a868a1f8e2a14b20788ee28ae891cbb9d8..0093dd24ad77d6962780abdce84f64ba733a2df1 100644 --- a/internal/llm/provider/openai.go +++ b/internal/llm/provider/openai.go @@ -38,7 +38,10 @@ func createOpenAIClient(opts providerClientOptions) openai.Client { openaiClientOptions = append(openaiClientOptions, option.WithAPIKey(opts.apiKey)) } if opts.baseURL != "" { - openaiClientOptions = append(openaiClientOptions, option.WithBaseURL(opts.baseURL)) + resolvedBaseURL, err := config.Get().Resolve(opts.baseURL) + if err == nil { + openaiClientOptions = append(openaiClientOptions, option.WithBaseURL(resolvedBaseURL)) + } } if opts.extraHeaders != nil { @@ -269,10 +272,13 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t currentContent := "" toolCalls := make([]message.ToolCall, 0) + var currentToolCallID string + var currentToolCall openai.ChatCompletionMessageToolCall + var msgToolCalls []openai.ChatCompletionMessageToolCall for openaiStream.Next() { chunk := openaiStream.Current() acc.AddChunk(chunk) - + // This fixes multiple tool calls for some providers for _, choice := range chunk.Choices { if choice.Delta.Content != "" { eventChan <- ProviderEvent{ @@ -280,6 +286,45 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t Content: choice.Delta.Content, } currentContent += choice.Delta.Content + } else if len(choice.Delta.ToolCalls) > 0 { + toolCall := choice.Delta.ToolCalls[0] + // Detect tool use start + if currentToolCallID == "" { + if toolCall.ID != "" { + currentToolCallID = toolCall.ID + currentToolCall = openai.ChatCompletionMessageToolCall{ + ID: toolCall.ID, + Type: "function", + Function: openai.ChatCompletionMessageToolCallFunction{ + Name: toolCall.Function.Name, + Arguments: toolCall.Function.Arguments, + }, + } + } + } else { + // Delta tool use + if toolCall.ID == "" { + currentToolCall.Function.Arguments += toolCall.Function.Arguments + } else { + // Detect new tool use + if toolCall.ID != currentToolCallID { + msgToolCalls = append(msgToolCalls, currentToolCall) + currentToolCallID = toolCall.ID + currentToolCall = openai.ChatCompletionMessageToolCall{ + ID: toolCall.ID, + Type: "function", + Function: openai.ChatCompletionMessageToolCallFunction{ + Name: toolCall.Function.Name, + Arguments: toolCall.Function.Arguments, + }, + } + } + } + } + } + if choice.FinishReason == "tool_calls" { + msgToolCalls = append(msgToolCalls, currentToolCall) + acc.Choices[0].Message.ToolCalls = msgToolCalls } } } @@ -290,6 +335,7 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t jsonData, _ := json.Marshal(acc.ChatCompletion) slog.Debug("Response", "messages", string(jsonData)) } + resultFinishReason := acc.ChatCompletion.Choices[0].FinishReason if resultFinishReason == "" { // If the finish reason is empty, we assume it was a successful completion diff --git a/internal/llm/tools/bash.go b/internal/llm/tools/bash.go index 0a10568a39315f6c4077385b8ca83f6b3e52691c..6d7a9a32b3829da02021be80e6e41e28888efd83 100644 --- a/internal/llm/tools/bash.go +++ b/internal/llm/tools/bash.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "runtime" "strings" "time" @@ -41,9 +42,74 @@ const ( ) var bannedCommands = []string{ - "alias", "curl", "curlie", "wget", "axel", "aria2c", - "nc", "telnet", "lynx", "w3m", "links", "httpie", "xh", - "http-prompt", "chrome", "firefox", "safari", + // Network/Download tools + "alias", + "aria2c", + "axel", + "chrome", + "curl", + "curlie", + "firefox", + "http-prompt", + "httpie", + "links", + "lynx", + "nc", + "safari", + "telnet", + "w3m", + "wget", + "xh", + + // System administration + "doas", + "su", + "sudo", + + // Package managers + "apk", + "apt", + "apt-cache", + "apt-get", + "dnf", + "dpkg", + "emerge", + "home-manager", + "makepkg", + "opkg", + "pacman", + "paru", + "pkg", + "pkg_add", + "pkg_delete", + "portage", + "rpm", + "yay", + "yum", + "zypper", + + // System modification + "at", + "batch", + "chkconfig", + "crontab", + "fdisk", + "mkfs", + "mount", + "parted", + "service", + "systemctl", + "umount", + + // Network configuration + "firewall-cmd", + "ifconfig", + "ip", + "iptables", + "netstat", + "pfctl", + "route", + "ufw", } // getSafeReadOnlyCommands returns platform-appropriate safe commands @@ -244,7 +310,42 @@ Important: - Never update git config`, bannedCommandsStr, MaxOutputLength) } +func blockFuncs() []shell.BlockFunc { + return []shell.BlockFunc{ + shell.CommandsBlocker(bannedCommands), + shell.ArgumentsBlocker([][]string{ + // System package managers + {"apk", "add"}, + {"apt", "install"}, + {"apt-get", "install"}, + {"dnf", "install"}, + {"emerge"}, + {"pacman", "-S"}, + {"pkg", "install"}, + {"yum", "install"}, + {"zypper", "install"}, + + // Language-specific package managers + {"brew", "install"}, + {"cargo", "install"}, + {"gem", "install"}, + {"go", "install"}, + {"npm", "install", "-g"}, + {"npm", "install", "--global"}, + {"pip", "install", "--user"}, + {"pip3", "install", "--user"}, + {"pnpm", "add", "-g"}, + {"pnpm", "add", "--global"}, + {"yarn", "global", "add"}, + }), + } +} + func NewBashTool(permission permission.Service, workingDir string) BaseTool { + // Set up command blocking on the persistent shell + persistentShell := shell.GetPersistentShell(workingDir) + persistentShell.SetBlockFuncs(blockFuncs()) + return &bashTool{ permissions: permission, workingDir: workingDir, @@ -289,13 +390,6 @@ func (b *bashTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) return NewTextErrorResponse("missing command"), nil } - baseCmd := strings.Fields(params.Command)[0] - for _, banned := range bannedCommands { - if strings.EqualFold(baseCmd, banned) { - return NewTextErrorResponse(fmt.Sprintf("command '%s' is not allowed", baseCmd)), nil - } - } - isSafeReadOnly := false cmdLower := strings.ToLower(params.Command) @@ -349,7 +443,20 @@ func (b *bashTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) stdout = truncateOutput(stdout) stderr = truncateOutput(stderr) + slog.Info("Bash command executed", + "command", params.Command, + "stdout", stdout, + "stderr", stderr, + "exit_code", exitCode, + "interrupted", interrupted, + "err", err, + ) + errorMessage := stderr + if errorMessage == "" && err != nil { + errorMessage = err.Error() + } + if interrupted { if errorMessage != "" { errorMessage += "\n" diff --git a/internal/lsp/transport.go b/internal/lsp/transport.go index 431a099fa1cda5e5035de7ce6c10ef3761e397ea..9a3dfd261fb68b1afdd17f614daab761f9294327 100644 --- a/internal/lsp/transport.go +++ b/internal/lsp/transport.go @@ -222,29 +222,32 @@ func (c *Client) Call(ctx context.Context, method string, params any, result any } // Wait for response - resp := <-ch - - if cfg.Options.DebugLSP { - slog.Debug("Received response", "id", id) - } - - if resp.Error != nil { - return fmt.Errorf("request failed: %s (code: %d)", resp.Error.Message, resp.Error.Code) - } + select { + case <-ctx.Done(): + return ctx.Err() + case resp := <-ch: + if cfg.Options.DebugLSP { + slog.Debug("Received response", "id", id) + } - if result != nil { - // If result is a json.RawMessage, just copy the raw bytes - if rawMsg, ok := result.(*json.RawMessage); ok { - *rawMsg = resp.Result - return nil + if resp.Error != nil { + return fmt.Errorf("request failed: %s (code: %d)", resp.Error.Message, resp.Error.Code) } - // Otherwise unmarshal into the provided type - if err := json.Unmarshal(resp.Result, result); err != nil { - return fmt.Errorf("failed to unmarshal result: %w", err) + + if result != nil { + // If result is a json.RawMessage, just copy the raw bytes + if rawMsg, ok := result.(*json.RawMessage); ok { + *rawMsg = resp.Result + return nil + } + // Otherwise unmarshal into the provided type + if err := json.Unmarshal(resp.Result, result); err != nil { + return fmt.Errorf("failed to unmarshal result: %w", err) + } } - } - return nil + return nil + } } // Notify sends a notification (a request without an ID that doesn't expect a response) diff --git a/internal/lsp/watcher/watcher.go b/internal/lsp/watcher/watcher.go index a6d27f057e06ea7026a6eed0308979991a44fb9d..5bd016eebe413a17acca29ef628612825d40b923 100644 --- a/internal/lsp/watcher/watcher.go +++ b/internal/lsp/watcher/watcher.go @@ -21,6 +21,7 @@ import ( // WorkspaceWatcher manages LSP file watching type WorkspaceWatcher struct { client *lsp.Client + name string workspacePath string debounceTime time.Duration @@ -33,8 +34,9 @@ type WorkspaceWatcher struct { } // NewWorkspaceWatcher creates a new workspace watcher -func NewWorkspaceWatcher(client *lsp.Client) *WorkspaceWatcher { +func NewWorkspaceWatcher(name string, client *lsp.Client) *WorkspaceWatcher { return &WorkspaceWatcher{ + name: name, client: client, debounceTime: 300 * time.Millisecond, debounceMap: make(map[string]*time.Timer), @@ -95,7 +97,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc } // Determine server type for specialized handling - serverName := getServerNameFromContext(ctx) + serverName := w.name slog.Debug("Server type detected", "serverName", serverName) // Check if this server has sent file watchers @@ -325,17 +327,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str cfg := config.Get() w.workspacePath = workspacePath - // Store the watcher in the context for later use - ctx = context.WithValue(ctx, "workspaceWatcher", w) - - // If the server name isn't already in the context, try to detect it - if _, ok := ctx.Value("serverName").(string); !ok { - serverName := getServerNameFromContext(ctx) - ctx = context.WithValue(ctx, "serverName", serverName) - } - - serverName := getServerNameFromContext(ctx) - slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName) + slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", w.name) // Register handler for file watcher registrations from the server lsp.RegisterFileWatchHandler(func(id string, watchers []protocol.FileSystemWatcher) { @@ -697,40 +689,6 @@ func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, chan return w.client.DidChangeWatchedFiles(ctx, params) } -// getServerNameFromContext extracts the server name from the context -// This is a best-effort function that tries to identify which LSP server we're dealing with -func getServerNameFromContext(ctx context.Context) string { - // First check if the server name is directly stored in the context - if serverName, ok := ctx.Value("serverName").(string); ok && serverName != "" { - return strings.ToLower(serverName) - } - - // Otherwise, try to extract server name from the client command path - if w, ok := ctx.Value("workspaceWatcher").(*WorkspaceWatcher); ok && w != nil && w.client != nil && w.client.Cmd != nil { - path := strings.ToLower(w.client.Cmd.Path) - - // Extract server name from path - if strings.Contains(path, "typescript") || strings.Contains(path, "tsserver") || strings.Contains(path, "vtsls") { - return "typescript" - } else if strings.Contains(path, "gopls") { - return "gopls" - } else if strings.Contains(path, "rust-analyzer") { - return "rust-analyzer" - } else if strings.Contains(path, "pyright") || strings.Contains(path, "pylsp") || strings.Contains(path, "python") { - return "python" - } else if strings.Contains(path, "clangd") { - return "clangd" - } else if strings.Contains(path, "jdtls") || strings.Contains(path, "java") { - return "java" - } - - // Return the base name as fallback - return filepath.Base(path) - } - - return "unknown" -} - // shouldPreloadFiles determines if we should preload files for a specific language server // Some servers work better with preloaded files, others don't need it func shouldPreloadFiles(serverName string) bool { @@ -884,64 +842,63 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) { } // Check if this path should be watched according to server registrations - if watched, _ := w.isPathWatched(path); watched { - // Get server name for specialized handling - serverName := getServerNameFromContext(ctx) + if watched, _ := w.isPathWatched(path); !watched { + return + } - // Check if the file is a high-priority file that should be opened immediately - // This helps with project initialization for certain language servers - if isHighPriorityFile(path, serverName) { - if cfg.Options.DebugLSP { - slog.Debug("Opening high-priority file", "path", path, "serverName", serverName) - } - if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP { - slog.Error("Error opening high-priority file", "path", path, "error", err) - } - return - } + serverName := w.name - // For non-high-priority files, we'll use different strategies based on server type - if shouldPreloadFiles(serverName) { - // For servers that benefit from preloading, open files but with limits + // Get server name for specialized handling + // Check if the file is a high-priority file that should be opened immediately + // This helps with project initialization for certain language servers + if isHighPriorityFile(path, serverName) { + if cfg.Options.DebugLSP { + slog.Debug("Opening high-priority file", "path", path, "serverName", serverName) + } + if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP { + slog.Error("Error opening high-priority file", "path", path, "error", err) + } + return + } - // Check file size - for preloading we're more conservative - if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files - if cfg.Options.DebugLSP { - slog.Debug("Skipping large file for preloading", "path", path, "size", info.Size()) - } - return - } + // For non-high-priority files, we'll use different strategies based on server type + if !shouldPreloadFiles(serverName) { + return + } + // For servers that benefit from preloading, open files but with limits - // Check file extension for common source files - ext := strings.ToLower(filepath.Ext(path)) + // Check file size - for preloading we're more conservative + if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files + if cfg.Options.DebugLSP { + slog.Debug("Skipping large file for preloading", "path", path, "size", info.Size()) + } + return + } - // Only preload source files for the specific language - shouldOpen := false + // Check file extension for common source files + ext := strings.ToLower(filepath.Ext(path)) - switch serverName { - case "typescript", "typescript-language-server", "tsserver", "vtsls": - shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx" - case "gopls": - shouldOpen = ext == ".go" - case "rust-analyzer": - shouldOpen = ext == ".rs" - case "python", "pyright", "pylsp": - shouldOpen = ext == ".py" - case "clangd": - shouldOpen = ext == ".c" || ext == ".cpp" || ext == ".h" || ext == ".hpp" - case "java", "jdtls": - shouldOpen = ext == ".java" - default: - // For unknown servers, be conservative - shouldOpen = false - } + // Only preload source files for the specific language + var shouldOpen bool + switch serverName { + case "typescript", "typescript-language-server", "tsserver", "vtsls": + shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx" + case "gopls": + shouldOpen = ext == ".go" + case "rust-analyzer": + shouldOpen = ext == ".rs" + case "python", "pyright", "pylsp": + shouldOpen = ext == ".py" + case "clangd": + shouldOpen = ext == ".c" || ext == ".cpp" || ext == ".h" || ext == ".hpp" + case "java", "jdtls": + shouldOpen = ext == ".java" + } - if shouldOpen { - // Don't need to check if it's already open - the client.OpenFile handles that - if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP { - slog.Error("Error opening file", "path", path, "error", err) - } - } + if shouldOpen { + // Don't need to check if it's already open - the client.OpenFile handles that + if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP { + slog.Error("Error opening file", "path", path, "error", err) } } } diff --git a/internal/shell/command_block_test.go b/internal/shell/command_block_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fd7c46bcd98e54f44abbe982e834f3cbb04cbfa4 --- /dev/null +++ b/internal/shell/command_block_test.go @@ -0,0 +1,123 @@ +package shell + +import ( + "context" + "os" + "strings" + "testing" +) + +func TestCommandBlocking(t *testing.T) { + tests := []struct { + name string + blockFuncs []BlockFunc + command string + shouldBlock bool + }{ + { + name: "block simple command", + blockFuncs: []BlockFunc{ + func(args []string) bool { + return len(args) > 0 && args[0] == "curl" + }, + }, + command: "curl https://example.com", + shouldBlock: true, + }, + { + name: "allow non-blocked command", + blockFuncs: []BlockFunc{ + func(args []string) bool { + return len(args) > 0 && args[0] == "curl" + }, + }, + command: "echo hello", + shouldBlock: false, + }, + { + name: "block subcommand", + blockFuncs: []BlockFunc{ + func(args []string) bool { + return len(args) >= 2 && args[0] == "brew" && args[1] == "install" + }, + }, + command: "brew install wget", + shouldBlock: true, + }, + { + name: "allow different subcommand", + blockFuncs: []BlockFunc{ + func(args []string) bool { + return len(args) >= 2 && args[0] == "brew" && args[1] == "install" + }, + }, + command: "brew list", + shouldBlock: false, + }, + { + name: "block npm global install with -g", + blockFuncs: []BlockFunc{ + ArgumentsBlocker([][]string{ + {"npm", "install", "-g"}, + {"npm", "install", "--global"}, + }), + }, + command: "npm install -g typescript", + shouldBlock: true, + }, + { + name: "block npm global install with --global", + blockFuncs: []BlockFunc{ + ArgumentsBlocker([][]string{ + {"npm", "install", "-g"}, + {"npm", "install", "--global"}, + }), + }, + command: "npm install --global typescript", + shouldBlock: true, + }, + { + name: "allow npm local install", + blockFuncs: []BlockFunc{ + ArgumentsBlocker([][]string{ + {"npm", "install", "-g"}, + {"npm", "install", "--global"}, + }), + }, + command: "npm install typescript", + shouldBlock: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a temporary directory for each test + tmpDir, err := os.MkdirTemp("", "shell-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + shell := NewShell(&Options{ + WorkingDir: tmpDir, + BlockFuncs: tt.blockFuncs, + }) + + _, _, err = shell.Exec(context.Background(), tt.command) + + if tt.shouldBlock { + if err == nil { + t.Errorf("Expected command to be blocked, but it was allowed") + } else if !strings.Contains(err.Error(), "not allowed for security reasons") { + t.Errorf("Expected security error, got: %v", err) + } + } else { + // For non-blocked commands, we might get other errors (like command not found) + // but we shouldn't get the security error + if err != nil && strings.Contains(err.Error(), "not allowed for security reasons") { + t.Errorf("Command was unexpectedly blocked: %v", err) + } + } + }) + } +} diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 0467c9072c5111e4b4ea9a5439519e4edf76af46..b655c5dbecf5b69c7ad102c53108733515138771 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -44,12 +44,16 @@ type noopLogger struct{} func (noopLogger) InfoPersist(msg string, keysAndValues ...interface{}) {} +// BlockFunc is a function that determines if a command should be blocked +type BlockFunc func(args []string) bool + // Shell provides cross-platform shell execution with optional state persistence type Shell struct { - env []string - cwd string - mu sync.Mutex - logger Logger + env []string + cwd string + mu sync.Mutex + logger Logger + blockFuncs []BlockFunc } // Options for creating a new shell @@ -57,6 +61,7 @@ type Options struct { WorkingDir string Env []string Logger Logger + BlockFuncs []BlockFunc } // NewShell creates a new shell instance with the given options @@ -81,9 +86,10 @@ func NewShell(opts *Options) *Shell { } return &Shell{ - cwd: cwd, - env: env, - logger: logger, + cwd: cwd, + env: env, + logger: logger, + blockFuncs: opts.BlockFuncs, } } @@ -152,6 +158,13 @@ func (s *Shell) SetEnv(key, value string) { s.env = append(s.env, keyPrefix+value) } +// SetBlockFuncs sets the command block functions for the shell +func (s *Shell) SetBlockFuncs(blockFuncs []BlockFunc) { + s.mu.Lock() + defer s.mu.Unlock() + s.blockFuncs = blockFuncs +} + // Windows-specific commands that should use native shell var windowsNativeCommands = map[string]bool{ "dir": true, @@ -203,6 +216,60 @@ func (s *Shell) determineShellType(command string) ShellType { return ShellTypePOSIX } +// CommandsBlocker creates a BlockFunc that blocks exact command matches +func CommandsBlocker(bannedCommands []string) BlockFunc { + bannedSet := make(map[string]bool) + for _, cmd := range bannedCommands { + bannedSet[cmd] = true + } + + return func(args []string) bool { + if len(args) == 0 { + return false + } + return bannedSet[args[0]] + } +} + +// ArgumentsBlocker creates a BlockFunc that blocks specific subcommands +func ArgumentsBlocker(blockedSubCommands [][]string) BlockFunc { + return func(args []string) bool { + for _, blocked := range blockedSubCommands { + if len(args) >= len(blocked) { + match := true + for i, part := range blocked { + if args[i] != part { + match = false + break + } + } + if match { + return true + } + } + } + return false + } +} + +func (s *Shell) blockHandler() func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc { + return func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc { + return func(ctx context.Context, args []string) error { + if len(args) == 0 { + return next(ctx, args) + } + + for _, blockFunc := range s.blockFuncs { + if blockFunc(args) { + return fmt.Errorf("command is not allowed for security reasons: %s", strings.Join(args, " ")) + } + } + + return next(ctx, args) + } + } +} + // execWindows executes commands using native Windows shells (cmd.exe or PowerShell) func (s *Shell) execWindows(ctx context.Context, command string, shell string) (string, string, error) { var cmd *exec.Cmd @@ -291,6 +358,7 @@ func (s *Shell) execPOSIX(ctx context.Context, command string) (string, string, interp.Interactive(false), interp.Env(expand.ListEnviron(s.env...)), interp.Dir(s.cwd), + interp.ExecHandlers(s.blockHandler()), ) if err != nil { return "", "", fmt.Errorf("could not run command: %w", err) diff --git a/internal/tui/components/chat/chat.go b/internal/tui/components/chat/chat.go index 058e3612d31f0e0d6be53fe28c4f8720fa49cb5b..0e6a95937476de9f33b1c5c0dd15e0489c645c43 100644 --- a/internal/tui/components/chat/chat.go +++ b/internal/tui/components/chat/chat.go @@ -14,8 +14,8 @@ import ( "github.com/charmbracelet/crush/internal/tui/components/chat/messages" "github.com/charmbracelet/crush/internal/tui/components/core/layout" "github.com/charmbracelet/crush/internal/tui/components/core/list" + "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" - "github.com/charmbracelet/lipgloss/v2" ) type SendMsg struct { @@ -37,6 +37,9 @@ type MessageListCmp interface { util.Model layout.Sizeable layout.Focusable + layout.Help + + SetSession(session.Session) tea.Cmd } // messageListCmp implements MessageListCmp, providing a virtualized list @@ -53,9 +56,9 @@ type messageListCmp struct { defaultListKeyMap list.KeyMap } -// NewMessagesListCmp creates a new message list component with custom keybindings +// New creates a new message list component with custom keybindings // and reverse ordering (newest messages at bottom). -func NewMessagesListCmp(app *app.App) MessageListCmp { +func New(app *app.App) MessageListCmp { defaultListKeyMap := list.DefaultKeyMap() listCmp := list.New( list.WithGapSize(1), @@ -70,7 +73,7 @@ func NewMessagesListCmp(app *app.App) MessageListCmp { } } -// Init initializes the component (no initialization needed). +// Init initializes the component. func (m *messageListCmp) Init() tea.Cmd { return tea.Sequence(m.listCmp.Init(), m.listCmp.Blur()) } @@ -102,16 +105,20 @@ func (m *messageListCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // View renders the message list or an initial screen if empty. func (m *messageListCmp) View() string { - return lipgloss.JoinVertical( - lipgloss.Left, - m.listCmp.View(), - ) + t := styles.CurrentTheme() + return t.S().Base. + Padding(1). + Width(m.width). + Height(m.height). + Render( + m.listCmp.View(), + ) } // handleChildSession handles messages from child sessions (agent tools). func (m *messageListCmp) handleChildSession(event pubsub.Event[message.Message]) tea.Cmd { var cmds []tea.Cmd - if len(event.Payload.ToolCalls()) == 0 { + if len(event.Payload.ToolCalls()) == 0 && len(event.Payload.ToolResults()) == 0 { return nil } items := m.listCmp.Items() @@ -151,6 +158,15 @@ func (m *messageListCmp) handleChildSession(event pubsub.Event[message.Message]) ) } } + for _, tr := range event.Payload.ToolResults() { + for nestedInx, nestedTC := range nestedToolCalls { + if nestedTC.GetToolCall().ID == tr.ToolCallID { + nestedToolCalls[nestedInx].SetToolResult(tr) + break + } + } + } + toolCall.SetNestedToolCalls(nestedToolCalls) m.listCmp.UpdateItem( toolCallInx, @@ -487,8 +503,8 @@ func (m *messageListCmp) GetSize() (int, int) { // SetSize updates the component dimensions and propagates to the list component. func (m *messageListCmp) SetSize(width int, height int) tea.Cmd { m.width = width - m.height = height - 1 - return m.listCmp.SetSize(width, height-1) + m.height = height + return m.listCmp.SetSize(width-2, height-2) // for padding } // Blur implements MessageListCmp. diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 1464512a403d8208aea669dced2811e3efa4bae8..67ba67f5e6c40f16a89f7bc4fe1b6932c9989754 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -18,6 +18,7 @@ import ( "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/completions" + "github.com/charmbracelet/crush/internal/tui/components/core/layout" "github.com/charmbracelet/crush/internal/tui/components/dialogs" "github.com/charmbracelet/crush/internal/tui/components/dialogs/filepicker" "github.com/charmbracelet/crush/internal/tui/components/dialogs/quit" @@ -26,6 +27,18 @@ import ( "github.com/charmbracelet/lipgloss/v2" ) +type Editor interface { + util.Model + layout.Sizeable + layout.Focusable + layout.Help + layout.Positional + + SetSession(session session.Session) tea.Cmd + IsCompletionsOpen() bool + Cursor() *tea.Cursor +} + type FileCompletionItem struct { Path string // The file path } @@ -67,7 +80,11 @@ const ( maxAttachments = 5 ) -func (m *editorCmp) openEditor() tea.Cmd { +type openEditorMsg struct { + Text string +} + +func (m *editorCmp) openEditor(value string) tea.Cmd { editor := os.Getenv("EDITOR") if editor == "" { // Use platform-appropriate default editor @@ -82,7 +99,10 @@ func (m *editorCmp) openEditor() tea.Cmd { if err != nil { return util.ReportError(err) } - tmpfile.Close() + defer tmpfile.Close() //nolint:errcheck + if _, err := tmpfile.WriteString(value); err != nil { + return util.ReportError(err) + } c := exec.Command(editor, tmpfile.Name()) c.Stdin = os.Stdin c.Stdout = os.Stdout @@ -99,11 +119,8 @@ func (m *editorCmp) openEditor() tea.Cmd { return util.ReportWarn("Message is empty") } os.Remove(tmpfile.Name()) - attachments := m.attachments - m.attachments = nil - return chat.SendMsg{ - Text: string(content), - Attachments: attachments, + return openEditorMsg{ + Text: strings.TrimSpace(string(content)), } }) } @@ -145,11 +162,6 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd var cmds []tea.Cmd switch msg := msg.(type) { - case chat.SessionSelectedMsg: - if msg.ID != m.session.ID { - m.session = msg - } - return m, nil case filepicker.FilePickedMsg: if len(m.attachments) >= maxAttachments { return m, util.ReportError(fmt.Errorf("cannot add more than %d images", maxAttachments)) @@ -178,6 +190,9 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.completionsStartIndex = 0 return m, nil } + case openEditorMsg: + m.textarea.SetValue(msg.Text) + m.textarea.MoveToEnd() case tea.KeyPressMsg: switch { // Completions @@ -239,19 +254,21 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.app.CoderAgent.IsSessionBusy(m.session.ID) { return m, util.ReportWarn("Agent is working, please wait...") } - return m, m.openEditor() + return m, m.openEditor(m.textarea.Value()) } if key.Matches(msg, DeleteKeyMaps.Escape) { m.deleteMode = false return m, nil } - // Hanlde Enter key + if key.Matches(msg, m.keyMap.Newline) { + m.textarea.InsertRune('\n') + } + // Handle Enter key if m.textarea.Focused() && key.Matches(msg, m.keyMap.SendMessage) { value := m.textarea.Value() if len(value) > 0 && value[len(value)-1] == '\\' { // If the last character is a backslash, remove it and add a newline - m.textarea.SetValue(value[:len(value)-1] + "\n") - return m, nil + m.textarea.SetValue(value[:len(value)-1]) } else { // Otherwise, send the message return m, m.send() @@ -344,8 +361,9 @@ func (m *editorCmp) startCompletions() tea.Msg { }) } - x := m.textarea.Cursor().X + m.x + 1 - y := m.textarea.Cursor().Y + m.y + 1 + cur := m.textarea.Cursor() + x := cur.X + m.x // adjust for padding + y := cur.Y + m.y + 1 return completions.OpenCompletionsMsg{ Completions: completionItems, X: x, @@ -369,19 +387,31 @@ func (c *editorCmp) IsFocused() bool { return c.textarea.Focused() } +// Bindings implements Container. func (c *editorCmp) Bindings() []key.Binding { return c.keyMap.KeyBindings() } -func NewEditorCmp(app *app.App) util.Model { +// TODO: most likely we do not need to have the session here +// we need to move some functionality to the page level +func (c *editorCmp) SetSession(session session.Session) tea.Cmd { + c.session = session + return nil +} + +func (c *editorCmp) IsCompletionsOpen() bool { + return c.isCompletionsOpen +} + +func New(app *app.App) Editor { t := styles.CurrentTheme() ta := textarea.New() ta.SetStyles(t.S().TextArea) - ta.SetPromptFunc(4, func(lineIndex int, focused bool) string { - if lineIndex == 0 { + ta.SetPromptFunc(4, func(info textarea.PromptInfo) string { + if info.LineNumber == 0 { return " > " } - if focused { + if info.Focused { return t.S().Base.Foreground(t.GreenDark).Render("::: ") } else { return t.S().Muted.Render("::: ") @@ -394,6 +424,7 @@ func NewEditorCmp(app *app.App) util.Model { ta.Focus() return &editorCmp{ + // TODO: remove the app instance from here app: app, textarea: ta, keyMap: DefaultEditorKeyMap(), diff --git a/internal/tui/components/chat/editor/keys.go b/internal/tui/components/chat/editor/keys.go index c64a92d526a1a81e558909fe5500b2bf1d4e3990..ef002436901ed0fbad3bcbd2da7cecc08ef255c1 100644 --- a/internal/tui/components/chat/editor/keys.go +++ b/internal/tui/components/chat/editor/keys.go @@ -8,6 +8,7 @@ type EditorKeyMap struct { AddFile key.Binding SendMessage key.Binding OpenEditor key.Binding + Newline key.Binding } func DefaultEditorKeyMap() EditorKeyMap { @@ -21,8 +22,15 @@ func DefaultEditorKeyMap() EditorKeyMap { key.WithHelp("enter", "send"), ), OpenEditor: key.NewBinding( - key.WithKeys("ctrl+e"), - key.WithHelp("ctrl+e", "open editor"), + key.WithKeys("ctrl+v"), + key.WithHelp("ctrl+v", "open editor"), + ), + Newline: key.NewBinding( + key.WithKeys("shift+enter", "ctrl+j"), + // "ctrl+j" is a common keybinding for newline in many editors. If + // the terminal supports "shift+enter", we substitute the help text + // to reflect that. + key.WithHelp("ctrl+j", "newline"), ), } } @@ -33,6 +41,7 @@ func (k EditorKeyMap) KeyBindings() []key.Binding { k.AddFile, k.SendMessage, k.OpenEditor, + k.Newline, } } diff --git a/internal/tui/components/chat/header/header.go b/internal/tui/components/chat/header/header.go index 0d01aa6fef1638cf85ad8ddf091c9bcbd2b789b0..5d27cc14fdf341ea3f201876f80f7edd7f1ce328 100644 --- a/internal/tui/components/chat/header/header.go +++ b/internal/tui/components/chat/header/header.go @@ -11,7 +11,6 @@ import ( "github.com/charmbracelet/crush/internal/lsp/protocol" "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/session" - "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" @@ -19,7 +18,8 @@ import ( type Header interface { util.Model - SetSession(session session.Session) + SetSession(session session.Session) tea.Cmd + SetWidth(width int) tea.Cmd SetDetailsOpen(open bool) } @@ -43,10 +43,6 @@ func (h *header) Init() tea.Cmd { func (p *header) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case tea.WindowSizeMsg: - p.width = msg.Width - 2 - case chat.SessionSelectedMsg: - p.session = msg case pubsub.Event[session.Session]: if msg.Type == pubsub.UpdatedEvent { if p.session.ID == msg.Payload.ID { @@ -131,6 +127,13 @@ func (h *header) SetDetailsOpen(open bool) { } // SetSession implements Header. -func (h *header) SetSession(session session.Session) { +func (h *header) SetSession(session session.Session) tea.Cmd { h.session = session + return nil +} + +// SetWidth implements Header. +func (h *header) SetWidth(width int) tea.Cmd { + h.width = width + return nil } diff --git a/internal/tui/components/chat/messages/messages.go b/internal/tui/components/chat/messages/messages.go index bd10b1c78dc06d5569b943267018b95631892427..e8ae97056728a0377ddcad179ecae1246f2da662 100644 --- a/internal/tui/components/chat/messages/messages.go +++ b/internal/tui/components/chat/messages/messages.go @@ -10,6 +10,7 @@ import ( "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/fur/provider" "github.com/charmbracelet/crush/internal/message" "github.com/charmbracelet/crush/internal/tui/components/anim" "github.com/charmbracelet/crush/internal/tui/components/core" @@ -65,10 +66,7 @@ func NewMessageCmp(msg message.Message) MessageCmp { // Returns a command to start the animation for spinning messages. func (m *messageCmp) Init() tea.Cmd { m.spinning = m.shouldSpin() - if m.spinning { - return m.anim.Init() - } - return nil + return m.anim.Init() } // Update handles incoming messages and updates the component state. @@ -296,6 +294,12 @@ func (m *assistantSectionModel) View() string { infoMsg := t.S().Subtle.Render(duration.String()) icon := t.S().Subtle.Render(styles.ModelIcon) model := config.Get().GetModel(m.message.Provider, m.message.Model) + if model == nil { + // This means the model is not configured anymore + model = &provider.Model{ + Model: "Unknown Model", + } + } modelFormatted := t.S().Muted.Render(model.Model) assistant := fmt.Sprintf("%s %s %s", icon, modelFormatted, infoMsg) return t.S().Base.PaddingLeft(2).Render( diff --git a/internal/tui/components/chat/messages/renderer.go b/internal/tui/components/chat/messages/renderer.go index 2d86d103bc60f2122c3eaf58883bd6d9ac42a47e..87eb2c8476655fe7d11fc8c787e73b32d4584de4 100644 --- a/internal/tui/components/chat/messages/renderer.go +++ b/internal/tui/components/chat/messages/renderer.go @@ -112,10 +112,21 @@ func (br baseRenderer) unmarshalParams(input string, target any) error { } // makeHeader builds the tool call header with status icon and parameters for a nested tool call. -func (br baseRenderer) makeNestedHeader(_ *toolCallCmp, tool string, width int, params ...string) string { +func (br baseRenderer) makeNestedHeader(v *toolCallCmp, tool string, width int, params ...string) string { t := styles.CurrentTheme() + icon := t.S().Base.Foreground(t.GreenDark).Render(styles.ToolPending) + if v.result.ToolCallID != "" { + if v.result.IsError { + icon = t.S().Base.Foreground(t.RedDark).Render(styles.ToolError) + } else { + icon = t.S().Base.Foreground(t.Green).Render(styles.ToolSuccess) + } + } else if v.cancelled { + icon = t.S().Muted.Render(styles.ToolPending) + } tool = t.S().Base.Foreground(t.FgHalfMuted).Render(tool) + " " - return tool + renderParamList(true, width-lipgloss.Width(tool), params...) + prefix := fmt.Sprintf("%s %s ", icon, tool) + return prefix + renderParamList(true, width-lipgloss.Width(tool), params...) } // makeHeader builds ": param (key=value)" and truncates as needed. @@ -196,6 +207,7 @@ func (br bashRenderer) Render(v *toolCallCmp) string { } cmd := strings.ReplaceAll(params.Command, "\n", " ") + cmd = strings.ReplaceAll(cmd, "\t", " ") args := newParamBuilder().addMain(cmd).build() return br.renderWithParams(v, "Bash", args, func() string { @@ -542,7 +554,7 @@ func (tr agentRenderer) Render(v *toolCallCmp) string { if v.result.ToolCallID == "" { v.spinning = true - parts = append(parts, v.anim.View()) + parts = append(parts, "", v.anim.View()) } else { v.spinning = false } @@ -567,8 +579,8 @@ func renderParamList(nested bool, paramsWidth int, params ...string) string { return "" } mainParam := params[0] - if len(mainParam) > paramsWidth { - mainParam = mainParam[:paramsWidth-3] + "…" + if paramsWidth >= 0 && lipgloss.Width(mainParam) > paramsWidth { + mainParam = ansi.Truncate(mainParam, paramsWidth, "…") } if len(params) == 1 { @@ -621,9 +633,9 @@ func earlyState(header string, v *toolCallCmp) (string, bool) { case v.result.IsError: message = v.renderToolError() case v.cancelled: - message = t.S().Base.Padding(0, 1).Background(t.Border).Render("Cancelled") + message = t.S().Base.Foreground(t.FgSubtle).Render("Canceled.") case v.result.ToolCallID == "": - message = t.S().Base.Padding(0, 1).Background(t.Accent).Foreground(t.FgSubtle).Render("Waiting for tool to start...") + message = t.S().Base.Foreground(t.FgSubtle).Render("Waiting for tool to start...") default: return "", false } @@ -634,8 +646,11 @@ func earlyState(header string, v *toolCallCmp) (string, bool) { func joinHeaderBody(header, body string) string { t := styles.CurrentTheme() + if body == "" { + return header + } body = t.S().Base.PaddingLeft(2).Render(body) - return lipgloss.JoinVertical(lipgloss.Left, header, "", body, "") + return lipgloss.JoinVertical(lipgloss.Left, header, "", body) } func renderPlainContent(v *toolCallCmp, content string) string { diff --git a/internal/tui/components/chat/messages/tool.go b/internal/tui/components/chat/messages/tool.go index fe61d44fb77f81d330447beecb9b1a7192a2a0c4..90ced40eeb54c0509dae9e74775462a179e0ad28 100644 --- a/internal/tui/components/chat/messages/tool.go +++ b/internal/tui/components/chat/messages/tool.go @@ -114,10 +114,7 @@ func NewToolCallCmp(parentMessageID string, tc message.ToolCall, opts ...ToolCal // Returns a command to start the animation for pending tool calls. func (m *toolCallCmp) Init() tea.Cmd { m.spinning = m.shouldSpin() - if m.spinning { - return m.anim.Init() - } - return nil + return m.anim.Init() } // Update handles incoming messages and updates the component state. @@ -219,11 +216,11 @@ func (m *toolCallCmp) SetIsNested(isNested bool) { // renderPending displays the tool name with a loading animation for pending tool calls func (m *toolCallCmp) renderPending() string { t := styles.CurrentTheme() + icon := t.S().Base.Foreground(t.GreenDark).Render(styles.ToolPending) if m.isNested { tool := t.S().Base.Foreground(t.FgHalfMuted).Render(prettifyToolName(m.call.Name)) - return fmt.Sprintf("%s %s", tool, m.anim.View()) + return fmt.Sprintf("%s %s %s", icon, tool, m.anim.View()) } - icon := t.S().Base.Foreground(t.GreenDark).Render(styles.ToolPending) tool := t.S().Base.Foreground(t.Blue).Render(prettifyToolName(m.call.Name)) return fmt.Sprintf("%s %s %s", icon, tool, m.anim.View()) } diff --git a/internal/tui/components/chat/sidebar/sidebar.go b/internal/tui/components/chat/sidebar/sidebar.go index 3d8338c2b40b33febd9d78f2649cc3aa06337db6..3fa08ce021d0fcac1ce7dc9668d46198f6d08055 100644 --- a/internal/tui/components/chat/sidebar/sidebar.go +++ b/internal/tui/components/chat/sidebar/sidebar.go @@ -13,7 +13,6 @@ import ( "github.com/charmbracelet/crush/internal/diff" "github.com/charmbracelet/crush/internal/fsext" "github.com/charmbracelet/crush/internal/history" - "github.com/charmbracelet/crush/internal/lsp" "github.com/charmbracelet/crush/internal/lsp/protocol" "github.com/charmbracelet/crush/internal/pubsub" @@ -29,10 +28,6 @@ import ( "github.com/charmbracelet/x/ansi" ) -const ( - logoBreakpoint = 65 -) - type FileHistory struct { initialVersion history.File latestVersion history.File @@ -52,6 +47,7 @@ type Sidebar interface { util.Model layout.Sizeable SetSession(session session.Session) tea.Cmd + SetCompactMode(bool) } type sidebarCmp struct { @@ -66,7 +62,7 @@ type sidebarCmp struct { files sync.Map } -func NewSidebarCmp(history history.Service, lspClients map[string]*lsp.Client, compact bool) Sidebar { +func New(history history.Service, lspClients map[string]*lsp.Client, compact bool) Sidebar { return &sidebarCmp{ lspClients: lspClients, history: history, @@ -75,15 +71,11 @@ func NewSidebarCmp(history history.Service, lspClients map[string]*lsp.Client, c } func (m *sidebarCmp) Init() tea.Cmd { - m.logo = m.logoBlock(false) - m.cwd = cwd() return nil } func (m *sidebarCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case chat.SessionSelectedMsg: - return m, m.SetSession(msg) case SessionFilesMsg: m.files = sync.Map{} for _, file := range msg.Files { @@ -137,7 +129,16 @@ func (m *sidebarCmp) View() string { m.mcpBlock(), ) - return lipgloss.JoinVertical(lipgloss.Left, parts...) + style := t.S().Base. + Width(m.width). + Height(m.height). + Padding(1) + if m.compactMode { + style = style.PaddingTop(0) + } + return style.Render( + lipgloss.JoinVertical(lipgloss.Left, parts...), + ) } func (m *sidebarCmp) handleFileHistoryEvent(event pubsub.Event[history.File]) tea.Cmd { @@ -230,12 +231,8 @@ func (m *sidebarCmp) loadSessionFiles() tea.Msg { } func (m *sidebarCmp) SetSize(width, height int) tea.Cmd { - if width < logoBreakpoint && (m.width == 0 || m.width >= logoBreakpoint) { - m.logo = m.logoBlock(true) - } else if width >= logoBreakpoint && (m.width == 0 || m.width < logoBreakpoint) { - m.logo = m.logoBlock(false) - } - + m.logo = m.logoBlock() + m.cwd = cwd() m.width = width m.height = height return nil @@ -245,23 +242,27 @@ func (m *sidebarCmp) GetSize() (int, int) { return m.width, m.height } -func (m *sidebarCmp) logoBlock(compact bool) string { +func (m *sidebarCmp) logoBlock() string { t := styles.CurrentTheme() - return logo.Render(version.Version, compact, logo.Opts{ + return logo.Render(version.Version, true, logo.Opts{ FieldColor: t.Primary, TitleColorA: t.Secondary, TitleColorB: t.Primary, CharmColor: t.Secondary, VersionColor: t.Primary, + Width: m.width - 2, }) } +func (m *sidebarCmp) getMaxWidth() int { + return min(m.width-2, 58) // -2 for padding +} + func (m *sidebarCmp) filesBlock() string { - maxWidth := min(m.width, 58) t := styles.CurrentTheme() section := t.S().Subtle.Render( - core.Section("Modified Files", maxWidth), + core.Section("Modified Files", m.getMaxWidth()), ) files := make([]SessionFile, 0) @@ -302,7 +303,7 @@ func (m *sidebarCmp) filesBlock() string { filePath := file.FilePath filePath = strings.TrimPrefix(filePath, cwd) filePath = fsext.DirTrim(fsext.PrettyPath(filePath), 2) - filePath = ansi.Truncate(filePath, maxWidth-lipgloss.Width(extraContent)-2, "…") + filePath = ansi.Truncate(filePath, m.getMaxWidth()-lipgloss.Width(extraContent)-2, "…") fileList = append(fileList, core.Status( core.StatusOpts{ @@ -311,7 +312,7 @@ func (m *sidebarCmp) filesBlock() string { Title: filePath, ExtraContent: extraContent, }, - m.width, + m.getMaxWidth(), ), ) } @@ -323,11 +324,10 @@ func (m *sidebarCmp) filesBlock() string { } func (m *sidebarCmp) lspBlock() string { - maxWidth := min(m.width, 58) t := styles.CurrentTheme() section := t.S().Subtle.Render( - core.Section("LSPs", maxWidth), + core.Section("LSPs", m.getMaxWidth()), ) lspList := []string{section, ""} @@ -385,7 +385,7 @@ func (m *sidebarCmp) lspBlock() string { Description: l.LSP.Command, ExtraContent: strings.Join(errs, " "), }, - m.width, + m.getMaxWidth(), ), ) } @@ -397,11 +397,10 @@ func (m *sidebarCmp) lspBlock() string { } func (m *sidebarCmp) mcpBlock() string { - maxWidth := min(m.width, 58) t := styles.CurrentTheme() section := t.S().Subtle.Render( - core.Section("MCPs", maxWidth), + core.Section("MCPs", m.getMaxWidth()), ) mcpList := []string{section, ""} @@ -428,7 +427,7 @@ func (m *sidebarCmp) mcpBlock() string { Title: l.Name, Description: l.MCP.Command, }, - m.width, + m.getMaxWidth(), ), ) } @@ -511,6 +510,11 @@ func (m *sidebarCmp) SetSession(session session.Session) tea.Cmd { return m.loadSessionFiles } +// SetCompactMode sets the compact mode for the sidebar. +func (m *sidebarCmp) SetCompactMode(compact bool) { + m.compactMode = compact +} + func cwd() string { cwd := config.Get().WorkingDir() t := styles.CurrentTheme() diff --git a/internal/tui/components/chat/splash/keys.go b/internal/tui/components/chat/splash/keys.go index df715c89e86971a0f788915737bf41a212c65b5a..675c608a94af4aa72b701376f3983506166ac7d7 100644 --- a/internal/tui/components/chat/splash/keys.go +++ b/internal/tui/components/chat/splash/keys.go @@ -5,14 +5,49 @@ import ( ) type KeyMap struct { - Cancel key.Binding + Select, + Next, + Previous, + Yes, + No, + Tab, + LeftRight, + Back key.Binding } func DefaultKeyMap() KeyMap { return KeyMap{ - Cancel: key.NewBinding( + Select: key.NewBinding( + key.WithKeys("enter", "ctrl+y"), + key.WithHelp("enter", "confirm"), + ), + Next: key.NewBinding( + key.WithKeys("down", "ctrl+n"), + key.WithHelp("↓", "next item"), + ), + Previous: key.NewBinding( + key.WithKeys("up", "ctrl+p"), + key.WithHelp("↑", "previous item"), + ), + Yes: key.NewBinding( + key.WithKeys("y", "Y"), + key.WithHelp("y", "yes"), + ), + No: key.NewBinding( + key.WithKeys("n", "N"), + key.WithHelp("n", "no"), + ), + Tab: key.NewBinding( + key.WithKeys("tab"), + key.WithHelp("tab", "switch"), + ), + LeftRight: key.NewBinding( + key.WithKeys("left", "right"), + key.WithHelp("←/→", "switch"), + ), + Back: key.NewBinding( key.WithKeys("esc"), - key.WithHelp("esc", "cancel"), + key.WithHelp("esc", "back"), ), } } diff --git a/internal/tui/components/chat/splash/splash.go b/internal/tui/components/chat/splash/splash.go index 2bd8aaed34b636d92b488af961635973be9576ae..5b343e6c5538cc17b476e521e6f2bfaf6b3490cb 100644 --- a/internal/tui/components/chat/splash/splash.go +++ b/internal/tui/components/chat/splash/splash.go @@ -1,9 +1,22 @@ package splash import ( + "fmt" + "os" + "slices" + "strings" + "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/fur/provider" + "github.com/charmbracelet/crush/internal/llm/prompt" + "github.com/charmbracelet/crush/internal/tui/components/chat" + "github.com/charmbracelet/crush/internal/tui/components/completions" + "github.com/charmbracelet/crush/internal/tui/components/core" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/core/list" + "github.com/charmbracelet/crush/internal/tui/components/dialogs/models" "github.com/charmbracelet/crush/internal/tui/components/logo" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" @@ -15,23 +28,98 @@ type Splash interface { util.Model layout.Sizeable layout.Help + Cursor() *tea.Cursor + // SetOnboarding controls whether the splash shows model selection UI + SetOnboarding(bool) + // SetProjectInit controls whether the splash shows project initialization prompt + SetProjectInit(bool) + + // Showing API key input + IsShowingAPIKey() bool } +const ( + SplashScreenPaddingY = 1 // Padding Y for the splash screen + + LogoGap = 6 +) + +// OnboardingCompleteMsg is sent when onboarding is complete +type OnboardingCompleteMsg struct{} + type splashCmp struct { width, height int keyMap KeyMap logoRendered string + + // State + isOnboarding bool + needsProjectInit bool + needsAPIKey bool + selectedNo bool + + listHeight int + modelList *models.ModelListComponent + apiKeyInput *models.APIKeyInput + selectedModel *models.ModelOption } func New() Splash { + keyMap := DefaultKeyMap() + listKeyMap := list.DefaultKeyMap() + listKeyMap.Down.SetEnabled(false) + listKeyMap.Up.SetEnabled(false) + listKeyMap.HalfPageDown.SetEnabled(false) + listKeyMap.HalfPageUp.SetEnabled(false) + listKeyMap.Home.SetEnabled(false) + listKeyMap.End.SetEnabled(false) + listKeyMap.DownOneItem = keyMap.Next + listKeyMap.UpOneItem = keyMap.Previous + + t := styles.CurrentTheme() + inputStyle := t.S().Base.Padding(0, 1, 0, 1) + modelList := models.NewModelListComponent(listKeyMap, inputStyle, "Find your fave") + apiKeyInput := models.NewAPIKeyInput() + return &splashCmp{ width: 0, height: 0, - keyMap: DefaultKeyMap(), + keyMap: keyMap, logoRendered: "", + modelList: modelList, + apiKeyInput: apiKeyInput, + selectedNo: false, } } +func (s *splashCmp) SetOnboarding(onboarding bool) { + s.isOnboarding = onboarding + if onboarding { + providers, err := config.Providers() + if err != nil { + return + } + filteredProviders := []provider.Provider{} + simpleProviders := []string{ + "anthropic", + "openai", + "gemini", + "xai", + "openrouter", + } + for _, p := range providers { + if slices.Contains(simpleProviders, string(p.ID)) { + filteredProviders = append(filteredProviders, p) + } + } + s.modelList.SetProviders(filteredProviders) + } +} + +func (s *splashCmp) SetProjectInit(needsInit bool) { + s.needsProjectInit = needsInit +} + // GetSize implements SplashPage. func (s *splashCmp) GetSize() (int, int) { return s.width, s.height @@ -39,15 +127,20 @@ func (s *splashCmp) GetSize() (int, int) { // Init implements SplashPage. func (s *splashCmp) Init() tea.Cmd { - return nil + return tea.Batch(s.modelList.Init(), s.apiKeyInput.Init()) } // SetSize implements SplashPage. func (s *splashCmp) SetSize(width int, height int) tea.Cmd { - s.width = width s.height = height - s.logoRendered = s.logoBlock() - return nil + if width != s.width { + s.width = width + s.logoRendered = s.logoBlock() + } + // remove padding, logo height, gap, title space + s.listHeight = s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - s.logoGap() - 2 + listWidth := min(60, width) + return s.modelList.SetSize(listWidth, s.listHeight) } // Update implements SplashPage. @@ -55,32 +148,485 @@ func (s *splashCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: return s, s.SetSize(msg.Width, msg.Height) + case tea.KeyPressMsg: + switch { + case key.Matches(msg, s.keyMap.Back): + if s.needsAPIKey { + // Go back to model selection + s.needsAPIKey = false + s.selectedModel = nil + return s, nil + } + case key.Matches(msg, s.keyMap.Select): + if s.isOnboarding && !s.needsAPIKey { + modelInx := s.modelList.SelectedIndex() + items := s.modelList.Items() + selectedItem := items[modelInx].(completions.CompletionItem).Value().(models.ModelOption) + if s.isProviderConfigured(string(selectedItem.Provider.ID)) { + cmd := s.setPreferredModel(selectedItem) + s.isOnboarding = false + return s, tea.Batch(cmd, util.CmdHandler(OnboardingCompleteMsg{})) + } else { + // Provider not configured, show API key input + s.needsAPIKey = true + s.selectedModel = &selectedItem + s.apiKeyInput.SetProviderName(selectedItem.Provider.Name) + return s, nil + } + } else if s.needsAPIKey { + // Handle API key submission + apiKey := s.apiKeyInput.Value() + if apiKey != "" { + return s, s.saveAPIKeyAndContinue(apiKey) + } + } else if s.needsProjectInit { + return s, s.initializeProject() + } + case key.Matches(msg, s.keyMap.Tab, s.keyMap.LeftRight): + if s.needsProjectInit { + s.selectedNo = !s.selectedNo + return s, nil + } + case key.Matches(msg, s.keyMap.Yes): + if s.needsProjectInit { + return s, s.initializeProject() + } + case key.Matches(msg, s.keyMap.No): + if s.needsProjectInit { + s.needsProjectInit = false + return s, util.CmdHandler(OnboardingCompleteMsg{}) + } + default: + if s.needsAPIKey { + u, cmd := s.apiKeyInput.Update(msg) + s.apiKeyInput = u.(*models.APIKeyInput) + return s, cmd + } else if s.isOnboarding { + u, cmd := s.modelList.Update(msg) + s.modelList = u + return s, cmd + } + } + case tea.PasteMsg: + if s.needsAPIKey { + u, cmd := s.apiKeyInput.Update(msg) + s.apiKeyInput = u.(*models.APIKeyInput) + return s, cmd + } else if s.isOnboarding { + var cmd tea.Cmd + s.modelList, cmd = s.modelList.Update(msg) + return s, cmd + } } return s, nil } -// View implements SplashPage. +func (s *splashCmp) saveAPIKeyAndContinue(apiKey string) tea.Cmd { + if s.selectedModel == nil { + return util.ReportError(fmt.Errorf("no model selected")) + } + + cfg := config.Get() + err := cfg.SetProviderAPIKey(string(s.selectedModel.Provider.ID), apiKey) + if err != nil { + return util.ReportError(fmt.Errorf("failed to save API key: %w", err)) + } + + // Reset API key state and continue with model selection + s.needsAPIKey = false + cmd := s.setPreferredModel(*s.selectedModel) + s.isOnboarding = false + s.selectedModel = nil + + return tea.Batch(cmd, util.CmdHandler(OnboardingCompleteMsg{})) +} + +func (s *splashCmp) initializeProject() tea.Cmd { + s.needsProjectInit = false + + if err := config.MarkProjectInitialized(); err != nil { + return util.ReportError(err) + } + var cmds []tea.Cmd + + cmds = append(cmds, util.CmdHandler(OnboardingCompleteMsg{})) + if !s.selectedNo { + cmds = append(cmds, + util.CmdHandler(chat.SessionClearedMsg{}), + util.CmdHandler(chat.SendMsg{ + Text: prompt.Initialize(), + }), + ) + } + return tea.Sequence(cmds...) +} + +func (s *splashCmp) setPreferredModel(selectedItem models.ModelOption) tea.Cmd { + cfg := config.Get() + model := cfg.GetModel(string(selectedItem.Provider.ID), selectedItem.Model.ID) + if model == nil { + return util.ReportError(fmt.Errorf("model %s not found for provider %s", selectedItem.Model.ID, selectedItem.Provider.ID)) + } + + selectedModel := config.SelectedModel{ + Model: selectedItem.Model.ID, + Provider: string(selectedItem.Provider.ID), + ReasoningEffort: model.DefaultReasoningEffort, + MaxTokens: model.DefaultMaxTokens, + } + + err := cfg.UpdatePreferredModel(config.SelectedModelTypeLarge, selectedModel) + if err != nil { + return util.ReportError(err) + } + + // Now lets automatically setup the small model + knownProvider, err := s.getProvider(selectedItem.Provider.ID) + if err != nil { + return util.ReportError(err) + } + if knownProvider == nil { + // for local provider we just use the same model + err = cfg.UpdatePreferredModel(config.SelectedModelTypeSmall, selectedModel) + if err != nil { + return util.ReportError(err) + } + } else { + smallModel := knownProvider.DefaultSmallModelID + model := cfg.GetModel(string(selectedItem.Provider.ID), smallModel) + // should never happen + if model == nil { + err = cfg.UpdatePreferredModel(config.SelectedModelTypeSmall, selectedModel) + if err != nil { + return util.ReportError(err) + } + return nil + } + smallSelectedModel := config.SelectedModel{ + Model: smallModel, + Provider: string(selectedItem.Provider.ID), + ReasoningEffort: model.DefaultReasoningEffort, + MaxTokens: model.DefaultMaxTokens, + } + err = cfg.UpdatePreferredModel(config.SelectedModelTypeSmall, smallSelectedModel) + if err != nil { + return util.ReportError(err) + } + } + cfg.SetupAgents() + return nil +} + +func (s *splashCmp) getProvider(providerID provider.InferenceProvider) (*provider.Provider, error) { + providers, err := config.Providers() + if err != nil { + return nil, err + } + for _, p := range providers { + if p.ID == providerID { + return &p, nil + } + } + return nil, nil +} + +func (s *splashCmp) isProviderConfigured(providerID string) bool { + cfg := config.Get() + if _, ok := cfg.Providers[providerID]; ok { + return true + } + return false +} + func (s *splashCmp) View() string { - content := lipgloss.JoinVertical(lipgloss.Left, s.logoRendered) - return content + t := styles.CurrentTheme() + var content string + if s.needsAPIKey { + remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) + apiKeyView := t.S().Base.PaddingLeft(1).Render(s.apiKeyInput.View()) + apiKeySelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render( + lipgloss.JoinVertical( + lipgloss.Left, + apiKeyView, + ), + ) + content = lipgloss.JoinVertical( + lipgloss.Left, + s.logoRendered, + apiKeySelector, + ) + } else if s.isOnboarding { + modelListView := s.modelList.View() + remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) + modelSelector := t.S().Base.AlignVertical(lipgloss.Bottom).Height(remainingHeight).Render( + lipgloss.JoinVertical( + lipgloss.Left, + t.S().Base.PaddingLeft(1).Foreground(t.Primary).Render("Choose a Model"), + "", + modelListView, + ), + ) + content = lipgloss.JoinVertical( + lipgloss.Left, + s.logoRendered, + modelSelector, + ) + } else if s.needsProjectInit { + titleStyle := t.S().Base.Foreground(t.FgBase) + bodyStyle := t.S().Base.Foreground(t.FgMuted) + shortcutStyle := t.S().Base.Foreground(t.Success) + + initText := lipgloss.JoinVertical( + lipgloss.Left, + titleStyle.Render("Would you like to initialize this project?"), + "", + bodyStyle.Render("When I initialize your codebase I examine the project and put the"), + bodyStyle.Render("result into a CRUSH.md file which serves as general context."), + "", + bodyStyle.Render("You can also initialize anytime via ")+shortcutStyle.Render("ctrl+p")+bodyStyle.Render("."), + "", + bodyStyle.Render("Would you like to initialize now?"), + ) + + yesButton := core.SelectableButton(core.ButtonOpts{ + Text: "Yep!", + UnderlineIndex: 0, + Selected: !s.selectedNo, + }) + + noButton := core.SelectableButton(core.ButtonOpts{ + Text: "Nope", + UnderlineIndex: 0, + Selected: s.selectedNo, + }) + + buttons := lipgloss.JoinHorizontal(lipgloss.Left, yesButton, " ", noButton) + infoSection := s.infoSection() + + remainingHeight := s.height - lipgloss.Height(s.logoRendered) - (SplashScreenPaddingY * 2) - lipgloss.Height(infoSection) + + initContent := t.S().Base.AlignVertical(lipgloss.Bottom).PaddingLeft(1).Height(remainingHeight).Render( + lipgloss.JoinVertical( + lipgloss.Left, + initText, + "", + buttons, + ), + ) + + content = lipgloss.JoinVertical( + lipgloss.Left, + s.logoRendered, + infoSection, + initContent, + ) + } else { + parts := []string{ + s.logoRendered, + s.infoSection(), + } + content = lipgloss.JoinVertical(lipgloss.Left, parts...) + } + + return t.S().Base. + Width(s.width). + Height(s.height). + PaddingTop(SplashScreenPaddingY). + PaddingBottom(SplashScreenPaddingY). + Render(content) +} + +func (s *splashCmp) Cursor() *tea.Cursor { + if s.needsAPIKey { + cursor := s.apiKeyInput.Cursor() + if cursor != nil { + return s.moveCursor(cursor) + } + } else if s.isOnboarding { + cursor := s.modelList.Cursor() + if cursor != nil { + return s.moveCursor(cursor) + } + } else { + return nil + } + return nil +} + +func (s *splashCmp) infoSection() string { + t := styles.CurrentTheme() + return t.S().Base.PaddingLeft(2).Render( + lipgloss.JoinVertical( + lipgloss.Left, + s.cwd(), + "", + lipgloss.JoinHorizontal(lipgloss.Left, s.lspBlock(), s.mcpBlock()), + "", + ), + ) } func (s *splashCmp) logoBlock() string { t := styles.CurrentTheme() - const padding = 2 - return logo.Render(version.Version, false, logo.Opts{ - FieldColor: t.Primary, - TitleColorA: t.Secondary, - TitleColorB: t.Primary, - CharmColor: t.Secondary, - VersionColor: t.Primary, - Width: s.width - padding, - }) + return t.S().Base.Padding(0, 2).Width(s.width).Render( + logo.Render(version.Version, false, logo.Opts{ + FieldColor: t.Primary, + TitleColorA: t.Secondary, + TitleColorB: t.Primary, + CharmColor: t.Secondary, + VersionColor: t.Primary, + Width: s.width - 4, + }), + ) +} + +func (s *splashCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor { + if cursor == nil { + return nil + } + // Calculate the correct Y offset based on current state + logoHeight := lipgloss.Height(s.logoRendered) + if s.needsAPIKey { + infoSectionHeight := lipgloss.Height(s.infoSection()) + baseOffset := logoHeight + SplashScreenPaddingY + infoSectionHeight + remainingHeight := s.height - baseOffset - lipgloss.Height(s.apiKeyInput.View()) - SplashScreenPaddingY + offset := baseOffset + remainingHeight + cursor.Y += offset + cursor.X = cursor.X + 1 + } else if s.isOnboarding { + offset := logoHeight + SplashScreenPaddingY + s.logoGap() + 3 + cursor.Y += offset + cursor.X = cursor.X + 1 + } + + return cursor +} + +func (s *splashCmp) logoGap() int { + if s.height > 35 { + return LogoGap + } + return 0 } // Bindings implements SplashPage. func (s *splashCmp) Bindings() []key.Binding { - return []key.Binding{ - s.keyMap.Cancel, + if s.needsAPIKey { + return []key.Binding{ + s.keyMap.Select, + s.keyMap.Back, + } + } else if s.isOnboarding { + return []key.Binding{ + s.keyMap.Select, + s.keyMap.Next, + s.keyMap.Previous, + } + } else if s.needsProjectInit { + return []key.Binding{ + s.keyMap.Select, + s.keyMap.Yes, + s.keyMap.No, + s.keyMap.Tab, + s.keyMap.LeftRight, + } } + return []key.Binding{} +} + +func (s *splashCmp) getMaxInfoWidth() int { + return min(s.width-2, 40) // 2 for left padding +} + +func (s *splashCmp) cwd() string { + cwd := config.Get().WorkingDir() + t := styles.CurrentTheme() + homeDir, err := os.UserHomeDir() + if err == nil && cwd != homeDir { + cwd = strings.ReplaceAll(cwd, homeDir, "~") + } + maxWidth := s.getMaxInfoWidth() + return t.S().Muted.Width(maxWidth).Render(cwd) +} + +func LSPList(maxWidth int) []string { + t := styles.CurrentTheme() + lspList := []string{} + lsp := config.Get().LSP.Sorted() + if len(lsp) == 0 { + return []string{t.S().Base.Foreground(t.Border).Render("None")} + } + for _, l := range lsp { + iconColor := t.Success + if l.LSP.Disabled { + iconColor = t.FgMuted + } + lspList = append(lspList, + core.Status( + core.StatusOpts{ + IconColor: iconColor, + Title: l.Name, + Description: l.LSP.Command, + }, + maxWidth, + ), + ) + } + return lspList +} + +func (s *splashCmp) lspBlock() string { + t := styles.CurrentTheme() + maxWidth := s.getMaxInfoWidth() / 2 + section := t.S().Subtle.Render("LSPs") + lspList := append([]string{section, ""}, LSPList(maxWidth-1)...) + return t.S().Base.Width(maxWidth).PaddingRight(1).Render( + lipgloss.JoinVertical( + lipgloss.Left, + lspList..., + ), + ) +} + +func MCPList(maxWidth int) []string { + t := styles.CurrentTheme() + mcpList := []string{} + mcps := config.Get().MCP.Sorted() + if len(mcps) == 0 { + return []string{t.S().Base.Foreground(t.Border).Render("None")} + } + for _, l := range mcps { + iconColor := t.Success + if l.MCP.Disabled { + iconColor = t.FgMuted + } + mcpList = append(mcpList, + core.Status( + core.StatusOpts{ + IconColor: iconColor, + Title: l.Name, + Description: l.MCP.Command, + }, + maxWidth, + ), + ) + } + return mcpList +} + +func (s *splashCmp) mcpBlock() string { + t := styles.CurrentTheme() + maxWidth := s.getMaxInfoWidth() / 2 + section := t.S().Subtle.Render("MCPs") + mcpList := append([]string{section, ""}, MCPList(maxWidth-1)...) + return t.S().Base.Width(maxWidth).PaddingRight(1).Render( + lipgloss.JoinVertical( + lipgloss.Left, + mcpList..., + ), + ) +} + +func (s *splashCmp) IsShowingAPIKey() bool { + return s.needsAPIKey } diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index 6153a76834ff697546e0c3ba38dece817bb97921..5a6bcfe92e23f38c3f40c84770a0dcc9893e59d5 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -9,6 +9,8 @@ import ( "github.com/charmbracelet/lipgloss/v2" ) +const maxCompletionsHeight = 10 + type Completion struct { Title string // The title of the completion item Value any // The value of the completion item @@ -43,7 +45,7 @@ type Completions interface { type completionsCmp struct { width int height int // Height of the completions component` - x int // X position for the completions popup\ + x int // X position for the completions popup y int // Y position for the completions popup open bool // Indicates if the completions are open keyMap KeyMap @@ -70,8 +72,8 @@ func New() Completions { list.WithHideFilterInput(true), ) return &completionsCmp{ - width: 30, - height: 10, + width: 0, + height: 0, list: l, query: "", keyMap: completionsKeyMap, @@ -89,6 +91,10 @@ func (c *completionsCmp) Init() tea.Cmd { // Update implements Completions. func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case tea.WindowSizeMsg: + c.width = min(msg.Width-c.x, 80) + c.height = min(msg.Height-c.y, 15) + return c, nil case tea.KeyPressMsg: switch { case key.Matches(msg, c.keyMap.Up): @@ -135,7 +141,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { item := NewCompletionItem(completion.Title, completion.Value, WithBackgroundColor(t.BgSubtle)) items = append(items, item) } - c.height = max(min(10, len(items)), 1) // Ensure at least 1 item height + c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height cmds := []tea.Cmd{ c.list.SetSize(c.width, c.height), c.list.SetItems(items), @@ -146,18 +152,25 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if !c.open { return c, nil // If completions are not open, do nothing } - cmd := c.list.Filter(msg.Query) - c.height = max(min(10, len(c.list.Items())), 1) - return c, tea.Batch( - cmd, - c.list.SetSize(c.width, c.height), - ) + var cmds []tea.Cmd + cmds = append(cmds, c.list.Filter(msg.Query)) + itemsLen := len(c.list.Items()) + c.height = max(min(maxCompletionsHeight, itemsLen), 1) + cmds = append(cmds, c.list.SetSize(c.width, c.height)) + if itemsLen == 0 { + // Close completions if no items match the query + cmds = append(cmds, util.CmdHandler(CloseCompletionsMsg{})) + } + return c, tea.Batch(cmds...) } return c, nil } // View implements Completions. func (c *completionsCmp) View() string { + if !c.open { + return "" + } if len(c.list.Items()) == 0 { return c.style().Render("No completions found") } diff --git a/internal/tui/components/completions/item.go b/internal/tui/components/completions/item.go index d1b18a75ba1591a52524713d228a7f8b24fa1c96..414ad94b9ffaae3792f80169feb4cdfff9a71d64 100644 --- a/internal/tui/components/completions/item.go +++ b/internal/tui/components/completions/item.go @@ -90,6 +90,7 @@ func (c *completionItemCmp) View() string { if c.bgColor != nil { titleStyle = titleStyle.Background(c.bgColor) titleMatchStyle = titleMatchStyle.Background(c.bgColor) + itemStyle = itemStyle.Background(c.bgColor) } if c.focus { diff --git a/internal/tui/components/completions/keys.go b/internal/tui/components/completions/keys.go index fee3a0e574ab926cb4e80d02c0d9d19c0e614edd..530b429fe32ffd89d73c6cec1723c27de1ddd459 100644 --- a/internal/tui/components/completions/keys.go +++ b/internal/tui/components/completions/keys.go @@ -22,7 +22,7 @@ func DefaultKeyMap() KeyMap { key.WithHelp("up", "move up"), ), Select: key.NewBinding( - key.WithKeys("enter"), + key.WithKeys("enter", "tab", "ctrl+y"), key.WithHelp("enter", "select"), ), Cancel: key.NewBinding( diff --git a/internal/tui/components/core/helpers.go b/internal/tui/components/core/core.go similarity index 74% rename from internal/tui/components/core/helpers.go rename to internal/tui/components/core/core.go index 1c2c05a6229b98222d870694e726069bfc9c6e92..1db79e954350a11a4a843797b07a091736a1cae9 100644 --- a/internal/tui/components/core/helpers.go +++ b/internal/tui/components/core/core.go @@ -5,12 +5,40 @@ import ( "strings" "github.com/alecthomas/chroma/v2" + "github.com/charmbracelet/bubbles/v2/help" + "github.com/charmbracelet/bubbles/v2/key" "github.com/charmbracelet/crush/internal/tui/exp/diffview" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/x/ansi" ) +type KeyMapHelp interface { + Help() help.KeyMap +} + +type simpleHelp struct { + shortList []key.Binding + fullList [][]key.Binding +} + +func NewSimpleHelp(shortList []key.Binding, fullList [][]key.Binding) help.KeyMap { + return &simpleHelp{ + shortList: shortList, + fullList: fullList, + } +} + +// FullHelp implements help.KeyMap. +func (s *simpleHelp) FullHelp() [][]key.Binding { + return s.fullList +} + +// ShortHelp implements help.KeyMap. +func (s *simpleHelp) ShortHelp() []key.Binding { + return s.shortList +} + func Section(text string, width int) string { t := styles.CurrentTheme() char := "─" @@ -23,6 +51,22 @@ func Section(text string, width int) string { return text } +func SectionWithInfo(text string, width int, info string) string { + t := styles.CurrentTheme() + char := "─" + length := lipgloss.Width(text) + 1 + remainingWidth := width - length + + if info != "" { + remainingWidth -= lipgloss.Width(info) + 1 // 1 for the space before info + } + lineStyle := t.S().Base.Foreground(t.Border) + if remainingWidth > 0 { + text = text + " " + lineStyle.Render(strings.Repeat(char, remainingWidth)) + " " + info + } + return text +} + func Title(title string, width int) string { t := styles.CurrentTheme() char := "╱" @@ -147,6 +191,21 @@ func SelectableButtons(buttons []ButtonOpts, spacing string) string { return lipgloss.JoinHorizontal(lipgloss.Left, parts...) } +// SelectableButtonsVertical creates a vertical row of selectable buttons +func SelectableButtonsVertical(buttons []ButtonOpts, spacing int) string { + var parts []string + for i, button := range buttons { + parts = append(parts, SelectableButton(button)) + if i < len(buttons)-1 { + for j := 0; j < spacing; j++ { + parts = append(parts, "") + } + } + } + + return lipgloss.JoinVertical(lipgloss.Center, parts...) +} + func DiffFormatter() *diffview.DiffView { t := styles.CurrentTheme() formatDiff := diffview.New() diff --git a/internal/tui/components/core/layout/container.go b/internal/tui/components/core/layout/container.go deleted file mode 100644 index 9940a320e8c3a2733c8a543e09d5c25b68a103d1..0000000000000000000000000000000000000000 --- a/internal/tui/components/core/layout/container.go +++ /dev/null @@ -1,263 +0,0 @@ -package layout - -import ( - "github.com/charmbracelet/bubbles/v2/key" - tea "github.com/charmbracelet/bubbletea/v2" - "github.com/charmbracelet/crush/internal/tui/styles" - "github.com/charmbracelet/crush/internal/tui/util" - "github.com/charmbracelet/lipgloss/v2" -) - -type Container interface { - util.Model - Sizeable - Help - Positional - Focusable -} -type container struct { - width int - height int - isFocused bool - - x, y int - - content util.Model - - // Style options - paddingTop int - paddingRight int - paddingBottom int - paddingLeft int - - borderTop bool - borderRight bool - borderBottom bool - borderLeft bool - borderStyle lipgloss.Border -} - -type ContainerOption func(*container) - -func NewContainer(content util.Model, options ...ContainerOption) Container { - c := &container{ - content: content, - borderStyle: lipgloss.NormalBorder(), - } - - for _, option := range options { - option(c) - } - - return c -} - -func (c *container) Init() tea.Cmd { - return c.content.Init() -} - -func (c *container) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.KeyPressMsg: - if c.IsFocused() { - u, cmd := c.content.Update(msg) - c.content = u.(util.Model) - return c, cmd - } - return c, nil - default: - u, cmd := c.content.Update(msg) - c.content = u.(util.Model) - return c, cmd - } -} - -func (c *container) Cursor() *tea.Cursor { - if cursor, ok := c.content.(util.Cursor); ok { - return cursor.Cursor() - } - return nil -} - -func (c *container) View() string { - t := styles.CurrentTheme() - width := c.width - height := c.height - - style := t.S().Base - - // Apply border if any side is enabled - if c.borderTop || c.borderRight || c.borderBottom || c.borderLeft { - // Adjust width and height for borders - if c.borderTop { - height-- - } - if c.borderBottom { - height-- - } - if c.borderLeft { - width-- - } - if c.borderRight { - width-- - } - style = style.Border(c.borderStyle, c.borderTop, c.borderRight, c.borderBottom, c.borderLeft) - style = style.BorderBackground(t.BgBase).BorderForeground(t.Border) - } - style = style. - Width(width). - Height(height). - PaddingTop(c.paddingTop). - PaddingRight(c.paddingRight). - PaddingBottom(c.paddingBottom). - PaddingLeft(c.paddingLeft) - - contentView := c.content.View() - return style.Render(contentView) -} - -func (c *container) SetSize(width, height int) tea.Cmd { - c.width = width - c.height = height - - // If the content implements Sizeable, adjust its size to account for padding and borders - if sizeable, ok := c.content.(Sizeable); ok { - // Calculate horizontal space taken by padding and borders - horizontalSpace := c.paddingLeft + c.paddingRight - if c.borderLeft { - horizontalSpace++ - } - if c.borderRight { - horizontalSpace++ - } - - // Calculate vertical space taken by padding and borders - verticalSpace := c.paddingTop + c.paddingBottom - if c.borderTop { - verticalSpace++ - } - if c.borderBottom { - verticalSpace++ - } - - // Set content size with adjusted dimensions - contentWidth := max(0, width-horizontalSpace) - contentHeight := max(0, height-verticalSpace) - return sizeable.SetSize(contentWidth, contentHeight) - } - return nil -} - -func (c *container) GetSize() (int, int) { - return c.width, c.height -} - -func (c *container) SetPosition(x, y int) tea.Cmd { - c.x = x - c.y = y - if positionable, ok := c.content.(Positional); ok { - return positionable.SetPosition(x, y) - } - return nil -} - -func (c *container) Bindings() []key.Binding { - if b, ok := c.content.(Help); ok { - return b.Bindings() - } - return nil -} - -// Blur implements Container. -func (c *container) Blur() tea.Cmd { - c.isFocused = false - if focusable, ok := c.content.(Focusable); ok { - return focusable.Blur() - } - return nil -} - -// Focus implements Container. -func (c *container) Focus() tea.Cmd { - c.isFocused = true - if focusable, ok := c.content.(Focusable); ok { - return focusable.Focus() - } - return nil -} - -// IsFocused implements Container. -func (c *container) IsFocused() bool { - isFocused := c.isFocused - if focusable, ok := c.content.(Focusable); ok { - isFocused = isFocused || focusable.IsFocused() - } - return isFocused -} - -// Padding options -func WithPadding(top, right, bottom, left int) ContainerOption { - return func(c *container) { - c.paddingTop = top - c.paddingRight = right - c.paddingBottom = bottom - c.paddingLeft = left - } -} - -func WithPaddingAll(padding int) ContainerOption { - return WithPadding(padding, padding, padding, padding) -} - -func WithPaddingHorizontal(padding int) ContainerOption { - return func(c *container) { - c.paddingLeft = padding - c.paddingRight = padding - } -} - -func WithPaddingVertical(padding int) ContainerOption { - return func(c *container) { - c.paddingTop = padding - c.paddingBottom = padding - } -} - -func WithBorder(top, right, bottom, left bool) ContainerOption { - return func(c *container) { - c.borderTop = top - c.borderRight = right - c.borderBottom = bottom - c.borderLeft = left - } -} - -func WithBorderAll() ContainerOption { - return WithBorder(true, true, true, true) -} - -func WithBorderHorizontal() ContainerOption { - return WithBorder(true, false, true, false) -} - -func WithBorderVertical() ContainerOption { - return WithBorder(false, true, false, true) -} - -func WithBorderStyle(style lipgloss.Border) ContainerOption { - return func(c *container) { - c.borderStyle = style - } -} - -func WithRoundedBorder() ContainerOption { - return WithBorderStyle(lipgloss.RoundedBorder()) -} - -func WithThickBorder() ContainerOption { - return WithBorderStyle(lipgloss.ThickBorder()) -} - -func WithDoubleBorder() ContainerOption { - return WithBorderStyle(lipgloss.DoubleBorder()) -} diff --git a/internal/tui/components/core/layout/layout.go b/internal/tui/components/core/layout/layout.go index f5f2361d72d0d41bcb898c81f00df174571cfa72..6ceb30adf45595f5d44d4b4b48d6ac0feb87a028 100644 --- a/internal/tui/components/core/layout/layout.go +++ b/internal/tui/components/core/layout/layout.go @@ -5,6 +5,8 @@ import ( tea "github.com/charmbracelet/bubbletea/v2" ) +// TODO: move this to core + type Focusable interface { Focus() tea.Cmd Blur() tea.Cmd @@ -23,8 +25,3 @@ type Help interface { type Positional interface { SetPosition(x, y int) tea.Cmd } - -// KeyMapProvider defines an interface for types that can provide their key bindings as a slice -type KeyMapProvider interface { - KeyBindings() []key.Binding -} diff --git a/internal/tui/components/core/layout/split.go b/internal/tui/components/core/layout/split.go deleted file mode 100644 index b36e655007aaccade96f6c760763184158b9bd32..0000000000000000000000000000000000000000 --- a/internal/tui/components/core/layout/split.go +++ /dev/null @@ -1,380 +0,0 @@ -package layout - -import ( - "log/slog" - - "github.com/charmbracelet/bubbles/v2/key" - tea "github.com/charmbracelet/bubbletea/v2" - - "github.com/charmbracelet/crush/internal/tui/styles" - "github.com/charmbracelet/crush/internal/tui/util" - "github.com/charmbracelet/lipgloss/v2" -) - -type LayoutPanel string - -const ( - LeftPanel LayoutPanel = "left" - RightPanel LayoutPanel = "right" - BottomPanel LayoutPanel = "bottom" -) - -type SplitPaneLayout interface { - util.Model - Sizeable - Help - SetLeftPanel(panel Container) tea.Cmd - SetRightPanel(panel Container) tea.Cmd - SetBottomPanel(panel Container) tea.Cmd - - ClearLeftPanel() tea.Cmd - ClearRightPanel() tea.Cmd - ClearBottomPanel() tea.Cmd - - FocusPanel(panel LayoutPanel) tea.Cmd - SetOffset(x, y int) -} - -type splitPaneLayout struct { - width int - height int - xOffset int - yOffset int - - ratio float64 - verticalRatio float64 - - rightPanel Container - leftPanel Container - bottomPanel Container - - fixedBottomHeight int // Fixed height for the bottom panel, if any - fixedRightWidth int // Fixed width for the right panel, if any -} - -type SplitPaneOption func(*splitPaneLayout) - -func (s *splitPaneLayout) Init() tea.Cmd { - var cmds []tea.Cmd - - if s.leftPanel != nil { - cmds = append(cmds, s.leftPanel.Init()) - } - - if s.rightPanel != nil { - cmds = append(cmds, s.rightPanel.Init()) - } - - if s.bottomPanel != nil { - cmds = append(cmds, s.bottomPanel.Init()) - } - - return tea.Batch(cmds...) -} - -func (s *splitPaneLayout) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmds []tea.Cmd - switch msg := msg.(type) { - case tea.WindowSizeMsg: - return s, s.SetSize(msg.Width, msg.Height) - } - - if s.rightPanel != nil { - u, cmd := s.rightPanel.Update(msg) - s.rightPanel = u.(Container) - if cmd != nil { - cmds = append(cmds, cmd) - } - } - - if s.leftPanel != nil { - u, cmd := s.leftPanel.Update(msg) - s.leftPanel = u.(Container) - if cmd != nil { - cmds = append(cmds, cmd) - } - } - - if s.bottomPanel != nil { - u, cmd := s.bottomPanel.Update(msg) - s.bottomPanel = u.(Container) - if cmd != nil { - cmds = append(cmds, cmd) - } - } - - return s, tea.Batch(cmds...) -} - -func (s *splitPaneLayout) Cursor() *tea.Cursor { - if s.bottomPanel != nil { - if c, ok := s.bottomPanel.(util.Cursor); ok { - return c.Cursor() - } - } else if s.rightPanel != nil { - if c, ok := s.rightPanel.(util.Cursor); ok { - return c.Cursor() - } - } else if s.leftPanel != nil { - if c, ok := s.leftPanel.(util.Cursor); ok { - return c.Cursor() - } - } - return nil -} - -func (s *splitPaneLayout) View() string { - var topSection string - - if s.leftPanel != nil && s.rightPanel != nil { - leftView := s.leftPanel.View() - rightView := s.rightPanel.View() - topSection = lipgloss.JoinHorizontal(lipgloss.Top, leftView, rightView) - } else if s.leftPanel != nil { - topSection = s.leftPanel.View() - } else if s.rightPanel != nil { - topSection = s.rightPanel.View() - } else { - topSection = "" - } - - var finalView string - - if s.bottomPanel != nil && topSection != "" { - bottomView := s.bottomPanel.View() - finalView = lipgloss.JoinVertical(lipgloss.Left, topSection, bottomView) - } else if s.bottomPanel != nil { - finalView = s.bottomPanel.View() - } else { - finalView = topSection - } - - t := styles.CurrentTheme() - - style := t.S().Base. - Width(s.width). - Height(s.height) - - return style.Render(finalView) -} - -func (s *splitPaneLayout) SetSize(width, height int) tea.Cmd { - s.width = width - s.height = height - slog.Info("Setting split pane size", "width", width, "height", height) - - var topHeight, bottomHeight int - var cmds []tea.Cmd - if s.bottomPanel != nil { - if s.fixedBottomHeight > 0 { - bottomHeight = s.fixedBottomHeight - topHeight = height - bottomHeight - } else { - topHeight = int(float64(height) * s.verticalRatio) - bottomHeight = height - topHeight - if bottomHeight <= 0 { - bottomHeight = 2 - topHeight = height - bottomHeight - } - } - } else { - topHeight = height - bottomHeight = 0 - } - - var leftWidth, rightWidth int - if s.leftPanel != nil && s.rightPanel != nil { - if s.fixedRightWidth > 0 { - rightWidth = s.fixedRightWidth - leftWidth = width - rightWidth - } else { - leftWidth = int(float64(width) * s.ratio) - rightWidth = width - leftWidth - if rightWidth <= 0 { - rightWidth = 2 - leftWidth = width - rightWidth - } - } - } else if s.leftPanel != nil { - leftWidth = width - rightWidth = 0 - } else if s.rightPanel != nil { - leftWidth = 0 - rightWidth = width - } - - if s.leftPanel != nil { - cmd := s.leftPanel.SetSize(leftWidth, topHeight) - cmds = append(cmds, cmd) - if positional, ok := s.leftPanel.(Positional); ok { - cmds = append(cmds, positional.SetPosition(s.xOffset, s.yOffset)) - } - } - - if s.rightPanel != nil { - cmd := s.rightPanel.SetSize(rightWidth, topHeight) - cmds = append(cmds, cmd) - if positional, ok := s.rightPanel.(Positional); ok { - cmds = append(cmds, positional.SetPosition(s.xOffset+leftWidth, s.yOffset)) - } - } - - if s.bottomPanel != nil { - cmd := s.bottomPanel.SetSize(width, bottomHeight) - cmds = append(cmds, cmd) - if positional, ok := s.bottomPanel.(Positional); ok { - cmds = append(cmds, positional.SetPosition(s.xOffset, s.yOffset+topHeight)) - } - } - return tea.Batch(cmds...) -} - -func (s *splitPaneLayout) GetSize() (int, int) { - return s.width, s.height -} - -func (s *splitPaneLayout) SetLeftPanel(panel Container) tea.Cmd { - s.leftPanel = panel - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) SetRightPanel(panel Container) tea.Cmd { - s.rightPanel = panel - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) SetBottomPanel(panel Container) tea.Cmd { - s.bottomPanel = panel - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) ClearLeftPanel() tea.Cmd { - s.leftPanel = nil - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) ClearRightPanel() tea.Cmd { - s.rightPanel = nil - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) ClearBottomPanel() tea.Cmd { - s.bottomPanel = nil - if s.width > 0 && s.height > 0 { - return s.SetSize(s.width, s.height) - } - return nil -} - -func (s *splitPaneLayout) Bindings() []key.Binding { - if s.leftPanel != nil { - if b, ok := s.leftPanel.(Help); ok && s.leftPanel.IsFocused() { - return b.Bindings() - } - } - if s.rightPanel != nil { - if b, ok := s.rightPanel.(Help); ok && s.rightPanel.IsFocused() { - return b.Bindings() - } - } - if s.bottomPanel != nil { - if b, ok := s.bottomPanel.(Help); ok && s.bottomPanel.IsFocused() { - return b.Bindings() - } - } - return nil -} - -func (s *splitPaneLayout) FocusPanel(panel LayoutPanel) tea.Cmd { - panels := map[LayoutPanel]Container{ - LeftPanel: s.leftPanel, - RightPanel: s.rightPanel, - BottomPanel: s.bottomPanel, - } - var cmds []tea.Cmd - for p, container := range panels { - if container == nil { - continue - } - if p == panel { - cmds = append(cmds, container.Focus()) - } else { - cmds = append(cmds, container.Blur()) - } - } - return tea.Batch(cmds...) -} - -// SetOffset implements SplitPaneLayout. -func (s *splitPaneLayout) SetOffset(x int, y int) { - s.xOffset = x - s.yOffset = y -} - -func NewSplitPane(options ...SplitPaneOption) SplitPaneLayout { - layout := &splitPaneLayout{ - ratio: 0.8, - verticalRatio: 0.92, // Default 90% for top section, 10% for bottom - } - for _, option := range options { - option(layout) - } - return layout -} - -func WithLeftPanel(panel Container) SplitPaneOption { - return func(s *splitPaneLayout) { - s.leftPanel = panel - } -} - -func WithRightPanel(panel Container) SplitPaneOption { - return func(s *splitPaneLayout) { - s.rightPanel = panel - } -} - -func WithRatio(ratio float64) SplitPaneOption { - return func(s *splitPaneLayout) { - s.ratio = ratio - } -} - -func WithBottomPanel(panel Container) SplitPaneOption { - return func(s *splitPaneLayout) { - s.bottomPanel = panel - } -} - -func WithVerticalRatio(ratio float64) SplitPaneOption { - return func(s *splitPaneLayout) { - s.verticalRatio = ratio - } -} - -func WithFixedBottomHeight(height int) SplitPaneOption { - return func(s *splitPaneLayout) { - s.fixedBottomHeight = height - } -} - -func WithFixedRightWidth(width int) SplitPaneOption { - return func(s *splitPaneLayout) { - s.fixedRightWidth = width - } -} diff --git a/internal/tui/components/core/list/list.go b/internal/tui/components/core/list/list.go index ca7a0ebbac20076f662f318314355acca7f8173a..3f99eda5d979e72f0497a120e056df10aca228c3 100644 --- a/internal/tui/components/core/list/list.go +++ b/internal/tui/components/core/list/list.go @@ -41,6 +41,8 @@ type ListModel interface { SelectedIndex() int // Get the index of the currently selected item SetSelected(int) tea.Cmd // Set the selected item by index and scroll to it Filter(string) tea.Cmd // Filter items based on a search term + SetFilterPlaceholder(string) // Set the placeholder text for the filter input + Cursor() *tea.Cursor // Get the current cursor position in the filter input } // HasAnim interface identifies items that support animation. @@ -1363,3 +1365,7 @@ func (m *model) Focus() tea.Cmd { func (m *model) IsFocused() bool { return m.isFocused } + +func (m *model) SetFilterPlaceholder(placeholder string) { + m.input.Placeholder = placeholder +} diff --git a/internal/tui/components/core/status/status.go b/internal/tui/components/core/status/status.go index bd87b013e86780d6a52a17f648d5f7479c7d350a..b7339705649f24129dc61c28471f23044ba7dafb 100644 --- a/internal/tui/components/core/status/status.go +++ b/internal/tui/components/core/status/status.go @@ -98,13 +98,12 @@ func (m *statusCmp) SetKeyMap(keyMap help.KeyMap) { m.keyMap = keyMap } -func NewStatusCmp(keyMap help.KeyMap) StatusCmp { +func NewStatusCmp() StatusCmp { t := styles.CurrentTheme() help := help.New() help.Styles = t.S().Help return &statusCmp{ messageTTL: 5 * time.Second, help: help, - keyMap: keyMap, } } diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 140996fdd59af21e27e6eb4017ca5cca847cb0d9..10cdbbd539f06836550b7da6a857d35db3becd74 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -6,6 +6,7 @@ import ( tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/crush/internal/llm/prompt" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/completions" "github.com/charmbracelet/crush/internal/tui/components/core" @@ -239,16 +240,8 @@ func (c *commandDialogCmp) defaultCommands() []Command { Title: "Initialize Project", Description: "Create/Update the CRUSH.md memory file", Handler: func(cmd Command) tea.Cmd { - prompt := `Please analyze this codebase and create a CRUSH.md file containing: - 1. Build/lint/test commands - especially for running a single test - 2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc. - - The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long. - If there's already a CRUSH.md, improve it. - If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them. - Add the .crush directory to the .gitignore file if it's not already there.` return util.CmdHandler(chat.SendMsg{ - Text: prompt, + Text: prompt.Initialize(), }) }, }, diff --git a/internal/tui/components/dialogs/commands/item.go b/internal/tui/components/dialogs/commands/item.go index 97668694e61c5c89e38b9034a249b6cd4a46f37e..990423958cdc41ab4a04afafed71762ab5e7f122 100644 --- a/internal/tui/components/dialogs/commands/item.go +++ b/internal/tui/components/dialogs/commands/item.go @@ -14,11 +14,12 @@ type ItemSection interface { util.Model layout.Sizeable list.SectionHeader + SetInfo(info string) } type itemSectionModel struct { - width int - title string - noPadding bool // No padding for the section header + width int + title string + info string } func NewItemSection(title string) ItemSection { @@ -40,7 +41,14 @@ func (m *itemSectionModel) View() string { title := ansi.Truncate(m.title, m.width-2, "…") style := t.S().Base.Padding(1, 1, 0, 1) title = t.S().Muted.Render(title) - return style.Render(core.Section(title, m.width-2)) + section := "" + if m.info != "" { + section = core.SectionWithInfo(title, m.width-2, m.info) + } else { + section = core.Section(title, m.width-2) + } + + return style.Render(section) } func (m *itemSectionModel) GetSize() (int, int) { @@ -55,3 +63,7 @@ func (m *itemSectionModel) SetSize(width int, height int) tea.Cmd { func (m *itemSectionModel) IsSectionHeader() bool { return true } + +func (m *itemSectionModel) SetInfo(info string) { + m.info = info +} diff --git a/internal/tui/components/dialogs/init/init.go b/internal/tui/components/dialogs/init/init.go deleted file mode 100644 index 66e26bd99f86e5b49fca11ca3daca2f74d5b8656..0000000000000000000000000000000000000000 --- a/internal/tui/components/dialogs/init/init.go +++ /dev/null @@ -1,214 +0,0 @@ -package init - -import ( - "github.com/charmbracelet/bubbles/v2/key" - tea "github.com/charmbracelet/bubbletea/v2" - "github.com/charmbracelet/lipgloss/v2" - - "github.com/charmbracelet/crush/internal/config" - cmpChat "github.com/charmbracelet/crush/internal/tui/components/chat" - "github.com/charmbracelet/crush/internal/tui/components/core" - "github.com/charmbracelet/crush/internal/tui/components/dialogs" - "github.com/charmbracelet/crush/internal/tui/styles" - "github.com/charmbracelet/crush/internal/tui/util" -) - -const InitDialogID dialogs.DialogID = "init" - -// InitDialogCmp is a component that asks the user if they want to initialize the project. -type InitDialogCmp interface { - dialogs.DialogModel -} - -type initDialogCmp struct { - wWidth, wHeight int - width, height int - selected int - keyMap KeyMap -} - -// NewInitDialogCmp creates a new InitDialogCmp. -func NewInitDialogCmp() InitDialogCmp { - return &initDialogCmp{ - selected: 0, - keyMap: DefaultKeyMap(), - } -} - -// Init implements tea.Model. -func (m *initDialogCmp) Init() tea.Cmd { - return nil -} - -// Update implements tea.Model. -func (m *initDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - m.wWidth = msg.Width - m.wHeight = msg.Height - cmd := m.SetSize() - return m, cmd - case tea.KeyPressMsg: - switch { - case key.Matches(msg, m.keyMap.Close): - return m, tea.Batch( - util.CmdHandler(dialogs.CloseDialogMsg{}), - m.handleInitialization(false), - ) - case key.Matches(msg, m.keyMap.ChangeSelection): - m.selected = (m.selected + 1) % 2 - return m, nil - case key.Matches(msg, m.keyMap.Select): - return m, tea.Batch( - util.CmdHandler(dialogs.CloseDialogMsg{}), - m.handleInitialization(m.selected == 0), - ) - case key.Matches(msg, m.keyMap.Y): - return m, tea.Batch( - util.CmdHandler(dialogs.CloseDialogMsg{}), - m.handleInitialization(true), - ) - case key.Matches(msg, m.keyMap.N): - return m, tea.Batch( - util.CmdHandler(dialogs.CloseDialogMsg{}), - m.handleInitialization(false), - ) - } - } - return m, nil -} - -func (m *initDialogCmp) renderButtons() string { - t := styles.CurrentTheme() - baseStyle := t.S().Base - - buttons := []core.ButtonOpts{ - { - Text: "Yes", - UnderlineIndex: 0, // "Y" - Selected: m.selected == 0, - }, - { - Text: "No", - UnderlineIndex: 0, // "N" - Selected: m.selected == 1, - }, - } - - content := core.SelectableButtons(buttons, " ") - - return baseStyle.AlignHorizontal(lipgloss.Right).Width(m.width - 4).Render(content) -} - -func (m *initDialogCmp) renderContent() string { - t := styles.CurrentTheme() - baseStyle := t.S().Base - - explanation := t.S().Text. - Width(m.width - 4). - Render("Initialization generates a new CRUSH.md file that contains information about your codebase, this file serves as memory for each project, you can freely add to it to help the agents be better at their job.") - - question := t.S().Text. - Width(m.width - 4). - Render("Would you like to initialize this project?") - - return baseStyle.Render(lipgloss.JoinVertical( - lipgloss.Left, - explanation, - "", - question, - )) -} - -func (m *initDialogCmp) render() string { - t := styles.CurrentTheme() - baseStyle := t.S().Base - title := core.Title("Initialize Project", m.width-4) - - content := m.renderContent() - buttons := m.renderButtons() - - dialogContent := lipgloss.JoinVertical( - lipgloss.Top, - title, - "", - content, - "", - buttons, - "", - ) - - return baseStyle. - Padding(0, 1). - Border(lipgloss.RoundedBorder()). - BorderForeground(t.BorderFocus). - Width(m.width). - Render(dialogContent) -} - -// View implements tea.Model. -func (m *initDialogCmp) View() string { - return m.render() -} - -// SetSize sets the size of the component. -func (m *initDialogCmp) SetSize() tea.Cmd { - m.width = min(90, m.wWidth) - m.height = min(15, m.wHeight) - return nil -} - -// ID implements DialogModel. -func (m *initDialogCmp) ID() dialogs.DialogID { - return InitDialogID -} - -// Position implements DialogModel. -func (m *initDialogCmp) Position() (int, int) { - row := (m.wHeight / 2) - (m.height / 2) - col := (m.wWidth / 2) - (m.width / 2) - return row, col -} - -// handleInitialization handles the initialization logic when the dialog is closed. -func (m *initDialogCmp) handleInitialization(initialize bool) tea.Cmd { - if initialize { - // Run the initialization command - prompt := `Please analyze this codebase and create a CRUSH.md file containing: -1. Build/lint/test commands - especially for running a single test -2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc. - -The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long. -If there's already a CRUSH.md, improve it. -If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them. -Add the .crush directory to the .gitignore file if it's not already there.` - - // Mark the project as initialized - if err := config.MarkProjectInitialized(); err != nil { - return util.ReportError(err) - } - - return tea.Sequence( - util.CmdHandler(cmpChat.SessionClearedMsg{}), - util.CmdHandler(cmpChat.SendMsg{ - Text: prompt, - }), - ) - } else { - // Mark the project as initialized without running the command - if err := config.MarkProjectInitialized(); err != nil { - return util.ReportError(err) - } - } - return nil -} - -// CloseInitDialogMsg is a message that is sent when the init dialog is closed. -type CloseInitDialogMsg struct { - Initialize bool -} - -// ShowInitDialogMsg is a message that is sent to show the init dialog. -type ShowInitDialogMsg struct { - Show bool -} diff --git a/internal/tui/components/dialogs/init/keys.go b/internal/tui/components/dialogs/init/keys.go deleted file mode 100644 index afd82d45ea8b47630c2d5ed1450419ae8d4b4c19..0000000000000000000000000000000000000000 --- a/internal/tui/components/dialogs/init/keys.go +++ /dev/null @@ -1,69 +0,0 @@ -package init - -import ( - "github.com/charmbracelet/bubbles/v2/key" -) - -type KeyMap struct { - ChangeSelection, - Select, - Y, - N, - Close key.Binding -} - -func DefaultKeyMap() KeyMap { - return KeyMap{ - ChangeSelection: key.NewBinding( - key.WithKeys("tab", "left", "right", "h", "l"), - key.WithHelp("tab/←/→", "toggle selection"), - ), - Select: key.NewBinding( - key.WithKeys("enter"), - key.WithHelp("enter", "confirm"), - ), - Y: key.NewBinding( - key.WithKeys("y"), - key.WithHelp("y", "yes"), - ), - N: key.NewBinding( - key.WithKeys("n"), - key.WithHelp("n", "no"), - ), - Close: key.NewBinding( - key.WithKeys("esc"), - key.WithHelp("esc", "cancel"), - ), - } -} - -// KeyBindings implements layout.KeyMapProvider -func (k KeyMap) KeyBindings() []key.Binding { - return []key.Binding{ - k.ChangeSelection, - k.Select, - k.Y, - k.N, - k.Close, - } -} - -// FullHelp implements help.KeyMap. -func (k KeyMap) FullHelp() [][]key.Binding { - m := [][]key.Binding{} - slice := k.KeyBindings() - for i := 0; i < len(slice); i += 4 { - end := min(i+4, len(slice)) - m = append(m, slice[i:end]) - } - return m -} - -// ShortHelp implements help.KeyMap. -func (k KeyMap) ShortHelp() []key.Binding { - return []key.Binding{ - k.ChangeSelection, - k.Select, - k.Close, - } -} diff --git a/internal/tui/components/dialogs/models/apikey.go b/internal/tui/components/dialogs/models/apikey.go new file mode 100644 index 0000000000000000000000000000000000000000..d5aa034d133d2e4d5cbe676aed0fb7e1edde487c --- /dev/null +++ b/internal/tui/components/dialogs/models/apikey.go @@ -0,0 +1,96 @@ +package models + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/bubbles/v2/textinput" + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/tui/styles" + "github.com/charmbracelet/lipgloss/v2" +) + +type APIKeyInput struct { + input textinput.Model + width int + height int + providerName string +} + +func NewAPIKeyInput() *APIKeyInput { + t := styles.CurrentTheme() + + ti := textinput.New() + ti.Placeholder = "Enter your API key..." + ti.SetWidth(50) + ti.SetVirtualCursor(false) + ti.Prompt = "> " + ti.SetStyles(t.S().TextInput) + ti.Focus() + + return &APIKeyInput{ + input: ti, + width: 60, + providerName: "Provider", + } +} + +func (a *APIKeyInput) SetProviderName(name string) { + a.providerName = name +} + +func (a *APIKeyInput) Init() tea.Cmd { + return textinput.Blink +} + +func (a *APIKeyInput) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + a.width = msg.Width + a.height = msg.Height + } + + var cmd tea.Cmd + a.input, cmd = a.input.Update(msg) + return a, cmd +} + +func (a *APIKeyInput) View() string { + t := styles.CurrentTheme() + + title := t.S().Base. + Foreground(t.Primary). + Bold(true). + Render(fmt.Sprintf("Enter your %s API Key", a.providerName)) + + inputView := a.input.View() + + dataPath := config.GlobalConfigData() + dataPath = strings.Replace(dataPath, config.HomeDir(), "~", 1) + helpText := t.S().Muted. + Render(fmt.Sprintf("This will be written to the global configuration: %s", dataPath)) + + content := lipgloss.JoinVertical( + lipgloss.Left, + title, + "", + inputView, + "", + helpText, + ) + + return content +} + +func (a *APIKeyInput) Cursor() *tea.Cursor { + cursor := a.input.Cursor() + if cursor != nil { + cursor.Y += 2 // Adjust for title and spacing + } + return cursor +} + +func (a *APIKeyInput) Value() string { + return a.input.Value() +} diff --git a/internal/tui/components/dialogs/models/list.go b/internal/tui/components/dialogs/models/list.go new file mode 100644 index 0000000000000000000000000000000000000000..8425b8f2c04569749a33867fb7e14e4b628d019e --- /dev/null +++ b/internal/tui/components/dialogs/models/list.go @@ -0,0 +1,202 @@ +package models + +import ( + "fmt" + "slices" + + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/fur/provider" + "github.com/charmbracelet/crush/internal/tui/components/completions" + "github.com/charmbracelet/crush/internal/tui/components/core/list" + "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" + "github.com/charmbracelet/crush/internal/tui/styles" + "github.com/charmbracelet/crush/internal/tui/util" + "github.com/charmbracelet/lipgloss/v2" +) + +type ModelListComponent struct { + list list.ListModel + modelType int + providers []provider.Provider +} + +func NewModelListComponent(keyMap list.KeyMap, inputStyle lipgloss.Style, inputPlaceholder string) *ModelListComponent { + modelList := list.New( + list.WithFilterable(true), + list.WithKeyMap(keyMap), + list.WithInputStyle(inputStyle), + list.WithFilterPlaceholder(inputPlaceholder), + list.WithWrapNavigation(true), + ) + + return &ModelListComponent{ + list: modelList, + modelType: LargeModelType, + } +} + +func (m *ModelListComponent) Init() tea.Cmd { + var cmds []tea.Cmd + if len(m.providers) == 0 { + providers, err := config.Providers() + m.providers = providers + if err != nil { + cmds = append(cmds, util.ReportError(err)) + } + } + cmds = append(cmds, m.list.Init(), m.SetModelType(m.modelType)) + return tea.Batch(cmds...) +} + +func (m *ModelListComponent) Update(msg tea.Msg) (*ModelListComponent, tea.Cmd) { + u, cmd := m.list.Update(msg) + m.list = u.(list.ListModel) + return m, cmd +} + +func (m *ModelListComponent) View() string { + return m.list.View() +} + +func (m *ModelListComponent) Cursor() *tea.Cursor { + return m.list.Cursor() +} + +func (m *ModelListComponent) SetSize(width, height int) tea.Cmd { + return m.list.SetSize(width, height) +} + +func (m *ModelListComponent) Items() []util.Model { + return m.list.Items() +} + +func (m *ModelListComponent) SelectedIndex() int { + return m.list.SelectedIndex() +} + +func (m *ModelListComponent) SetModelType(modelType int) tea.Cmd { + t := styles.CurrentTheme() + m.modelType = modelType + + modelItems := []util.Model{} + selectIndex := 0 + + cfg := config.Get() + var currentModel config.SelectedModel + if m.modelType == LargeModelType { + currentModel = cfg.Models[config.SelectedModelTypeLarge] + } else { + currentModel = cfg.Models[config.SelectedModelTypeSmall] + } + + configuredIcon := t.S().Base.Foreground(t.Success).Render(styles.CheckIcon) + configured := fmt.Sprintf("%s %s", configuredIcon, t.S().Subtle.Render("Configured")) + + // Create a map to track which providers we've already added + addedProviders := make(map[string]bool) + + // First, add any configured providers that are not in the known providers list + // These should appear at the top of the list + knownProviders := provider.KnownProviders() + for providerID, providerConfig := range cfg.Providers { + if providerConfig.Disable { + continue + } + + // Check if this provider is not in the known providers list + if !slices.Contains(knownProviders, provider.InferenceProvider(providerID)) { + // Convert config provider to provider.Provider format + configProvider := provider.Provider{ + Name: providerConfig.Name, + ID: provider.InferenceProvider(providerID), + Models: make([]provider.Model, len(providerConfig.Models)), + } + + // Convert models + for i, model := range providerConfig.Models { + configProvider.Models[i] = provider.Model{ + ID: model.ID, + Model: model.Model, + CostPer1MIn: model.CostPer1MIn, + CostPer1MOut: model.CostPer1MOut, + CostPer1MInCached: model.CostPer1MInCached, + CostPer1MOutCached: model.CostPer1MOutCached, + ContextWindow: model.ContextWindow, + DefaultMaxTokens: model.DefaultMaxTokens, + CanReason: model.CanReason, + HasReasoningEffort: model.HasReasoningEffort, + DefaultReasoningEffort: model.DefaultReasoningEffort, + SupportsImages: model.SupportsImages, + } + } + + // Add this unknown provider to the list + name := configProvider.Name + if name == "" { + name = string(configProvider.ID) + } + section := commands.NewItemSection(name) + section.SetInfo(configured) + modelItems = append(modelItems, section) + for _, model := range configProvider.Models { + modelItems = append(modelItems, completions.NewCompletionItem(model.Model, ModelOption{ + Provider: configProvider, + Model: model, + })) + if model.ID == currentModel.Model && string(configProvider.ID) == currentModel.Provider { + selectIndex = len(modelItems) - 1 // Set the selected index to the current model + } + } + addedProviders[providerID] = true + } + } + + // Then add the known providers from the predefined list + for _, provider := range m.providers { + // Skip if we already added this provider as an unknown provider + if addedProviders[string(provider.ID)] { + continue + } + + // Check if this provider is configured and not disabled + if providerConfig, exists := cfg.Providers[string(provider.ID)]; exists && providerConfig.Disable { + continue + } + + name := provider.Name + if name == "" { + name = string(provider.ID) + } + + section := commands.NewItemSection(name) + if _, ok := cfg.Providers[string(provider.ID)]; ok { + section.SetInfo(configured) + } + modelItems = append(modelItems, section) + for _, model := range provider.Models { + modelItems = append(modelItems, completions.NewCompletionItem(model.Model, ModelOption{ + Provider: provider, + Model: model, + })) + if model.ID == currentModel.Model && string(provider.ID) == currentModel.Provider { + selectIndex = len(modelItems) - 1 // Set the selected index to the current model + } + } + } + + return tea.Sequence(m.list.SetItems(modelItems), m.list.SetSelected(selectIndex)) +} + +// GetModelType returns the current model type +func (m *ModelListComponent) GetModelType() int { + return m.modelType +} + +func (m *ModelListComponent) SetInputPlaceholder(placeholder string) { + m.list.SetFilterPlaceholder(placeholder) +} + +func (m *ModelListComponent) SetProviders(providers []provider.Provider) { + m.providers = providers +} diff --git a/internal/tui/components/dialogs/models/models.go b/internal/tui/components/dialogs/models/models.go index b108a19af789d50ed6f3f63538bc8ce08a4fb21a..a4cb9bd47e81229b343d65660174f843a98503a8 100644 --- a/internal/tui/components/dialogs/models/models.go +++ b/internal/tui/components/dialogs/models/models.go @@ -1,8 +1,6 @@ package models import ( - "slices" - "github.com/charmbracelet/bubbles/v2/help" "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" @@ -12,7 +10,6 @@ import ( "github.com/charmbracelet/crush/internal/tui/components/core" "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/components/dialogs" - "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" @@ -27,6 +24,9 @@ const ( const ( LargeModelType int = iota SmallModelType + + largeModelInputPlaceholder = "Choose a model for large, complex tasks" + smallModelInputPlaceholder = "Choose a model for small, simple tasks" ) // ModelSelectedMsg is sent when a model is selected @@ -53,10 +53,9 @@ type modelDialogCmp struct { wWidth int wHeight int - modelList list.ListModel + modelList *ModelListComponent keyMap KeyMap help help.Model - modelType int } func NewModelDialogCmp() ModelDialog { @@ -75,12 +74,7 @@ func NewModelDialogCmp() ModelDialog { t := styles.CurrentTheme() inputStyle := t.S().Base.Padding(0, 1, 0, 1) - modelList := list.New( - list.WithFilterable(true), - list.WithKeyMap(listKeyMap), - list.WithInputStyle(inputStyle), - list.WithWrapNavigation(true), - ) + modelList := NewModelListComponent(listKeyMap, inputStyle, "Choose a model for large, complex tasks") help := help.New() help.Styles = t.S().Help @@ -89,12 +83,10 @@ func NewModelDialogCmp() ModelDialog { width: defaultWidth, keyMap: DefaultKeyMap(), help: help, - modelType: LargeModelType, } } func (m *modelDialogCmp) Init() tea.Cmd { - m.SetModelType(m.modelType) return m.modelList.Init() } @@ -103,7 +95,6 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: m.wWidth = msg.Width m.wHeight = msg.Height - m.SetModelType(m.modelType) return m, m.modelList.SetSize(m.listWidth(), m.listHeight()) case tea.KeyPressMsg: switch { @@ -116,7 +107,7 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { selectedItem := items[selectedItemInx].(completions.CompletionItem).Value().(ModelOption) var modelType config.SelectedModelType - if m.modelType == LargeModelType { + if m.modelList.GetModelType() == LargeModelType { modelType = config.SelectedModelTypeLarge } else { modelType = config.SelectedModelTypeSmall @@ -133,16 +124,18 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { }), ) case key.Matches(msg, m.keyMap.Tab): - if m.modelType == LargeModelType { - return m, m.SetModelType(SmallModelType) + if m.modelList.GetModelType() == LargeModelType { + m.modelList.SetInputPlaceholder(smallModelInputPlaceholder) + return m, m.modelList.SetModelType(SmallModelType) } else { - return m, m.SetModelType(LargeModelType) + m.modelList.SetInputPlaceholder(largeModelInputPlaceholder) + return m, m.modelList.SetModelType(LargeModelType) } case key.Matches(msg, m.keyMap.Close): return m, util.CmdHandler(dialogs.CloseDialogMsg{}) default: u, cmd := m.modelList.Update(msg) - m.modelList = u.(list.ListModel) + m.modelList = u return m, cmd } } @@ -164,12 +157,10 @@ func (m *modelDialogCmp) View() string { } func (m *modelDialogCmp) Cursor() *tea.Cursor { - if cursor, ok := m.modelList.(util.Cursor); ok { - cursor := cursor.Cursor() - if cursor != nil { - cursor = m.moveCursor(cursor) - return cursor - } + cursor := m.modelList.Cursor() + if cursor != nil { + cursor = m.moveCursor(cursor) + return cursor } return nil } @@ -187,7 +178,8 @@ func (m *modelDialogCmp) listWidth() int { } func (m *modelDialogCmp) listHeight() int { - listHeigh := len(m.modelList.Items()) + 2 + 4 // height based on items + 2 for the input + 4 for the sections + items := m.modelList.Items() + listHeigh := len(items) + 2 + 4 return min(listHeigh, m.wHeight/2) } @@ -215,115 +207,8 @@ func (m *modelDialogCmp) modelTypeRadio() string { choices := []string{"Large Task", "Small Task"} iconSelected := "◉" iconUnselected := "○" - if m.modelType == LargeModelType { + if m.modelList.GetModelType() == LargeModelType { return t.S().Base.Foreground(t.FgHalfMuted).Render(iconSelected + " " + choices[0] + " " + iconUnselected + " " + choices[1]) } return t.S().Base.Foreground(t.FgHalfMuted).Render(iconUnselected + " " + choices[0] + " " + iconSelected + " " + choices[1]) } - -func (m *modelDialogCmp) SetModelType(modelType int) tea.Cmd { - m.modelType = modelType - - providers, err := config.Providers() - if err != nil { - return util.ReportError(err) - } - - modelItems := []util.Model{} - selectIndex := 0 - - cfg := config.Get() - var currentModel config.SelectedModel - if m.modelType == LargeModelType { - currentModel = cfg.Models[config.SelectedModelTypeLarge] - } else { - currentModel = cfg.Models[config.SelectedModelTypeSmall] - } - - // Create a map to track which providers we've already added - addedProviders := make(map[string]bool) - - // First, add any configured providers that are not in the known providers list - // These should appear at the top of the list - knownProviders := provider.KnownProviders() - for providerID, providerConfig := range cfg.Providers { - if providerConfig.Disable { - continue - } - - // Check if this provider is not in the known providers list - if !slices.Contains(knownProviders, provider.InferenceProvider(providerID)) { - // Convert config provider to provider.Provider format - configProvider := provider.Provider{ - Name: string(providerID), // Use provider ID as name for unknown providers - ID: provider.InferenceProvider(providerID), - Models: make([]provider.Model, len(providerConfig.Models)), - } - - // Convert models - for i, model := range providerConfig.Models { - configProvider.Models[i] = provider.Model{ - ID: model.ID, - Model: model.Model, - CostPer1MIn: model.CostPer1MIn, - CostPer1MOut: model.CostPer1MOut, - CostPer1MInCached: model.CostPer1MInCached, - CostPer1MOutCached: model.CostPer1MOutCached, - ContextWindow: model.ContextWindow, - DefaultMaxTokens: model.DefaultMaxTokens, - CanReason: model.CanReason, - HasReasoningEffort: model.HasReasoningEffort, - DefaultReasoningEffort: model.DefaultReasoningEffort, - SupportsImages: model.SupportsImages, - } - } - - // Add this unknown provider to the list - name := configProvider.Name - if name == "" { - name = string(configProvider.ID) - } - modelItems = append(modelItems, commands.NewItemSection(name)) - for _, model := range configProvider.Models { - modelItems = append(modelItems, completions.NewCompletionItem(model.Model, ModelOption{ - Provider: configProvider, - Model: model, - })) - if model.ID == currentModel.Model && string(configProvider.ID) == currentModel.Provider { - selectIndex = len(modelItems) - 1 // Set the selected index to the current model - } - } - addedProviders[providerID] = true - } - } - - // Then add the known providers from the predefined list - for _, provider := range providers { - // Skip if we already added this provider as an unknown provider - if addedProviders[string(provider.ID)] { - continue - } - - // Check if this provider is configured and not disabled - if providerConfig, exists := cfg.Providers[string(provider.ID)]; exists && providerConfig.Disable { - continue - } - - name := provider.Name - if name == "" { - name = string(provider.ID) - } - modelItems = append(modelItems, commands.NewItemSection(name)) - for _, model := range provider.Models { - modelItems = append(modelItems, completions.NewCompletionItem(model.Model, ModelOption{ - Provider: provider, - Model: model, - })) - if model.ID == currentModel.Model && string(provider.ID) == currentModel.Provider { - selectIndex = len(modelItems) - 1 // Set the selected index to the current model - } - } - } - - return tea.Sequence(m.modelList.SetItems(modelItems), m.modelList.SetSelected(selectIndex)) -} diff --git a/internal/tui/components/dialogs/permissions/keys.go b/internal/tui/components/dialogs/permissions/keys.go index 8964e4d4894586e073a4d3c72e029749310a5fef..0065daa9733a5bb649e5364f56fea89fdeb466f6 100644 --- a/internal/tui/components/dialogs/permissions/keys.go +++ b/internal/tui/components/dialogs/permissions/keys.go @@ -109,9 +109,5 @@ func (k KeyMap) ShortHelp() []key.Binding { key.WithKeys("shift+left", "shift+down", "shift+up", "shift+right"), key.WithHelp("shift+←↓↑→", "scroll"), ), - key.NewBinding( - key.WithKeys("shift+h", "shift+j", "shift+k", "shift+l"), - key.WithHelp("shift+hjkl", "scroll"), - ), } } diff --git a/internal/tui/components/dialogs/permissions/permissions.go b/internal/tui/components/dialogs/permissions/permissions.go index e7f6dd517b1504e2f938c9310e95b8a7086cbbf0..6bac6e58b37a99b376ad936bbf19f541b999eb4b 100644 --- a/internal/tui/components/dialogs/permissions/permissions.go +++ b/internal/tui/components/dialogs/permissions/permissions.go @@ -199,6 +199,13 @@ func (p *permissionDialogCmp) renderButtons() string { } content := core.SelectableButtons(buttons, " ") + if lipgloss.Width(content) > p.width-4 { + content = core.SelectableButtonsVertical(buttons, 1) + return baseStyle.AlignVertical(lipgloss.Center). + AlignHorizontal(lipgloss.Center). + Width(p.width - 4). + Render(content) + } return baseStyle.AlignHorizontal(lipgloss.Right).Width(p.width - 4).Render(content) } @@ -382,19 +389,10 @@ func (p *permissionDialogCmp) generateFetchContent() string { t := styles.CurrentTheme() baseStyle := t.S().Base.Background(t.BgSubtle) if pr, ok := p.permission.Params.(tools.FetchPermissionsParams); ok { - content := fmt.Sprintf("```bash\n%s\n```", pr.URL) - - // Use the cache for markdown rendering - renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) { - r := styles.GetMarkdownRenderer(p.width - 4) - s, err := r.Render(content) - return s, err - }) - finalContent := baseStyle. + Padding(1, 2). Width(p.contentViewPort.Width()). - Render(renderedContent) - + Render(pr.URL) return finalContent } return "" @@ -452,8 +450,8 @@ func (p *permissionDialogCmp) render() string { if p.supportsDiffView() { contentHelp = help.New().View(p.keyMap) } - // Calculate content height dynamically based on window size + // Calculate content height dynamically based on window size strs := []string{ title, "", @@ -491,7 +489,7 @@ func (p *permissionDialogCmp) SetSize() tea.Cmd { switch p.permission.ToolName { case tools.BashToolName: - p.width = int(float64(p.wWidth) * 0.4) + p.width = int(float64(p.wWidth) * 0.8) p.height = int(float64(p.wHeight) * 0.3) case tools.EditToolName: p.width = int(float64(p.wWidth) * 0.8) @@ -500,7 +498,7 @@ func (p *permissionDialogCmp) SetSize() tea.Cmd { p.width = int(float64(p.wWidth) * 0.8) p.height = int(float64(p.wHeight) * 0.8) case tools.FetchToolName: - p.width = int(float64(p.wWidth) * 0.4) + p.width = int(float64(p.wWidth) * 0.8) p.height = int(float64(p.wHeight) * 0.3) default: p.width = int(float64(p.wWidth) * 0.7) diff --git a/internal/tui/components/logo/logo.go b/internal/tui/components/logo/logo.go index 7a063f79b7c8a9fd34507c1762b1c98842be5ac4..dbd3229e9b6c49b9f59b1a477fac9a5dc1c84d6e 100644 --- a/internal/tui/components/logo/logo.go +++ b/internal/tui/components/logo/logo.go @@ -85,7 +85,7 @@ func Render(version string, compact bool, o Opts) string { } // Right field. - rightWidth := max(15, o.Width-crushWidth-leftWidth) // 2 for the gap. + rightWidth := max(15, o.Width-crushWidth-leftWidth-2) // 2 for the gap. const stepDownAt = 0 rightField := new(strings.Builder) for i := range fieldHeight { @@ -98,7 +98,16 @@ func Render(version string, compact bool, o Opts) string { // Return the wide version. const hGap = " " - return lipgloss.JoinHorizontal(lipgloss.Top, leftField.String(), hGap, crush, hGap, rightField.String()) + logo := lipgloss.JoinHorizontal(lipgloss.Top, leftField.String(), hGap, crush, hGap, rightField.String()) + if o.Width > 0 { + // Truncate the logo to the specified width. + lines := strings.Split(logo, "\n") + for i, line := range lines { + lines[i] = ansi.Truncate(line, o.Width, "") + } + logo = strings.Join(lines, "\n") + } + return logo } // renderWord renders letterforms to fork a word. diff --git a/internal/tui/exp/diffview/diffview.go b/internal/tui/exp/diffview/diffview.go index bb51a7e505666e67fd9e914a135a0dd7632bb184..1cb56a678f51d0809c584edc1bedd73befc59966 100644 --- a/internal/tui/exp/diffview/diffview.go +++ b/internal/tui/exp/diffview/diffview.go @@ -365,7 +365,8 @@ func (dv *DiffView) renderUnified() string { shouldWrite := func() bool { return printedLines >= 0 } getContent := func(in string, ls LineStyle) (content string, leadingEllipsis bool) { - content = strings.TrimSuffix(in, "\n") + content = strings.ReplaceAll(in, "\r\n", "\n") + content = strings.TrimSuffix(content, "\n") content = dv.hightlightCode(content, ls.Code.GetBackground()) content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) content = ansi.Truncate(content, dv.codeWidth, "…") @@ -488,7 +489,8 @@ func (dv *DiffView) renderSplit() string { shouldWrite := func() bool { return printedLines >= 0 } getContent := func(in string, ls LineStyle) (content string, leadingEllipsis bool) { - content = strings.TrimSuffix(in, "\n") + content = strings.ReplaceAll(in, "\r\n", "\n") + content = strings.TrimSuffix(content, "\n") content = dv.hightlightCode(content, ls.Code.GetBackground()) content = ansi.GraphemeWidth.Cut(content, dv.xOffset, len(content)) content = ansi.Truncate(content, dv.codeWidth, "…") diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden index 698ca85f639a3611eeb3964c3be994b66ea73bb1..4d1b5fc8a73872fc833b62fd441dfc6875a44b6e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden @@ -1,16 +1,16 @@ -  …  @@ -1,13 +1,15 @@    …    -  1  package main   1  package main  -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  8   fmt.Println(getContent())   9   fmt.Println(getContent())  -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -1,13 +1,15 @@    …    +  1  package main   1  package main  +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  8   fmt.Println(getContent())   9   fmt.Println(getContent())  +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden index e548d553e1fc3bfb41c7b84bcb5a3f813cd7ae66..3f19f551648e42af98912fd50f9eeaeb113846d6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden @@ -1,16 +1,16 @@ -  …  @@ -1,13 +1,15 @@    …    -  1  package main   1  package main  -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  8   fmt.Println(getContent())   9   fmt.Println(getContent())  -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -1,13 +1,15 @@    …    +  1  package main   1  package main  +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  8   fmt.Println(getContent())   9   fmt.Println(getContent())  +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden index b00b47a18b46163593bcb105cea18dbb4661f966..5b91d6f674f1a8ccbf60793e81c31886cae88360 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  )   5  )  -  6     6    -  7  func main() {   7  func main() {  -  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!"  -       9 +  fmt.Println(content)  -  9  }  10  }  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  )   5  )  +  6     6    +  7  func main() {   7  func main() {  +  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!"  +       9 +  fmt.Println(content)  +  9  }  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.golden index 1d5472609c01435393837ff441dcf9834ae561ae..4f23b92da5f4ee718ff2d4d394d2bf709f74b1ab 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  )   5  )  -  6     6    -  7  func main() {   7  func main() {  -  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!"  -       9 +  fmt.Println(content)  -  9  }  10  }  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  )   5  )  +  6     6    +  7  func main() {   7  func main() {  +  8 -  fmt.Println("Hello, world!")   8 +  content := "Hello, world!"  +       9 +  fmt.Println(content)  +  9  }  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden index 5058ab2079c8c27905c07929ec1b854549dfa9f0..f86d56d4a7441f7fa9ba9a550b01559dd104f2b3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden index 54be547a1c74b34e4bfc1fd3ee84d946bd7603d5..496e191046dda837217f3883164395e519331bc2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden index 818863adc9081bcd2b66b0029f3a72a994d618e5..3318393a143b3bf22029f5e2f684e823ef8c84aa 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden index 376bae2594d8e175cdd84b90846fe43c639c4d69..9dfd2891ab3ba67f956bc1b13e07cd743e35aef6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden index 5b5a7815e5a6ca092036595df1a3cb30d644e8c9..db71ebb528931a3694354c210852721e394f3f40 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden @@ -1,4 +1,4 @@ - …  @@ -1,3 +1,3 @@   …    - 1 - a  1 + d  - 2 - b  2 + e  - 3 - c  3 + f  \ No newline at end of file + …  @@ -1,3 +1,3 @@   …    + 1 - a  1 + d  + 2 - b  2 + e  + 3 - c  3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden index 4ece6dca5318253fbc8af76e89a3fe41fc87009b..5ef50d3631ef12780340c266e0b06eeafe85b4f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden @@ -1,4 +1,4 @@ - …  @@ -1,3 +1,3 @@   …    - 1 - a  1 + d  - 2 - b  2 + e  - 3 - c  3 + f  \ No newline at end of file + …  @@ -1,3 +1,3 @@   …    + 1 - a  1 + d  + 2 - b  2 + e  + 3 - c  3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden index c69efe614a04aba3f680d6cf9af91112af13560b..f28397b63c34637944edbec3663a3f3222b310fe 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4  "fmt"   4  "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4  "fmt"   4  "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden index e22a98ecf771bc651d26af440a361286dcb167f7..77b6c47dfbabf4b62dc965790477441a8b3e46a9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4  "fmt"   4  "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4  "fmt"   4  "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden index c3744b0a3b97baa0404ad5830ff7893105c0db9d..bf2669828cf88596cf5528c7debc75cc3928f656 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6…  …    -  9  }  10  }  - 10    11    - 11  func getConte… 12  func getConte… - 12 -  return "H… 13 +  content :… -      14 +  return co… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6…  …    +  9  }  10  }  + 10    11    + 11  func getConte… 12  func getConte… + 12 -  return "H… 13 +  content :… +      14 +  return co… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden index 7efec8881d7252d4e0f5a444f372a19e12e5e035..88098510f3a8ef415eec21288725a81737ea69c7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6…  …    -  9  }  10  }  - 10    11    - 11  func getConte… 12  func getConte… - 12 -  return "H… 13 +  content :… -      14 +  return co… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6…  …    +  9  }  10  }  + 10    11    + 11  func getConte… 12  func getConte… + 12 -  return "H… 13 +  content :… +      14 +  return co… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden index 94d5b96e6ead9e58f58cead608bc24571d712d50..2747dac38c0ceb93c33e474e98d4bd14b02d76fd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden @@ -1,17 +1,17 @@ -  …   …  @@ -1,13 +1,15 @@   -  1   1  package main  -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  8   9   fmt.Println(getContent())  -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -1,13 +1,15 @@   +  1   1  package main  +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  8   9   fmt.Println(getContent())  +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden index 769aef3900a021bec59a59051c537562c78c0f95..7b01abe25fe193056299664c3e88922a719a98a9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden @@ -1,17 +1,17 @@ -  …   …  @@ -1,13 +1,15 @@   -  1   1  package main  -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  8   9   fmt.Println(getContent())  -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -1,13 +1,15 @@   +  1   1  package main  +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  8   9   fmt.Println(getContent())  +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden index 508754f0c6a3493d1efa006360eaeeacde13baea..ecbdbbdcb131c670d457f0c78eba50c02ac2babf 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  )  -  6   6    -  7   7  func main() {  -  8    -  fmt.Println("Hello, world!")  -     8 +  content := "Hello, world!"  -     9 +  fmt.Println(content)  -  9  10  }  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  )  +  6   6    +  7   7  func main() {  +  8    -  fmt.Println("Hello, world!")  +     8 +  content := "Hello, world!"  +     9 +  fmt.Println(content)  +  9  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden index 6532d31fe0f28f9a7619af543fc10848f438f4c9..1031618dece3febd0797ab23fd1b01d7aa7dd9d4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  )  -  6   6    -  7   7  func main() {  -  8    -  fmt.Println("Hello, world!")  -     8 +  content := "Hello, world!"  -     9 +  fmt.Println(content)  -  9  10  }  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  )  +  6   6    +  7   7  func main() {  +  8    -  fmt.Println("Hello, world!")  +     8 +  content := "Hello, world!"  +     9 +  fmt.Println(content)  +  9  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden index c0be6012af274bc1c746a26746d4e29473493ef8..1acdbca64411e80980db7fdae1300d42f46bde10 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden index f1700f00f23dc0960a12e5cdf37281e922d8fe2d..99b7bf5be8cdbc7016510672476a51c755e08e35 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden index bd1232d8439ec0f20601793817093304b37b91c4..d7c164e23317f57dc99125391a3b7b85744cb695 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden index 4833a8a0263aada505f2e115c5dfb9fc469def67..601742405296c42cd6ef8ae4ab4a20b4a9a7d764 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden index 586dcd0a0ad6b4dc2963f8d2064db1e54f917b30..29845f3aad7de5830772ab61ff3cf0806da5510c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden @@ -1,7 +1,7 @@ - …  …  @@ -1,3 +1,3 @@   - 1    - a  - 2    - b  - 3    - c  -    1 + d  -    2 + e  -    3 + f  \ No newline at end of file + …  …  @@ -1,3 +1,3 @@   + 1    - a  + 2    - b  + 3    - c  +    1 + d  +    2 + e  +    3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden index ec946344674b34b4c4530bedb1d3307ca364bc8f..79f1ed7bcf7b9dde3bcf5858d7c4a92049e34792 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden @@ -1,7 +1,7 @@ - …  …  @@ -1,3 +1,3 @@   - 1    - a  - 2    - b  - 3    - c  -    1 + d  -    2 + e  -    3 + f  \ No newline at end of file + …  …  @@ -1,3 +1,3 @@   + 1    - a  + 2    - b  + 3    - c  +    1 + d  +    2 + e  +    3 + f  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden index 18c9c363f3952bda8537f96496405edce5684485..4a066df9d92d2f32d724d2fde9682ffe9d7cf016 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4  "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4  "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden index 285caf3659ba538e0c12da796836045311ecad67..3a6fc89f11f9191e1a8b7ed461c25f0f42389195 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4  "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4  "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden index 773547de65905ab8872164be01584770da29d475..9c47b132a10d39ecbac588951114b0c521a916de 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUppe… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUppe… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden index bc1c6c04db45d3d8dfddf23440dcfa430cec7fb0..65d80ac49069a1fc792ed569f27fda08181b39b6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUppe… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUppe… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden index 8ab230c57cafc11906a067ee7361e48b66ede3f9..d964f98a62f198cd3a748c89b377e61c8bfcfada 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden @@ -1 +1 @@ -  …  @@ -2,6 +2,7 @@    …    \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden index 2a4e8eff92df5b3539dad4578a0715e0ec6ce42a..91b417195dc74ad497a169b2a9bea3f64be6b81e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden @@ -1,2 +1,2 @@ -  …  @@ -2,6 +2,7 @@    …    -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden index 8b77ca205d3f1c85a25f733f0a3044a541805c10..4df3869c8df525382f32778df12540966c827cd9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden @@ -1,3 +1,3 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden index b42965be972ce8b096db1508514e9d494a57bad7..0f044b6028c34ec693933d35f3e079943fa153ea 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden @@ -1,4 +1,4 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden index 8d4a293fdd17ce5cbd8d709656573105a8cc7b09..5f2744c16f6b8b93265fcdb6bf40e60a70b2f0fc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden @@ -1,5 +1,5 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden index 67d30fec443bdeea7b49eba4ab346603baba7670..54c9dbbd1568e5c930786b53916a10bae158a4a6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden @@ -1,6 +1,6 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden index ba19bebf9686a530e87e11d090ad4f04f4ade5fb..c45c32897f14e8ae09471f6824bb49165cd80d9f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden @@ -1,7 +1,7 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden index edb4eb9aaa24d28523498661d3d802edb62b243d..99b91fbb2203cef90eb8f608626ab0bd8e45f9c3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden @@ -1,8 +1,8 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden index fc1998f1d33f0299550660b368de1e4d720c2ed0..61d8e83b95edac2ffd02203869f9a2eddf8576f5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden @@ -1,9 +1,9 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden index 10474f0884137006961cc6e5bfddf6d001c5561d..f0c7564d7f8425502ec38fab4bbb3ef017056f4c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden @@ -1,10 +1,10 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden index 0e25a5ef5279cf29cfa1eb24831bc062a8bb6254..0c3a84f7d409fed4ec3b3d3161bcd20eaf294775 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden @@ -1,11 +1,11 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden index f178ad9ab9285b83c0efc9b207379a61f16ec7a9..a199a3614b8083707240fc3372eb4c797c42e49b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden @@ -1,12 +1,12 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden index edcfcd2f89adef8525a8acee4d3ce9e8d1ffd605..254eb52172e127903d99b8d974e7a255f3cf0656 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden @@ -1,13 +1,13 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden index 6ff0ca309b149aa73bfaec8ec0debdaa253cecfe..9a0bc2a69419416dae030f111c340311d579662f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden @@ -1,14 +1,14 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden index 376bae2594d8e175cdd84b90846fe43c639c4d69..9dfd2891ab3ba67f956bc1b13e07cd743e35aef6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden index 6b79b752f668a21205c772356ffb1af1d6c88546..d1d117809967c1ae1d4b10ad10824c391c575a32 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden @@ -1,16 +1,16 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden index 81086126879f38feda13147520b4ced931441d67..ce3d2e00dbfa827d6dd13f7f2dfcba96c71fa3f8 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden @@ -1,17 +1,17 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           -           \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden index 0ced2af062c5ddfa3179501b02ea58c549491103..2816e081dc2e48c7279c44e2fdab59d6a8a6b7f3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden @@ -1,18 +1,18 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           -           -           \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden index e94c36d1f801e0dae9ae22c6758638e692aa5afa..774d7124513556759e948e771841fc4ed4199684 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden @@ -1,19 +1,19 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           -           -           -           \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden index 0c20bb81d81d8a4a000f601fa75a1f148610c06d..9aa08b5f2b45ef8dd7f30d0c4c290841d31e1ff2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden @@ -1,20 +1,20 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           -           -           -           -           \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           +           +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden index 65e9cca91c8ced66ea2d69e111cb09cfbb8e8852..404e81bd2cb0c2dc77432470b0bb71d9e14bdae5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden @@ -1 +1 @@ -  …   …  @@ -2,6 +2,7 @@   \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden index 61a03f25c81520058f8fd3856a03e84daac6cbb6..181c36ed41c5b51554304ec481a4d5b299987ff2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden @@ -1,2 +1,2 @@ -  …   …  @@ -2,6 +2,7 @@   -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden index 6951d63de62756d581aa7a98564d6547dd244609..1dcdc7e2100105faa7c46450ac632c21995d8ac5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden @@ -1,3 +1,3 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden index c25c0f42f2fce40ac113946407cfee70cb597ebd..cd4a7d199633684aa828b3cf6bfdebb5c02bb1d6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden @@ -1,4 +1,4 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden index e11e6df667cfa9dc3d909f30fef8895c16dc85c2..12156bccd3e9fd73c0866fea9973f91f940395f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden @@ -1,5 +1,5 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden index d6a7952a8e59e13f6443a7430a08d38245963daa..92ee7b85cd56f4d40bccc83cb99617b57d44628d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden @@ -1,6 +1,6 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden index f04437d8e721cd83ccac5d83d7ece23aea2deca9..77660a735bb1dec47736b63e6aea9b83957b8729 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden @@ -1,7 +1,7 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden index 9bc97685b06c45886e3e51aa853e6979c13535f4..2b7224c2ba28f9dafec0255a89f2a12e04738d8a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden @@ -1,8 +1,8 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden index b644669ac3c44b02fa524df27a79ca5fa43ebc5f..d6fee48a3de9dc285089248b833817760799bf7c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden @@ -1,9 +1,9 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden index 2c1730435a32cf3a5adfa6a0cd2b7096959d72cb..b1f41124ba7daea7e530761f4c756d425385d873 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden @@ -1,10 +1,10 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden index 11933267d0e96a9d40847cc6ab63eb8a638c903f..6737555f551442b91f83c797f4cbc440eb74bc60 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden @@ -1,11 +1,11 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden index 6f85a1321dafe076664f68bce0cfacc904bcf348..2afc7df3ef23de99bfa7e8e148098f91f7545ca7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden @@ -1,12 +1,12 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden index 9a40f2743bb130da78160e44804121046bfc2648..1028f4122d332a581391e44ca74ca75f3ed151cc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden @@ -1,13 +1,13 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden index 92c873c53589db4d5dbb3d5823577ec0ea3c0525..376157c30e23e6927a7b0e805bc054b64f4725eb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden @@ -1,14 +1,14 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden index a6c452786f6dd1a90b06af9565230a32a2f7fca9..9283edc981a61b3b9da35c942e70927a2dc03e0e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden @@ -1,15 +1,15 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden index 4833a8a0263aada505f2e115c5dfb9fc469def67..601742405296c42cd6ef8ae4ab4a20b4a9a7d764 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden index 6a11e8c96fbf5917fb8fba209c6e08420042b50e..d21fa9269446b628a51347d4940e6a3a6e1122e7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden @@ -1,17 +1,17 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden index e1679a274299677d72b8fde8f12f8900edb32244..6ce4dd6dae2779ae947eec220ba28244663751ae 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden @@ -1,18 +1,18 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         -         \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden index e500ceed976da0ee572e015eba1e1908963ce0f2..aabfe04315a2ae8ff67c4ee42e6ca5d8bd171d8b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden @@ -1,19 +1,19 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         -         -         \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden index 89d701a43e2df3c14677ef4135dfebc7654eb3df..7d6cb8931f16722b6a63c384f45b8b22d1d3aa24 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden @@ -1,20 +1,20 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         -         -         -         \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         +         +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Split.golden b/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Split.golden index 55f9b83eb60b7d807d6573770c095f1fe4300380..86d7ef627d7be3360681c56a9bc0bd35d743b417 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Split.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Split.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Unified.golden b/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Unified.golden index 744ba1f8400a69344016826ad10de5a72c540a0b..bdf635a1fbcef080ed5706fa4d5dd56a6a62269a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Unified.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewTabs/Unified.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden index 3fc43d9cabb64c1de963ffc5fb229bb6a853690e..5cbf6f43175c50b34339fbb08aa60bc5130c8b2b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden @@ -1,15 +1,15 @@ -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  \ No newline at end of file +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden index e9ff4178d144232d7c64aa08f98235174ae6171a..e7c9ef64599ef14fa1b3880d07ecc93377570c2c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden @@ -1,15 +1,15 @@ -   -   -   -   -   -   -   -   -   -   - 1 - 1 - 1 -   - 1 \ No newline at end of file +   +   +   +   +   +   +   +   +   +   + 1 + 1 + 1 +   + 1 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden index e4793972aaef14ebd0efdd95899a412b7afd88fe..6b48f68568014cdf3c332dc00298ac01450b9025 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden @@ -1,15 +1,15 @@ -  … -  2 -  3 -  4 -   -  5 -  6 -  7 -  … -  9 - 10 - 11 - 12 -   - 13 \ No newline at end of file +  … +  2 +  3 +  4 +   +  5 +  6 +  7 +  … +  9 + 10 + 11 + 12 +   + 13 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden index ea92f5ceffc1e6c99381064d731ac9321f09ce3e..423ecfb721593f479b33b8bc9e2653dad2debc96 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden @@ -1,15 +1,15 @@ -  …  -  2  -  3  -  4  -    -  5  -  6  -  7  -  …  -  9  - 10  - 11  - 12  -    - 13  \ No newline at end of file +  …  +  2  +  3  +  4  +    +  5  +  6  +  7  +  …  +  9  + 10  + 11  + 12  +    + 13  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden index 52d7f5f1a76707802fbc4426c0004f5c618cf887..9e0c7229fc430f46e299aaf134fe451206dd6ed7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden @@ -1,15 +1,15 @@ -  …   -  2   -  3   -  4   -     -  5   -  6   -  7   -  …   -  9   - 10   - 11   - 12 - -     - 13   \ No newline at end of file +  …   +  2   +  3   +  4   +     +  5   +  6   +  7   +  …   +  9   + 10   + 11   + 12 - +     + 13   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden index 7d4c531980e2af3a94cd612e2fcb5bb672ceb553..dfc7dc68372591ebc5e5ab8ebfc8efd776733846 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden @@ -1,15 +1,15 @@ -  …    -  2   -  3   -  4   -     -  5   -  6   -  7   -  …    -  9   - 10   - 11   - 12 -  -     - 13   \ No newline at end of file +  …    +  2   +  3   +  4   +     +  5   +  6   +  7   +  …    +  9   + 10   + 11   + 12 -  +     + 13   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden index 5d837eeb27466b95efdb8fd65f9a39ca9d27e3f4..bef1e31920cfa41abfe9550cb3f2ef796bfd8715 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden @@ -1,15 +1,15 @@ -  …   … -  2    -  3    -  4    -      -  5    -  6    -  7    -  …   … -  9    - 10    - 11    - 12 -   -      - 13    \ No newline at end of file +  …   … +  2    +  3    +  4    +      +  5    +  6    +  7    +  …   … +  9    + 10    + 11    + 12 -   +      + 13    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden index 1a34fe59526ac61809752750759bfd894c9fdbb7..5236fb29ab8cc7a50f93c197dac73d15f460835a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden @@ -1,15 +1,15 @@ -  …   …  -  2     -  3     -  4     -       -  5     -  6     -  7     -  …   …  -  9   1 - 10   1 - 11   1 - 12 -  1 -     1 - 13   1 \ No newline at end of file +  …   …  +  2     +  3     +  4     +       +  5     +  6     +  7     +  …   …  +  9   1 + 10   1 + 11   1 + 12 -  1 +     1 + 13   1 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden index 47170f9836acbbe16f1de1fc739b1a9e32924ebf..79c2bdcddc72773af89d794f39be69c5b9589195 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden @@ -1,15 +1,15 @@ -  … …  …  -  2    2  -  3    3  -  4    4  -      5  -  5    6  -  6    7  -  7    8  -  … …  …  -  9   10  - 10   11  - 11   12  - 12 - 13  -     14  - 13   15  \ No newline at end of file +  … …  …  +  2    2  +  3    3  +  4    4  +      5  +  5    6  +  6    7  +  7    8  +  … …  …  +  9   10  + 10   11  + 11   12  + 12 - 13  +     14  + 13   15  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden index 7de1ab70c01b038036944c1be33703eaa3ee69e2..44158595bacb86bc74dbfb41a3411a66ea4f10aa 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden @@ -1,15 +1,15 @@ -  … …  …   -  2    2   -  3    3   -  4    4   -      5 + -  5    6   -  6    7   -  7    8   -  … …  …   -  9   10   - 10   11   - 11   12   - 12 - 13 + -     14 + - 13   15   \ No newline at end of file +  … …  …   +  2    2   +  3    3   +  4    4   +      5 + +  5    6   +  6    7   +  7    8   +  … …  …   +  9   10   + 10   11   + 11   12   + 12 - 13 + +     14 + + 13   15   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden index 0a3c87cd5b70374bb983c3bbb131e38691d6f857..60922683667e97a950c54fdb00daf99564cec45d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden @@ -1,15 +1,15 @@ -  …  …  …   -  2    2   -  3    3   -  4    4   -      5 + -  5    6   -  6    7   -  7    8   -  …  …  …   -  9   10   - 10   11   - 11   12   - 12 -  13 + -     14 + - 13   15   \ No newline at end of file +  …  …  …   +  2    2   +  3    3   +  4    4   +      5 + +  5    6   +  6    7   +  7    8   +  …  …  …   +  9   10   + 10   11   + 11   12   + 12 -  13 + +     14 + + 13   15   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden index 70e872896752b131d9c42289a062f2ac7b0069cb..7411e7f8f6152212a3b1e2250d1664a47cca50a7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden @@ -1,15 +1,15 @@ -  …  …  …    -  2    2   -  3    3   -  4    4   -      5 +  -  5    6   -  6    7   -  7    8   -  …  …  …    -  9   10   - 10   11   - 11   12   - 12 -  13 +  -     14 +  - 13   15   \ No newline at end of file +  …  …  …    +  2    2   +  3    3   +  4    4   +      5 +  +  5    6   +  6    7   +  7    8   +  …  …  …    +  9   10   + 10   11   + 11   12   + 12 -  13 +  +     14 +  + 13   15   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden index 18784d5152179f7166a928d253b00515ff549dcf..5e4fe608e29f710745ee11c4a7c0b04b854c27bb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden @@ -1,15 +1,15 @@ -  …  …  …    -  2    2    -  3    3    -  4    4    -      5 +   -  5    6    -  6    7    -  7    8    -  …  …  …    -  9   10    - 10   11    - 11   12    - 12 -  13 +   -     14 +   - 13   15    \ No newline at end of file +  …  …  …    +  2    2    +  3    3    +  4    4    +      5 +   +  5    6    +  6    7    +  7    8    +  …  …  …    +  9   10    + 10   11    + 11   12    + 12 -  13 +   +     14 +   + 13   15    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden index 92962575466205b1520bcb948bfbcf3d9040cd20..95c279972d7006e6c10282f5bf206ad44a6a3f8c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden @@ -1,15 +1,15 @@ -  …  …  …    -  2     2    -  3  …  3  … -  4  …  4  … -       5 + … -  5  )  6  ) -  6     7    -  7  …  8  … -  …  …  …    -  9  } 10  } - 10    11    - 11  … 12  … - 12 - … 13 + … -      14 + … - 13  } 15  } \ No newline at end of file +  …  …  …    +  2     2    +  3  …  3  … +  4  …  4  … +       5 + … +  5  )  6  ) +  6     7    +  7  …  8  … +  …  …  …    +  9  } 10  } + 10    11    + 11  … 12  … + 12 - … 13 + … +      14 + … + 13  } 15  } \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden index 3e564c4e1b4224f1c1a95c4e459b14b989ed9211..2a387ddb9c968f2d0d7e7912460da3dd155d1d89 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden @@ -1,15 +1,15 @@ -  …  …  …    -  2     2    -  3  …  3  …  -  4  …  4  …  -       5 + …  -  5  )  6  )  -  6     7    -  7  …  8  …  -  …  …  …    -  9  } 10  }  - 10    11    - 11  … 12  …  - 12 - … 13 + …  -      14 + …  - 13  } 15  }  \ No newline at end of file +  …  …  …    +  2     2    +  3  …  3  …  +  4  …  4  …  +       5 + …  +  5  )  6  )  +  6     7    +  7  …  8  …  +  …  …  …    +  9  } 10  }  + 10    11    + 11  … 12  …  + 12 - … 13 + …  +      14 + …  + 13  } 15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden index 73c32b5beb4fe882fee590f933ba30fc7df3f055..e1555921f1c8cb4ba84775d124bd6312615bc838 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden @@ -1,15 +1,15 @@ -  …  @…  …    -  2     2    -  3  i…  3  i… -  4   …  4   … -       5 +  … -  5  )   6  )  -  6     7    -  7  f…  8  f… -  …  @…  …    -  9  }  10  }  - 10    11    - 11  f… 12  f… - 12 -  … 13 +  … -      14 +  … - 13  }  15  }  \ No newline at end of file +  …  @…  …    +  2     2    +  3  i…  3  i… +  4   …  4   … +       5 +  … +  5  )   6  )  +  6     7    +  7  f…  8  f… +  …  @…  …    +  9  }  10  }  + 10    11    + 11  f… 12  f… + 12 -  … 13 +  … +      14 +  … + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden index a0a56d1c19961775f7ae0b8471f2dd36be2898d6..01226536bb49cb5a96361192c4a611034c62fadc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden @@ -1,15 +1,15 @@ -  …  @…  …    -  2     2    -  3  i…  3  i…  -  4   …  4   …  -       5 +  …  -  5  )   6  )  -  6     7    -  7  f…  8  f…  -  …  @…  …    -  9  }  10  }  - 10    11    - 11  f… 12  f…  - 12 -  … 13 +  …  -      14 +  …  - 13  }  15  }  \ No newline at end of file +  …  @…  …    +  2     2    +  3  i…  3  i…  +  4   …  4   …  +       5 +  …  +  5  )   6  )  +  6     7    +  7  f…  8  f…  +  …  @…  …    +  9  }  10  }  + 10    11    + 11  f… 12  f…  + 12 -  … 13 +  …  +      14 +  …  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden index eaf9ba5140a00fbb67c689bf66cae5293464fbbd..676ed1064cff38b224658fcd09a85ef6d0bc0bf7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden @@ -1,15 +1,15 @@ -  …  @@…  …    -  2     2    -  3  im…  3  im… -  4   …  4   … -       5 +  … -  5  )   6  )  -  6     7    -  7  fu…  8  fu… -  …  @@…  …    -  9  }  10  }  - 10    11    - 11  fu… 12  fu… - 12 -  … 13 +  … -      14 +  … - 13  }  15  }  \ No newline at end of file +  …  @@…  …    +  2     2    +  3  im…  3  im… +  4   …  4   … +       5 +  … +  5  )   6  )  +  6     7    +  7  fu…  8  fu… +  …  @@…[48;2;71;118;255m  …    +  9  }  10  }  + 10    11    + 11  fu… 12  fu… + 12 -  … 13 +  … +      14 +  … + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden index f2b48119efe04ce3650d2964df314d7a43fadd99..8e29058f56b082f28dea80a751331e50f813ac0d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden @@ -1,15 +1,15 @@ -  …  @@…  …    -  2     2    -  3  im…  3  im…  -  4   …  4   …  -       5 +  …  -  5  )   6  )  -  6     7    -  7  fu…  8  fu…  -  …  @@…  …    -  9  }  10  }  - 10    11    - 11  fu… 12  fu…  - 12 -  … 13 +  …  -      14 +  …  - 13  }  15  }  \ No newline at end of file +  …  @@…  …    +  2     2    +  3  im…  3  im…  +  4   …  4   …  +       5 +  …  +  5  )   6  )  +  6     7    +  7  fu…  8  fu…  +  …  @@…  …    +  9  }  10  }  + 10    11    + 11  fu… 12  fu…  + 12 -  … 13 +  …  +      14 +  …  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden index 80faca00e90d24c17339877a2e96fee8363d195b..a161b63342f3a955bb6aaa507010a59c3af1f296 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden @@ -1,15 +1,15 @@ -  …  @@ …  …    -  2     2    -  3  imp…  3  imp… -  4   …  4   … -       5 +  … -  5  )   6  )  -  6     7    -  7  fun…  8  fun… -  …  @@ …  …    -  9  }  10  }  - 10    11    - 11  fun… 12  fun… - 12 -  … 13 +  … -      14 +  … - 13  }  15  }  \ No newline at end of file +  …  @@ …  …    +  2     2    +  3  imp…  3  imp… +  4   …  4   … +       5 +  … +  5  )   6  )  +  6     7    +  7  fun…  8  fun… +  …  @@ …  …    +  9  }  10  }  + 10    11    + 11  fun… 12  fun… + 12 -  … 13 +  … +      14 +  … + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden index ef6bbfffd814eb2ae28e1f399d78ebe9ea1c3b05..aa0f90c7d156ec6b398ef92418b3dfcffad9b81c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden @@ -1,15 +1,15 @@ -  …  @@ …  …    -  2     2    -  3  imp…  3  imp…  -  4   …  4   …  -       5 +  …  -  5  )   6  )  -  6     7    -  7  fun…  8  fun…  -  …  @@ …  …    -  9  }  10  }  - 10    11    - 11  fun… 12  fun…  - 12 -  … 13 +  …  -      14 +  …  - 13  }  15  }  \ No newline at end of file +  …  @@ …  …    +  2     2    +  3  imp…  3  imp…  +  4   …  4   …  +       5 +  …  +  5  )   6  )  +  6     7    +  7  fun…  8  fun…  +  …  @@ …  …    +  9  }  10  }  + 10    11    + 11  fun… 12  fun…  + 12 -  … 13 +  …  +      14 +  …  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden index 9a3d74e5073f9229d4ff87cf0f54cc035804a87e..503ddf6d62ab0ea806a5473fa3d2fe08fb36f39c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden @@ -1,15 +1,15 @@ -  …  @@ -…  …    -  2     2    -  3  impo…  3  impo… -  4   …  4   … -       5 +  … -  5  )   6  )  -  6     7    -  7  func…  8  func… -  …  @@ -…  …    -  9  }  10  }  - 10    11    - 11  func… 12  func… - 12 -  … 13 +  … -      14 +  … - 13  }  15  }  \ No newline at end of file +  …  @@ -…  …    +  2     2    +  3  impo…  3  impo… +  4   …  4   … +       5 +  … +  5  )   6  )  +  6     7    +  7  func…  8  func… +  …  @@ -…  …    +  9  }  10  }  + 10    11    + 11  func… 12  func… + 12 -  … 13 +  … +      14 +  … + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden index 8b59e07438c73077b25e91e1aea95b0762278ead..cbad737f4444a03dad72b2c47b56dc5b0466ed59 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden @@ -1,15 +1,15 @@ -  …  @@ -…  …    -  2     2    -  3  impo…  3  impo…  -  4   …  4   …  -       5 +  …  -  5  )   6  )  -  6     7    -  7  func…  8  func…  -  …  @@ -…  …    -  9  }  10  }  - 10    11    - 11  func… 12  func…  - 12 -  … 13 +  …  -      14 +  …  - 13  }  15  }  \ No newline at end of file +  …  @@ -…  …    +  2     2    +  3  impo…  3  impo…  +  4   …  4   …  +       5 +  …  +  5  )   6  )  +  6     7    +  7  func…  8  func…  +  …  @@ -…  …    +  9  }  10  }  + 10    11    + 11  func… 12  func…  + 12 -  … 13 +  …  +      14 +  …  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden index e9e963f6d68f39797652735946bba4d60f9bb07b..cbba124f35dcb045e3f95a469ced5b4e8109c330 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden @@ -1,15 +1,15 @@ -  …  @@ -2…  …    -  2     2    -  3  impor…  3  impor… -  4   "…  4   "… -       5 +  "… -  5  )   6  )  -  6     7    -  7  func …  8  func … -  …  @@ -9…  …    -  9  }  10  }  - 10    11    - 11  func … 12  func … - 12 -  r… 13 +  c… -      14 +  r… - 13  }  15  }  \ No newline at end of file +  …  @@ -2…  …    +  2     2    +  3  impor…  3  impor… +  4   "…  4   "… +       5 +  "… +  5  )   6  )  +  6     7    +  7  func …  8  func … +  …  @@ -9…  …    +  9  }  10  }  + 10    11    + 11  func … 12  func … + 12 -  r… 13 +  c… +      14 +  r… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden index 88b14c368e9d758f73b170aedcc289665b323de5..9b5d59f486fa7705dc71c64f5ad71256845f56d7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden @@ -1,15 +1,15 @@ -  …  @@ -2…  …    -  2     2    -  3  impor…  3  impor…  -  4   "…  4   "…  -       5 +  "…  -  5  )   6  )  -  6     7    -  7  func …  8  func …  -  …  @@ -9…  …    -  9  }  10  }  - 10    11    - 11  func … 12  func …  - 12 -  r… 13 +  c…  -      14 +  r…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2…  …    +  2     2    +  3  impor…  3  impor…  +  4   "…  4   "…  +       5 +  "…  +  5  )   6  )  +  6     7    +  7  func …  8  func …  +  …  @@ -9…  …    +  9  }  10  }  + 10    11    + 11  func … 12  func …  + 12 -  r… 13 +  c…  +      14 +  r…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden index f1a03a44b153d125baea902647542eb268e04c85..ea421380509e52b06692d734e56e7bf1fd71030d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden @@ -1,15 +1,15 @@ -  …  @@ -2,…  …    -  2     2    -  3  import…  3  import… -  4   "f…  4   "f… -       5 +  "s… -  5  )   6  )  -  6     7    -  7  func m…  8  func m… -  …  @@ -9,…  …    -  9  }  10  }  - 10    11    - 11  func g… 12  func g… - 12 -  re… 13 +  co… -      14 +  re… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,…  …    +  2     2    +  3  import…  3  import… +  4   "f…  4   "f… +       5 +  "s… +  5  )   6  )  +  6     7    +  7  func m…  8  func m… +  …  @@ -9,…  …    +  9  }  10  }  + 10    11    + 11  func g… 12  func g… + 12 -  re… 13 +  co… +      14 +  re… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden index 2be2ed4039296a08ca88ea742294c69fe328bb09..13257caf4dd4670ff535824cd71e64bf06da9078 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden @@ -1,15 +1,15 @@ -  …  @@ -2,…  …    -  2     2    -  3  import…  3  import…  -  4   "f…  4   "f…  -       5 +  "s…  -  5  )   6  )  -  6     7    -  7  func m…  8  func m…  -  …  @@ -9,…  …    -  9  }  10  }  - 10    11    - 11  func g… 12  func g…  - 12 -  re… 13 +  co…  -      14 +  re…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,…  …    +  2     2    +  3  import…  3  import…  +  4   "f…  4   "f…  +       5 +  "s…  +  5  )   6  )  +  6     7    +  7  func m…  8  func m…  +  …  @@ -9,…  …    +  9  }  10  }  + 10    11    + 11  func g… 12  func g…  + 12 -  re… 13 +  co…  +      14 +  re…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden index ac729f74b19b2bed7b6c254aae945d6dcd9321af..ca6a247e70999ec23e8f27f6b924ae41f792ed36 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6…  …    -  2     2    -  3  import (  3  import ( -  4   "fm…  4   "fm… -       5 +  "st… -  5  )   6  )  -  6     7    -  7  func ma…  8  func ma… -  …  @@ -9,5…  …    -  9  }  10  }  - 10    11    - 11  func ge… 12  func ge… - 12 -  ret… 13 +  con… -      14 +  ret… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6…  …    +  2     2    +  3  import (  3  import ( +  4   "fm…  4   "fm… +       5 +  "st… +  5  )   6  )  +  6     7    +  7  func ma…  8  func ma… +  …  @@ -9,5…  …    +  9  }  10  }  + 10    11    + 11  func ge… 12  func ge… + 12 -  ret… 13 +  con… +      14 +  ret… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden index ac330346bcde118e8f0366cd3bf5ba85162a7156..e1d38036959dd20d52fa4712a466d0cdb9f5ffca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6…  …    -  2     2    -  3  import (  3  import (  -  4   "fm…  4   "fm…  -       5 +  "st…  -  5  )   6  )  -  6     7    -  7  func ma…  8  func ma…  -  …  @@ -9,5…  …    -  9  }  10  }  - 10    11    - 11  func ge… 12  func ge…  - 12 -  ret… 13 +  con…  -      14 +  ret…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6…  …    +  2     2    +  3  import (  3  import (  +  4   "fm…  4   "fm…  +       5 +  "st…  +  5  )   6  )  +  6     7    +  7  func ma…  8  func ma…  +  …  @@ -9,5…  …    +  9  }  10  }  + 10    11    + 11  func ge… 12  func ge…  + 12 -  ret… 13 +  con…  +      14 +  ret…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden index 6504f7ece94be17d44840ce265658a01165f6764..24e99e13e04e2e8f6e50a6ca1a2f9598382a2e91 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"  4   "fmt" -       5 +  "str… -  5  )   6  )  -  6     7    -  7  func mai…  8  func mai… -  …  @@ -9,5 …  …    -  9  }  10  }  - 10    11    - 11  func get… 12  func get… - 12 -  retu… 13 +  cont… -      14 +  retu… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"  4   "fmt" +       5 +  "str… +  5  )   6  )  +  6     7    +  7  func mai…  8  func mai… +  …  @@ -9,5 …  …    +  9  }  10  }  + 10    11    + 11  func get… 12  func get… + 12 -  retu… 13 +  cont… +      14 +  retu… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden index 8c93b028a434f0819fa013886eb00d8aabd1285d..9f5a0e17b2ec3979d342cc57fda07430e75515cb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"  4   "fmt"  -       5 +  "str…  -  5  )   6  )  -  6     7    -  7  func mai…  8  func mai…  -  …  @@ -9,5 …  …    -  9  }  10  }  - 10    11    - 11  func get… 12  func get…  - 12 -  retu… 13 +  cont…  -      14 +  retu…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"  4   "fmt"  +       5 +  "str…  +  5  )   6  )  +  6     7    +  7  func mai…  8  func mai…  +  …  @@ -9,5 …  …    +  9  }  10  }  + 10    11    + 11  func get… 12  func get…  + 12 -  retu… 13 +  cont…  +      14 +  retu…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden index 4a71409e9b273fbe3095c77ae6b14817e1d4a712..b66ec5296278805d56275c97337257d3324a9e48 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "stri… -  5  )   6  )  -  6     7    -  7  func main…  8  func main… -  …  @@ -9,5 +…  …    -  9  }  10  }  - 10    11    - 11  func getC… 12  func getC… - 12 -  retur… 13 +  conte… -      14 +  retur… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "stri… +  5  )   6  )  +  6     7    +  7  func main…  8  func main… +  …  @@ -9,5 +…  …    +  9  }  10  }  + 10    11    + 11  func getC… 12  func getC… + 12 -  retur… 13 +  conte… +      14 +  retur… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden index 9273c0133a6bb74a1d9ff0786ec5b8d001cf1eb6..7d9a7f93b504a6c73f906e4ec2bf133cfd0c69a8 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "stri…  -  5  )   6  )  -  6     7    -  7  func main…  8  func main…  -  …  @@ -9,5 +…  …    -  9  }  10  }  - 10    11    - 11  func getC… 12  func getC…  - 12 -  retur… 13 +  conte…  -      14 +  retur…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "stri…  +  5  )   6  )  +  6     7    +  7  func main…  8  func main…  +  …  @@ -9,5 +…  …    +  9  }  10  }  + 10    11    + 11  func getC… 12  func getC…  + 12 -  retur… 13 +  conte…  +      14 +  retur…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden index bafd04e96979aba50254250e9260e9079606bd6c..0702878f23e5fcb9dff7a2023c369acc81dd6c77 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strin… -  5  )   6  )  -  6     7    -  7  func main(…  8  func main(… -  …  @@ -9,5 +1…  …    -  9  }  10  }  - 10    11    - 11  func getCo… 12  func getCo… - 12 -  return… 13 +  conten… -      14 +  return… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strin… +  5  )   6  )  +  6     7    +  7  func main(…  8  func main(… +  …  @@ -9,5 +1…  …    +  9  }  10  }  + 10    11    + 11  func getCo… 12  func getCo… + 12 -  return… 13 +  conten… +      14 +  return… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden index 8ac20fa259d92f9c4a13c1b7d0b3ece1ef65639c..c3b1cddb8d0ccfda0678729d60e8b38040bedd67 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strin…  -  5  )   6  )  -  6     7    -  7  func main(…  8  func main(…  -  …  @@ -9,5 +1…  …    -  9  }  10  }  - 10    11    - 11  func getCo… 12  func getCo…  - 12 -  return… 13 +  conten…  -      14 +  return…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strin…  +  5  )   6  )  +  6     7    +  7  func main(…  8  func main(…  +  …  @@ -9,5 +1…  …    +  9  }  10  }  + 10    11    + 11  func getCo… 12  func getCo…  + 12 -  return… 13 +  conten…  +      14 +  return…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden index a138a46233c89e3526ceb96c1c672aadd7daa919..cdfcbb7c04707f1f0132dbc5f59e95255f221d0a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "string… -  5  )   6  )  -  6     7    -  7  func main()…  8  func main()… -  …  @@ -9,5 +10…  …    -  9  }  10  }  - 10    11    - 11  func getCon… 12  func getCon… - 12 -  return … 13 +  content… -      14 +  return … - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "string… +  5  )   6  )  +  6     7    +  7  func main()…  8  func main()… +  …  @@ -9,5 +10…  …    +  9  }  10  }  + 10    11    + 11  func getCon… 12  func getCon… + 12 -  return … 13 +  content… +      14 +  return … + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden index dd0cb8c2799baa35864ca202dd67a97b5434b8bc..13cc915edc69b810b43539d64f665227275ca295 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "string…  -  5  )   6  )  -  6     7    -  7  func main()…  8  func main()…  -  …  @@ -9,5 +10…  …    -  9  }  10  }  - 10    11    - 11  func getCon… 12  func getCon…  - 12 -  return … 13 +  content…  -      14 +  return …  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "string…  +  5  )   6  )  +  6     7    +  7  func main()…  8  func main()…  +  …  @@ -9,5 +10…  …    +  9  }  10  }  + 10    11    + 11  func getCon… 12  func getCon…  + 12 -  return … 13 +  content…  +      14 +  return …  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden index b0084aa014a51992926f11b26cef01b4fc21ab12..5db75e2dd8a75b3eb94cd4eb4049b0a80f092366 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings" -  5  )   6  )  -  6     7    -  7  func main() {  8  func main() { -  …  @@ -9,5 +10,…  …    -  9  }  10  }  - 10    11    - 11  func getCont… 12  func getCont… - 12 -  return "… 13 +  content … -      14 +  return c… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings" +  5  )   6  )  +  6     7    +  7  func main() {  8  func main() { +  …  @@ -9,5 +10,…  …    +  9  }  10  }  + 10    11    + 11  func getCont… 12  func getCont… + 12 -  return "… 13 +  content … +      14 +  return c… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden index ae1bde4711283fe156a8a349f6499c030e3daa66..fd2b1c11c8e1df06c57686b3d16f5009bbe61c05 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {  8  func main() {  -  …  @@ -9,5 +10,…  …    -  9  }  10  }  - 10    11    - 11  func getCont… 12  func getCont…  - 12 -  return "… 13 +  content …  -      14 +  return c…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {  8  func main() {  +  …  @@ -9,5 +10,…  …    +  9  }  10  }  + 10    11    + 11  func getCont… 12  func getCont…  + 12 -  return "… 13 +  content …  +      14 +  return c…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden index 7efec8881d7252d4e0f5a444f372a19e12e5e035..88098510f3a8ef415eec21288725a81737ea69c7 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6…  …    -  9  }  10  }  - 10    11    - 11  func getConte… 12  func getConte… - 12 -  return "H… 13 +  content :… -      14 +  return co… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6…  …    +  9  }  10  }  + 10    11    + 11  func getConte… 12  func getConte… + 12 -  return "H… 13 +  content :… +      14 +  return co… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden index 10c4f687102fb8aed1d0456cde43a67ebf2a06d3..a6d4eb07ece0143eb14eda2dbaa07a9642c41405 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 …  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6…  …    -  9  }  10  }  - 10    11    - 11  func getConte… 12  func getConte…  - 12 -  return "H… 13 +  content :…  -      14 +  return co…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 …  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6…  …    +  9  }  10  }  + 10    11    + 11  func getConte… 12  func getConte…  + 12 -  return "H… 13 +  content :…  +      14 +  return co…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden index 9af1da8df7623454ca6d493baa5c1e248c988c8c..515cb0a0084d87a66ea45a2c93d0b818f1b4ad3c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 …  …    -  9  }  10  }  - 10    11    - 11  func getConten… 12  func getConten… - 12 -  return "He… 13 +  content :=… -      14 +  return con… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 …  …    +  9  }  10  }  + 10    11    + 11  func getConten… 12  func getConten… + 12 -  return "He… 13 +  content :=… +      14 +  return con… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden index d4a9545f90cba3e7004f989b4b3231b921119b57..b942426e46c70274b294d35a736f6e830dae09da 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @…  …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 …  …    -  9  }  10  }  - 10    11    - 11  func getConten… 12  func getConten…  - 12 -  return "He… 13 +  content :=…  -      14 +  return con…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @…  …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 …  …    +  9  }  10  }  + 10    11    + 11  func getConten… 12  func getConten…  + 12 -  return "He… 13 +  content :=…  +      14 +  return con…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden index 31b3e5b8a566adde3453c3681ecfbd14721ea8d3..6495f8daf94e7d77d3e5c6353226a55522b6ac93 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@   …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @…  …    -  9  }  10  }  - 10    11    - 11  func getContent… 12  func getContent… - 12 -  return "Hel… 13 +  content := … -      14 +  return cont… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@   …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @…  …    +  9  }  10  }  + 10    11    + 11  func getContent… 12  func getContent… + 12 -  return "Hel… 13 +  content := … +      14 +  return cont… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden index 715b72802b8c564615318eec9afc966e4913ec4c..b0264407710db30308c9ec576dedf2c6b782c50b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@   …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @…  …    -  9  }  10  }  - 10    11    - 11  func getContent… 12  func getContent…  - 12 -  return "Hel… 13 +  content := …  -      14 +  return cont…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@   …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @…  …    +  9  }  10  }  + 10    11    + 11  func getContent… 12  func getContent…  + 12 -  return "Hel… 13 +  content := …  +      14 +  return cont…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden index 8f750e45dde66d7378ebd1c3cac9dcc42fd35928..4e7f05b11169a5d1092880d15d183682b71fe50b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@   …    -  9  }  10  }  - 10    11    - 11  func getContent(… 12  func getContent(… - 12 -  return "Hell… 13 +  content := s… -      14 +  return conte… - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@   …    +  9  }  10  }  + 10    11    + 11  func getContent(… 12  func getContent(… + 12 -  return "Hell… 13 +  content := s… +      14 +  return conte… + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden index 88d0334c820b4178059342fa2e1da9abc31554a7..82c452e1b4f4d114d001325320320a10f03720cb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@   …    -  9  }  10  }  - 10    11    - 11  func getContent(… 12  func getContent(…  - 12 -  return "Hell… 13 +  content := s…  -      14 +  return conte…  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@   …    +  9  }  10  }  + 10    11    + 11  func getContent(… 12  func getContent(…  + 12 -  return "Hell… 13 +  content := s…  +      14 +  return conte…  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden index 7f61027cd84e09baa6fbb032373a17dd2604e793..794458f1b7320c6ad2c4658736ee2a8a0db5255d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent()… 12  func getContent()… - 12 -  return "Hello… 13 +  content := st… -      14 +  return content - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent()… 12  func getContent()… + 12 -  return "Hello… 13 +  content := st… +      14 +  return content + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden index 9bb7c27c780a323330ce8809d49ca3a530e3446c..42acae5056e9b31b3a2a94ac070e3838f366a762 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent()… 12  func getContent()…  - 12 -  return "Hello… 13 +  content := st…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent()… 12  func getContent()…  + 12 -  return "Hello… 13 +  content := st…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden index ce5e92957c386876a86cb4560a4eadf8a7e08dc7..ff30d8a51759e6e808a330bfd5bdfcd5fddc9589 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() … 12  func getContent() … - 12 -  return "Hello,… 13 +  content := str… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() … 12  func getContent() … + 12 -  return "Hello,… 13 +  content := str… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden index 82adeb499fc4b5b6d15f9553765f3d1b4d1979dc..8ed5b991d0363b888fdc57337115407fb28f458b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() … 12  func getContent() …  - 12 -  return "Hello,… 13 +  content := str…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() … 12  func getContent() …  + 12 -  return "Hello,… 13 +  content := str…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden index ae6953eb26ea0aaeddb450b4da018c5cdc3797d0..a3926436ceeb2f1148818fb4dd5ba35f3374fca3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() s… 12  func getContent() s… - 12 -  return "Hello, … 13 +  content := stri… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() s… 12  func getContent() s… + 12 -  return "Hello, … 13 +  content := stri… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden index 51a38de9c1ef157ddf956975a705bd8c99927d91..9adb799de26c95d7241c8b11d86ed4005be66dd1 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() s… 12  func getContent() s…  - 12 -  return "Hello, … 13 +  content := stri…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() s… 12  func getContent() s…  + 12 -  return "Hello, … 13 +  content := stri…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden index 24c8e4d4b1fb74c8c2ab1e52127bc7dfdef8cde0..563d9d15b14b52bf00b2398b953768a24554cdca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() st… 12  func getContent() st… - 12 -  return "Hello, w… 13 +  content := strin… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() st… 12  func getContent() st… + 12 -  return "Hello, w… 13 +  content := strin… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden index cc0efd45a2cd5aa42b0734988df64ea2d05f880c..b75316bae41767af6828566fa9f27381ab9f4353 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() st… 12  func getContent() st…  - 12 -  return "Hello, w… 13 +  content := strin…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() st… 12  func getContent() st…  + 12 -  return "Hello, w… 13 +  content := strin…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden index 4de6f41ffaf0e87c4eda3263b57f42d84fc38aea..af7c006fdca898221797b5d009007df80af4e88c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() str… 12  func getContent() str… - 12 -  return "Hello, wo… 13 +  content := string… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() str… 12  func getContent() str… + 12 -  return "Hello, wo… 13 +  content := string… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden index 77419b66cf6caa014ddcb5324c3d8fe08b0fbdda..7e0baff7b12e3ac8062e989f6b35b2c58beb4f0e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() str… 12  func getContent() str…  - 12 -  return "Hello, wo… 13 +  content := string…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() str… 12  func getContent() str…  + 12 -  return "Hello, wo… 13 +  content := string…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden index 5992c78e7352a1d59605deaa364ff8b3e6262bf9..924c3c3520a23be31ad1d8a8f082eaf7ceb8d02a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() stri… 12  func getContent() stri… - 12 -  return "Hello, wor… 13 +  content := strings… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() stri… 12  func getContent() stri… + 12 -  return "Hello, wor… 13 +  content := strings… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden index 544a55196beb09c4784f668be8326bd5edb7e34e..e64de595007242776563eb990c8f9a14df9c9b81 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() stri… 12  func getContent() stri…  - 12 -  return "Hello, wor… 13 +  content := strings…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() stri… 12  func getContent() stri…  + 12 -  return "Hello, wor… 13 +  content := strings…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden index be01c935ada5686d689419f32873e280ac87b819..07f7338ab24d6cece5a05199c0eddea15b76d037 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() strin… 12  func getContent() strin… - 12 -  return "Hello, worl… 13 +  content := strings.… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() strin… 12  func getContent() strin… + 12 -  return "Hello, worl… 13 +  content := strings.… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden index c7b19c70c3cf547cfd8d8468426a767c3f1bc8eb..bd329ddbe651c2020d9c375dc2225409f26e5d10 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() strin… 12  func getContent() strin…  - 12 -  return "Hello, worl… 13 +  content := strings.…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() strin… 12  func getContent() strin…  + 12 -  return "Hello, worl… 13 +  content := strings.…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden index 8cf7d33c9dc489bfac63f416d78f90e8c9b240ee..9da29b78888a0707ec6346182bc2be2076c196d8 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string… 12  func getContent() string… - 12 -  return "Hello, world… 13 +  content := strings.T… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string… 12  func getContent() string… + 12 -  return "Hello, world… 13 +  content := strings.T… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden index ed1e489534d52ccb007df6102fcdd6955eacbe11..2dc22f76729d35a7d4986a3c06a93b75412e78ce 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string… 12  func getContent() string…  - 12 -  return "Hello, world… 13 +  content := strings.T…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string… 12  func getContent() string…  + 12 -  return "Hello, world… 13 +  content := strings.T…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden index 264b2f157f302c9efe51aa19fdf6652b21966357..3005c2d65585c7701906aca1977fdd313aef3daf 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string { 12  func getContent() string { - 12 -  return "Hello, world!" 13 +  content := strings.To… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string { 12  func getContent() string { + 12 -  return "Hello, world!" 13 +  content := strings.To… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden index 769077f8ddd3f8945e593a7dc829e32d0fc2a0da..a8257a2e0d6a413652457e2bcc3f06a11e6714f5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string { 12  func getContent() string {  - 12 -  return "Hello, world!" 13 +  content := strings.To…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string { 12  func getContent() string {  + 12 -  return "Hello, world!" 13 +  content := strings.To…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden index 41175031e8f238872ba86604bed92cc3852ee38f..52664de587619e430a34349422f3b136bb4d4195 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToU… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToU… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden index f6988276acd56bd73a1e4f5ae3896c423a6d2b06..bf8b834c55578c4a0a77af7f75fa9d9c4ea25de0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToU…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToU…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden index fc6241eae81aa7d386813dc04432d47876ce0fd7..999b221e6ea27bd181aac0ec4c9142dd72118cfc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUp… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUp… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden index 7d9ec994c9e1e13c40f954879feb1a5d1f600439..0cf5fe69f9a390fc0fed4d1b12631ee66e955582 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUp…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUp…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden index 2083a6eae970030b41a3cd0b941863927c55a185..d2fe053588f2dde9e04bd3a7395458ce688b6c43 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpp… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpp… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden index 760cdb047ee5ac89224e2c48b663bb09ae577433..a121d81ec956d852a040f73050c374342bfa2829 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpp…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpp…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden index b38d7f6d21bd1f4f4e8f1929bb0d0c12f509e184..85a5f5222482d19b5eeb2ca08ef08e9362bec782 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUppe… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUppe… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden index 46afcacf662110f5f75a26556e554bd871df6d45..4c2f88da63855111c8c6bb0815ade1c821412e81 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUppe…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUppe…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden index 414b8830390e69f43c724734053a31a2461b0d41..e747ba480b9e8abcc3e69e5f772b384595ecc8bf 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden index e64acc77814513ff1650e77ddab0e195cb2b2cdc..fabcd110d70e0e486f351627d57257cadcb8455d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden index d2b86deb4a1113f6313c40caf31837d4900c64eb..ff09ba5c4f148ba96d9753b283b32698be073c91 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden index b22b38baab4104282cf5dc1d7a49d0882c883fdd..b9cd61bc908a493caf7f40da48f3eb0859889568 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper(…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden index 12827013422b14ab15f0d124a65588c5ab1a47dc..85e5fb1803c3302916179257454362b2f6ed41a9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden index 2d50d36a9bd2b63bec0e0b463dccb5a0b7ebfd8d..efc787d60e80cf51c41d2f30d02f24921798296d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden index dcfc005d89889ca3216f1d13d578332f24519b88..914cfb8748038102dd0894cb11e6090b4b52e923 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden index a8ba35922b863854e348ee949bca17304598158f..c76f710f1ad4fb65b47a941909619f7f64bd05de 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("H…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden index 7160250698adaad0fb9fdf21e6602866577c2e95..4d7f80e148979a218b3a784bcab2b96149166c90 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden index 2aa2d2d1e9cd296520d4c0a0362586d221ea5547..1299f72ff1e9681ab096a57e67b8a5f9b4b73a12 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("He…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden index 365fa7567ae83238ef14c9853b6019f8d9d76a81..7f7dfad2600ff90693144d8a5393a825bf4a11f4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden index 591f662b6b13b1a93be2394e776aa663585659b2..700b69ac0bbc21d1b4a287f61358e2d47d57b7df 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hel…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden index 4cbe0d54aae59078129851e100b6228f678b00d0..a596b93dba70f677619d625fbcd5f44e2b064e52 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden index b03ee8eadedfda27d6989fa531603bac3b653f59..e980c52dbd96b2a5be2b04a2080e3b87cfc666e2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hell…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden index dad8e4a09a350c3085942ab29c31fb0476129a76..5e07ae811d80238998bb78aeda3818ca9735478b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10 [38;2;32;31;38;48;2;241;239;239m }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden index 361ce9c4119c1ec870b3f16775dc9ca5fc28bc71..d810bd5c2acf15b68d311c57f38106897628f2c3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden index ac5688381c2a73dd8e83189f88ce1464ba55362d..4155df2b78c7ef45f6c82baae3c39faa791dd57d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden index 9335a76abd6d37a2dc52c20bf38f1e3470455ebe..9fb1d0cd2fba45363ab5530ed7f21125714c6f62 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello,…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden index a089778adc04f6ae5ebc54c0576babaae46c2579..7107a97c672aa489dedd1234e331de7bb9c372f5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, … -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, … +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden index d74e0e4dfd8964ad1dbce8d4b6bab2629999939b..07511a06e104c7dd60f41610282021356bc6a7f3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, …  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, …  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden index 159da99b8898d95891669209ebe5369e52d105de..c2d2506bfce0ba84af89d5cca35ef0660111a47a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden index 7bf03eaa9224a70e982ddce0073d9f36f04ae547..15f77c75d8f997a4efcc028cd8f0575cf91b1cfc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, W…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden index e3135d8681efc69853b2381184d4f7b8a16e8b32..bcae9cb87fb6b6c03452a38f53e3beadb2dd650b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden index de2c0c5aa41e04c385374e75a2a0f0255faaefce..ed71765c436c9fc771d069f2fee73cc33f99f290 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wo…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden index 56052a977fce039b57aeee0d0ec402a1d1a04bed..b81411c9623832e8659a8004ccefef6cbc4d4e8f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden index f61adea5d8c82ff47df19349face74487f1257ce..cbf89a7e9dac0ec54dd5326782efda630056e067 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Wor…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden index 58be05012e0b61d77d34126e7741d50cbbd41277..e8ce1797719912c6fcb5cf7794633107f367a8cd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden index a1f145e36a97eae035efea876b85d32b3fc390ff..55647a9609994c060d5f6638c0163365e0bf2dec 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, Worl…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden index 6fd5678e6859b1fe5e54afb1b54dbc894b0595d4..8cfabbc26d01f4814656a2e633d928f048c8eab1 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden index 58d22841956cfae75a87aaeed04eb8b3dd7ca586..30d6ff25eb3646c106d15d45f4c47ee5592bd5da 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden index 31c3e8981d90b33b7eb45e9c8b1bddf6cc36efca..9b2d6d86a6f7b2c647057a6c2e16c20cd272ff1a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!… -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!… +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden index 25254c9b09f9e582887c8bc738de4d1e30ef260c..6e63ddf7f20b3fe6164500efb0bcafa6960341ec 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!…  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!…  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden index 5546a1538824cf03333077aa3b8bcc02f30d5f14..398288f3f5c1f884adc8016b5c1a53c0b88aae54 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!") +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden index fcee0eac1c1e60e4bfa27522ede8c7fe0ca9a49e..8ccc2750fcd4a188c7681a0544201e4266411397 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden index 376bae2594d8e175cdd84b90846fe43c639c4d69..9dfd2891ab3ba67f956bc1b13e07cd743e35aef6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden index 95d673f67bfd11f2bf5f56b6cc33960160f4be1f..5a38ce952052604f729078de8767434fad1fe8f9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden index 12fb2103fda145ee2c326171ba74ede6b8500a69..0f1c5c4972b103fd0489a63d77544f55798d9ecd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden @@ -1,15 +1,15 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden index f5ae08f760e597d50e72dcb4c99fe13136fcad89..d7f200ae4d90de0791a936a1d2b734e87e315403 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden @@ -1,16 +1,16 @@ -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  \ No newline at end of file +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden index 905f4640bb21bb8c092c0ca5fcab313591cb1796..0e3ddca3cacc4d59f010ec67c388ca9dc81ca3a5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden @@ -1,16 +1,16 @@ -   -   -   -   -   -   -   -   -   -   - 1 - 1 - 1 -   -   - 1 \ No newline at end of file +   +   +   +   +   +   +   +   +   +   + 1 + 1 + 1 +   +   + 1 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden index c9e63d8c4abc76931039144b413cb824f8ff9bb2..bdbc785417781de8c26603e513348aac672072d2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden @@ -1,16 +1,16 @@ -  … -  2 -  3 -  4 -   -  5 -  6 -  7 -  … -  9 - 10 - 11 - 12 -   -   - 13 \ No newline at end of file +  … +  2 +  3 +  4 +   +  5 +  6 +  7 +  … +  9 + 10 + 11 + 12 +   +   + 13 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden index 7cdf60705770462ea57c0f4c1a1e0fe58ae167eb..81a8b6f99b5292d9087bd47392b7298ad9efe62b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden @@ -1,16 +1,16 @@ -  …  -  2  -  3  -  4  -    -  5  -  6  -  7  -  …  -  9  - 10  - 11  - 12  -    -    - 13  \ No newline at end of file +  …  +  2  +  3  +  4  +    +  5  +  6  +  7  +  …  +  9  + 10  + 11  + 12  +    +    + 13  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden index 092ad8837b7435ac3870ec87a0ddbdaceb48282c..f905057da2ebaf25af8af31bd6c1daebd4672736 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden @@ -1,16 +1,16 @@ -  …   -  2   -  3   -  4   -     -  5   -  6   -  7   -  …   -  9   - 10   - 11   - 12   -     -     - 13   \ No newline at end of file +  …   +  2   +  3   +  4   +     +  5   +  6   +  7   +  …   +  9   + 10   + 11   + 12   +     +     + 13   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden index f31fccda9d0728eea91654a89623c27442cfbe60..5620afb69008624efe3be1562152c84e8e3f9709 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden @@ -1,16 +1,16 @@ -  …    -  2    -  3    -  4    -      -  5    -  6    -  7    -  …    -  9  1 - 10  1 - 11  1 - 12    -    1 -    1 - 13  1 \ No newline at end of file +  …    +  2    +  3    +  4    +      +  5    +  6    +  7    +  …    +  9  1 + 10  1 + 11  1 + 12    +    1 +    1 + 13  1 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden index 3c4ec8dbc951a899dc681f2b0774a9d66523c85b..edc8020ff9eadc3895a21ebac23c9e7ca4f79125 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden @@ -1,16 +1,16 @@ -  …   … -  2   2 -  3   3 -  4   4 -     5 -  5   6 -  6   7 -  7   8 -  …   … -  9  10 - 10  11 - 11  12 - 12    -    13 -    14 - 13  15 \ No newline at end of file +  …   … +  2   2 +  3   3 +  4   4 +     5 +  5   6 +  6   7 +  7   8 +  …   … +  9  10 + 10  11 + 11  12 + 12    +    13 +    14 + 13  15 \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden index f5ec574408debd36b433aed72b3e8881e4a47fd4..95b2f17149641642d13aa4394fdee4af20134d36 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden @@ -1,16 +1,16 @@ -  …   …  -  2   2  -  3   3  -  4   4  -     5  -  5   6  -  6   7  -  7   8  -  …   …  -  9  10  - 10  11  - 11  12  - 12     -    13  -    14  - 13  15  \ No newline at end of file +  …   …  +  2   2  +  3   3  +  4   4  +     5  +  5   6  +  6   7  +  7   8  +  …   …  +  9  10  + 10  11  + 11  12  + 12     +    13  +    14  + 13  15  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden index 7badb5543980ec3a8bb31512ecb69da2396aef5e..d94d83344297425bc5ec6e3733ce5b7439b391be 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden @@ -1,16 +1,16 @@ -  …   … … -  2   2   -  3   3   -  4   4   -     5 + -  5   6   -  6   7   -  7   8   -  …   … … -  9  10   - 10  11   - 11  12   - 12    - -    13 + -    14 + - 13  15   \ No newline at end of file +  …   … … +  2   2   +  3   3   +  4   4   +     5 + +  5   6   +  6   7   +  7   8   +  …   … … +  9  10   + 10  11   + 11  12   + 12    - +    13 + +    14 + + 13  15   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden index fa3542fb89a9cdfa58e94fc27e8d6e7650176e40..2f4e6d31a2900b70c080aff8d224b27052c17b36 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden @@ -1,16 +1,16 @@ -  …   …  … -  2   2   -  3   3   -  4   4   -     5 +  -  5   6   -  6   7   -  7   8   -  …   …  … -  9  10   - 10  11   - 11  12   - 12    -  -    13 +  -    14 +  - 13  15   \ No newline at end of file +  …   …  … +  2   2   +  3   3   +  4   4   +     5 +  +  5   6   +  6   7   +  7   8   +  …   …  … +  9  10   + 10  11   + 11  12   + 12    -  +    13 +  +    14 +  + 13  15   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden index 980ddd8d547ee6d9622b58b31dc52c050bf07c55..f103ad6593724b4c0988764a358588fa06b7c221 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden @@ -1,16 +1,16 @@ -  …   …  … -  2   2    -  3   3  … -  4   4  … -     5 + … -  5   6  ) -  6   7    -  7   8  … -  …   …  … -  9  10  } - 10  11    - 11  12  … - 12    - … -    13 + … -    14 + … - 13  15  } \ No newline at end of file +  …   …  … +  2   2    +  3   3  … +  4   4  … +     5 + … +  5   6  ) +  6   7    +  7   8  … +  …   …  … +  9  10  } + 10  11    + 11  12  … + 12    - … +    13 + … +    14 + … + 13  15  } \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden index 118d4c2e1865d9cc50cf1a9f4187792f1c368772..60d93b3daaab776a5fcac41802292026ad84c3bb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden @@ -1,16 +1,16 @@ -  …   …  @… -  2   2    -  3   3  i… -  4   4   … -     5 +  … -  5   6  )  -  6   7    -  7   8  f… -  …   …  @… -  9  10  }  - 10  11    - 11  12  f… - 12    -  … -    13 +  … -    14 +  … - 13  15  }  \ No newline at end of file +  …   …  @… +  2   2    +  3   3  i… +  4   4   … +     5 +  … +  5   6  )  +  6   7    +  7   8  f… +  …   …  @… +  9  10  }  + 10  11    + 11  12  f… + 12    -  … +    13 +  … +    14 +  … + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden index abbdb692cb6f6c09df620c88f6b0a6b86e4ef96f..2a7e9e3b68ba0b2ee5fcb7a6dbdeed3470e51027 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden @@ -1,16 +1,16 @@ -  …   …  @@… -  2   2    -  3   3  im… -  4   4   … -     5 +  … -  5   6  )  -  6   7    -  7   8  fu… -  …   …  @@… -  9  10  }  - 10  11    - 11  12  fu… - 12    -  … -    13 +  … -    14 +  … - 13  15  }  \ No newline at end of file +  …   …  @@… +  2   2    +  3   3  im… +  4   4   … +     5 +  … +  5   6  )  +  6   7    +  7   8  fu… +  …   …  @@… +  9  10  }  + 10  11    + 11  12  fu… + 12    -  … +    13 +  … +    14 +  … + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden index afab1410ed5fa9a7ff215fc3f7ca69123ce48981..7db558af9f520d6e3edf301d70511fdb1737a6fd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden @@ -1,16 +1,16 @@ -  …   …  @@ … -  2   2    -  3   3  imp… -  4   4   … -     5 +  … -  5   6  )  -  6   7    -  7   8  fun… -  …   …  @@ … -  9  10  }  - 10  11    - 11  12  fun… - 12    -  … -    13 +  … -    14 +  … - 13  15  }  \ No newline at end of file +  …   …  @@ … +  2   2    +  3   3  imp… +  4   4   … +     5 +  … +  5   6  )  +  6   7    +  7   8  fun… +  …   …  @@ … +  9  10  }  + 10  11    + 11  12  fun… + 12    -  … +    13 +  … +    14 +  … + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden index 47898c566201f8d5c4ce8cb87e2e317f9157f323..2efa7162f614697273f6e96abff01e0d025e50dc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden @@ -1,16 +1,16 @@ -  …   …  @@ -… -  2   2    -  3   3  impo… -  4   4   … -     5 +  … -  5   6  )  -  6   7    -  7   8  func… -  …   …  @@ -… -  9  10  }  - 10  11    - 11  12  func… - 12    -  … -    13 +  … -    14 +  … - 13  15  }  \ No newline at end of file +  …   …  @@ -… +  2   2    +  3   3  impo… +  4   4   … +     5 +  … +  5   6  )  +  6   7    +  7   8  func… +  …   …  @@ -… +  9  10  }  + 10  11    + 11  12  func… + 12    -  … +    13 +  … +    14 +  … + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden index b5d0f35783d462c9438357bef765d2d60e43ed19..709e481c17b8c7e3286079be68886de588ecfa17 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2… -  2   2    -  3   3  impor… -  4   4   "… -     5 +  "… -  5   6  )  -  6   7    -  7   8  func … -  …   …  @@ -9… -  9  10  }  - 10  11    - 11  12  func … - 12    -  r… -    13 +  c… -    14 +  r… - 13  15  }  \ No newline at end of file +  …   …  @@ -2… +  2   2    +  3   3  impor… +  4   4   "… +     5 +  "… +  5   6  )  +  6   7    +  7   8  func … +  …   …  @@ -9… +  9  10  }  + 10  11    + 11  12  func … + 12    -  r… +    13 +  c… +    14 +  r… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden index 58ed4f19ce4870ebe5dd6296c145d13f08f2044f..bcce9fbabe0a30bcb1e1d6e76488e69909fbf8d6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,… -  2   2    -  3   3  import… -  4   4   "f… -     5 +  "s… -  5   6  )  -  6   7    -  7   8  func m… -  …   …  @@ -9,… -  9  10  }  - 10  11    - 11  12  func g… - 12    -  re… -    13 +  co… -    14 +  re… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,… +  2   2    +  3   3  import… +  4   4   "f… +     5 +  "s… +  5   6  )  +  6   7    +  7   8  func m… +  …   …  @@ -9,… +  9  10  }  + 10  11    + 11  12  func g… + 12    -  re… +    13 +  co… +    14 +  re… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden index 73b420a33879df651950fb58d29e985f3d9d5e0a..61d7e3de2443465b4dd4cdc93a0c2919d84442d8 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6… -  2   2    -  3   3  import ( -  4   4   "fm… -     5 +  "st… -  5   6  )  -  6   7    -  7   8  func ma… -  …   …  @@ -9,5… -  9  10  }  - 10  11    - 11  12  func ge… - 12    -  ret… -    13 +  con… -    14 +  ret… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6… +  2   2    +  3   3  import ( +  4   4   "fm… +     5 +  "st… +  5   6  )  +  6   7    +  7   8  func ma… +  …   …  @@ -9,5… +  9  10  }  + 10  11    + 11  12  func ge… + 12    -  ret… +    13 +  con… +    14 +  ret… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden index e67fa43de7a3152291a9b08fad158fe4b8d8ff5a..21c3be44e09830309a9038b0126be25c08e7d068 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 … -  2   2    -  3   3  import (  -  4   4   "fmt" -     5 +  "str… -  5   6  )  -  6   7    -  7   8  func mai… -  …   …  @@ -9,5 … -  9  10  }  - 10  11    - 11  12  func get… - 12    -  retu… -    13 +  cont… -    14 +  retu… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 … +  2   2    +  3   3  import (  +  4   4   "fmt" +     5 +  "str… +  5   6  )  +  6   7    +  7   8  func mai… +  …   …  @@ -9,5 … +  9  10  }  + 10  11    + 11  12  func get… + 12    -  retu… +    13 +  cont… +    14 +  retu… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden index 07e8afd1fb5d87b6f7ac1a833989e9c73f7a08ae..0cc1dbbc757bd3b3894780b505fc6e3be121fe71 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +… -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "stri… -  5   6  )  -  6   7    -  7   8  func main… -  …   …  @@ -9,5 +… -  9  10  }  - 10  11    - 11  12  func getC… - 12    -  retur… -    13 +  conte… -    14 +  retur… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +… +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "stri… +  5   6  )  +  6   7    +  7   8  func main… +  …   …  @@ -9,5 +… +  9  10  }  + 10  11    + 11  12  func getC… + 12    -  retur… +    13 +  conte… +    14 +  retur… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden index 94299ef624a3fbfeb83bfd0a8c412f040314afd4..0aaa48d16b872c5c5eb14127d64718a9499c10c0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2… -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strin… -  5   6  )  -  6   7    -  7   8  func main(… -  …   …  @@ -9,5 +1… -  9  10  }  - 10  11    - 11  12  func getCo… - 12    -  return… -    13 +  conten… -    14 +  return… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2… +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strin… +  5   6  )  +  6   7    +  7   8  func main(… +  …   …  @@ -9,5 +1… +  9  10  }  + 10  11    + 11  12  func getCo… + 12    -  return… +    13 +  conten… +    14 +  return… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden index 38c4c162a2bdfcbb2aec1952c7d797dadbe8c9d9..7d600f2db3d00182e809049ff5adb1580bd7cb60 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,… -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "string… -  5   6  )  -  6   7    -  7   8  func main()… -  …   …  @@ -9,5 +10… -  9  10  }  - 10  11    - 11  12  func getCon… - 12    -  return … -    13 +  content… -    14 +  return … - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,… +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "string… +  5   6  )  +  6   7    +  7   8  func main()… +  …   …  @@ -9,5 +10… +  9  10  }  + 10  11    + 11  12  func getCon… + 12    -  return … +    13 +  content… +    14 +  return … + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden index 8d96b56fe8a222fadf2b62364256c2597a4f5e2d..d881094a166ad9b355552849e92ec5749d627735 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7… -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings" -  5   6  )  -  6   7    -  7   8  func main() { -  …   …  @@ -9,5 +10,… -  9  10  }  - 10  11    - 11  12  func getCont… - 12    -  return "… -    13 +  content … -    14 +  return c… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7… +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings" +  5   6  )  +  6   7    +  7   8  func main() { +  …   …  @@ -9,5 +10,… +  9  10  }  + 10  11    + 11  12  func getCont… + 12    -  return "… +    13 +  content … +    14 +  return c… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden index 009000c442042aabb50bdff598002b1b92e5d0fc..4217d71dc4197d0d6d6d4c2e63dc4edc59949d68 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 … -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6… -  9  10  }  - 10  11    - 11  12  func getConte… - 12    -  return "H… -    13 +  content :… -    14 +  return co… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 … +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6… +  9  10  }  + 10  11    + 11  12  func getConte… + 12    -  return "H… +    13 +  content :… +    14 +  return co… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden index 36412d17092b292702df8dccb64da381f6b7439f..31690265f34138909f1e8a40a3a251ffc2ad42d0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @… -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 … -  9  10  }  - 10  11    - 11  12  func getConten… - 12    -  return "He… -    13 +  content :=… -    14 +  return con… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @… +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 … +  9  10  }  + 10  11    + 11  12  func getConten… + 12    -  return "He… +    13 +  content :=… +    14 +  return con… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden index d6ce5b40b7f1ded424b842c7419ebfd3422d8bea..a3fffe0469fbc521b741de6a2e314cb3bdadf436 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@  -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @… -  9  10  }  - 10  11    - 11  12  func getContent… - 12    -  return "Hel… -    13 +  content := … -    14 +  return cont… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@  +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @… +  9  10  }  + 10  11    + 11  12  func getContent… + 12    -  return "Hel… +    13 +  content := … +    14 +  return cont… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden index 1d8d1a7b102989665a6fb5daa3f45671e240bb9a..37af8c75471d487bc9ce659f2de98a7e7e42870f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@  -  9  10  }  - 10  11    - 11  12  func getContent(… - 12    -  return "Hell… -    13 +  content := s… -    14 +  return conte… - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@  +  9  10  }  + 10  11    + 11  12  func getContent(… + 12    -  return "Hell… +    13 +  content := s… +    14 +  return conte… + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden index cd64972ae97ea3a43e6d8bbec01f6556e14ba209..2e63b76a4b3f7d6aacf52480e18db17352d4cf34 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent()… - 12    -  return "Hello… -    13 +  content := st… -    14 +  return content - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent()… + 12    -  return "Hello… +    13 +  content := st… +    14 +  return content + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden index 9630522016ffb5c9fbcc1b35c79af01807a461d6..dc0caab7b660c9a52b8e139c31cb227c321db53d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() … - 12    -  return "Hello,… -    13 +  content := str… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() … + 12    -  return "Hello,… +    13 +  content := str… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden index c968b68bbc5571f9e3a0ca7a57b8465c8d5d501c..84062eff9ec07a1e44368c7c7407258bb69eb7c0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() s… - 12    -  return "Hello, … -    13 +  content := stri… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() s… + 12    -  return "Hello, … +    13 +  content := stri… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden index 1e8e394258062076591dbadd12ab6e3062b354e1..b67a7198bdfaaa9885074aaad8cda50abfdb690e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() st… - 12    -  return "Hello, w… -    13 +  content := strin… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() st… + 12    -  return "Hello, w… +    13 +  content := strin… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden index 106501b3c9003cd8d663ee80f6ff7e8c6432e413..02f35ada096715621f1bca97b0fd369848451e35 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() str… - 12    -  return "Hello, wo… -    13 +  content := string… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() str… + 12    -  return "Hello, wo… +    13 +  content := string… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden index f1dcb3abfb3eda3d465699211b3fae06258e55c5..c024e0e5e892a2a9cc2afb388237bd4a2acba0ad 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() stri… - 12    -  return "Hello, wor… -    13 +  content := strings… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() stri… + 12    -  return "Hello, wor… +    13 +  content := strings… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden index 5fa2170cf92f1881d4ba6e7f7a1b21a7092ed448..c1672c154d36a94e6b02b9ba38e0ac6c6abfd72d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() strin… - 12    -  return "Hello, worl… -    13 +  content := strings.… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() strin… + 12    -  return "Hello, worl… +    13 +  content := strings.… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden index cc742db50aa4a556f10f963483e267783e2ae463..8867a62805e968f78b15ca82407206444c528033 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string… - 12    -  return "Hello, world… -    13 +  content := strings.T… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string… + 12    -  return "Hello, world… +    13 +  content := strings.T… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden index 9ec6dbba298c91f82166508728172710372b77b5..6ed9f92a19d7365e8f10c3d37249f6315abd6201 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string { - 12    -  return "Hello, world!" -    13 +  content := strings.To… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string { + 12    -  return "Hello, world!" +    13 +  content := strings.To… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden index f33c7a7aef1dc8c2d56e61cfbef846fdf4641ec6..d0cea8c9256564eb4e2a79fd5a60621741fc8816 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToU… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToU… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden index c87bc8d61c1341c9a066c501ff5b230b04ce0277..960cd4e7e133f83b2c4337d72c51fd6f7dc0b438 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUp… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUp… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden index ab2f47e1d7e5ada9820747d9305cba1e7aa63710..b8921437ac0507a8bfe7bad3406e9ca90aebdc34 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpp… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpp… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden index bc1c6c04db45d3d8dfddf23440dcfa430cec7fb0..65d80ac49069a1fc792ed569f27fda08181b39b6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUppe… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUppe… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden index aa382a513632ffd40e9fee31463d5cb29213e441..01af680be1a1d2c9b33337c0dca64a1e307907b8 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden index 6c721a82c4afc6423070b7c07cf909ec055bcc5d..b2274edf36e65122d9d76500a8b8316988cc7a4a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper(… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper(… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden index d2d80c72db4368679e3cc87c89143633cec3d8fd..70690b6d07448a96a40ac67ce0c9a87e572a7987 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden index 943719010fe4e96b29d702c2e49533bc5577cd2b..ef5417a4f36ea0afbdd1ffc89d4e39c234f1ef93 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("H… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("H… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden index 591ce67300df856c778afe8c883818cd0ef40918..8860677b641fb194fa6ad2a78b1aa0a35a08573e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("He… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("He… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden index 25ab875c4f1b5cb40ce08eb24503e93aa79bb083..4b6c59f944c01fd6b7b68cb27a46c93f85104889 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hel… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hel… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden index 58a8199865345c094709c677c238af4d55126867..b277350fc2c2feb4725ade519bfd2e98885cfbe5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hell… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hell… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden index 83ede19e2d8d68234852af840c82cc98d6358968..6d0fa9d423636ded10d65582351ef9210e59d780 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden index f531bcbf029d81258a3a77073cc469dfab59da36..d1c2aa59fd22631b7eb1bda543c7b331ff92a161 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello,… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello,… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden index 42d3bf74913c04219f87a6044becf0967ae35046..b8c5e56a288b3fed2cdc58d2681b13004aadcb9b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, … -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, … +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden index 8a0e974e715ecfd2d15beb026b8887eb98aa15c2..9060a49c38eb3c4cfe5bf1e1014810446a953ded 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, W… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, W… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden index 5eaaa47e038ee480ebd8825cc8b7cfe3b05686f7..ba216235877260b4f4b3b6f4c16956560f8652eb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, Wo… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, Wo… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden index 08ad6ddffccc6ba92cf63749775a5ccbb6ffdfec..1a868d5c5bc77ddfe5e5c6b7ba3b46b98643db13 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, Wor… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, Wor… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden index 2dff941c3c03509f116b639f725995df15e050e7..7ec01bc17cf2ac4aec08a0f5228c3ffdc73f7893 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, Worl… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, Worl… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden index 6c4244529a4fa5aa863b4d7654fa230417d8415f..28f0e74fa09a6290e99e2cfb745da8f49ab46ecc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden index e142e86ec29f9ccfc392512fb6a1ebdd7ef47b79..c0f81bfe06402bd62720634029ffbfb8d7310ec2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!… -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!… +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden index 0fc779146b016da6d50f41adef48995ac66ee3ce..11fad5bb9b603f9f7dc60e358a8363521faafbe4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!") -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!") +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden index 4833a8a0263aada505f2e115c5dfb9fc469def67..601742405296c42cd6ef8ae4ab4a20b4a9a7d764 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden index 7b2771b39f26769a36ce9acd7c5b13bf61108298..0467f13a8ba119a7486c6465299a89782741e797 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden index 6cff1caaad1de797a272c79b02e692268b5649da..8177be0c3b3493bc896904c3aff8286e011c67eb 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden @@ -1,16 +1,16 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden index 9ec2cc1f1d60f2ab2e26aea0ac9860accd927534..f1c41e216a50b0c300d3d78eebd0cdc4bcace411 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  )   5  )  -  6     6    -  7  func main() {   7  func main() {  -  8 -  fmt.Println("Hello,…  8 +  content := "Hello, … -       9 +  fmt.Println(content) -  9  }  10  }  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  )   5  )  +  6     6    +  7  func main() {   7  func main() {  +  8 -  fmt.Println("Hello,…  8 +  content := "Hello, … +       9 +  fmt.Println(content) +  9  }  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden index 473d996d55dd396c57a3f54ac33080501d3f692c..103b1f00ee55edd1d5260016e9e31152009bd690 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …unc main() {   7  …unc main() {  -  8 -… fmt.Println("Hello, …  8 +… content := "Hello, w… -       9 +… fmt.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …unc main() {   7  …unc main() {  +  8 -… fmt.Println("Hello, …  8 +… content := "Hello, w… +       9 +… fmt.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden index 270924bb42b6a2c148b550ae67c74fdb213980a9..54cfd448a0fc295f5294ad3546fd90cfb3a07d0a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …nc main() {   7  …nc main() {  -  8 -… fmt.Println("Hello, w…  8 +… content := "Hello, wo… -       9 +… fmt.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@ [48;2;113;154;252m   …    +  5  …   5  …  +  6     6    +  7  …nc main() {   7  …nc main() {  +  8 -… fmt.Println("Hello, w…  8 +… content := "Hello, wo… +       9 +… fmt.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden index a2d2007c22d981307c17247a23f0096a7d2f72b0..308cec604aa6074f374e6bebec273c608e1d03a9 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …c main() {   7  …c main() {  -  8 -… fmt.Println("Hello, wo…  8 +… content := "Hello, wor… -       9 +… fmt.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …c main() {   7  …c main() {  +  8 -… fmt.Println("Hello, wo…  8 +… content := "Hello, wor… +       9 +… fmt.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden index 407565b5ce6fe40545656ef814309fe4f35e7679..db2a3cbd742cddbc94c51548ec101ba30b2fe2ee 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  … main() {   7  … main() {  -  8 -…fmt.Println("Hello, wor…  8 +…content := "Hello, worl… -       9 +…fmt.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  … main() {   7  … main() {  +  8 -…fmt.Println("Hello, wor…  8 +…content := "Hello, worl… +       9 +…fmt.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden index 7e2988668b1be238ffe74db71886312f18c59a9d..fcb873fcaaca7f1d45ba193f3edb711b97a9565c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …main() {   7  …main() {  -  8 -…mt.Println("Hello, worl…  8 +…ontent := "Hello, world… -       9 +…mt.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …main() {   7  …main() {  +  8 -…mt.Println("Hello, worl…  8 +…ontent := "Hello, world… +       9 +…mt.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden index c0eebb94811fc3963094b942a6e3d92313570901..bbd50d6784da2025ffc8f93ef58c3c79ffee42fe 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …ain() {   7  …ain() {  -  8 -…t.Println("Hello, world…  8 +…ntent := "Hello, world!" -       9 +…t.Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …ain() {   7  …ain() {  +  8 -…t.Println("Hello, world…  8 +…ntent := "Hello, world!" +       9 +…t.Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden index d2d3307543e4ce996c82c51a5c30a75155c51865..b15ca2144154bb8ec46253fdaaf02ada24f683c5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …in() {   7  …in() {  -  8 -….Println("Hello, world!…  8 +…tent := "Hello, world!"  -       9 +….Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …in() {   7  …in() {  +  8 -….Println("Hello, world!…  8 +…tent := "Hello, world!"  +       9 +….Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden index 13d4a33d04fe3bf2a229c982082f9a13203ced3e..b61d425c10597c96687a9e37db860a979981fb28 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …n() {   7  …n() {  -  8 -…Println("Hello, world!")  8 +…ent := "Hello, world!"  -       9 +…Println(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …n() {   7  …n() {  +  8 -…Println("Hello, world!")  8 +…ent := "Hello, world!"  +       9 +…Println(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden index 393ec8889fce9e10eaf03c6648b160b5193d1f35..5cf0ff7d32079d024aded5167f414da85c2f663f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …() {   7  …() {  -  8 -…rintln("Hello, world!")   8 +…nt := "Hello, world!"  -       9 +…rintln(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …() {   7  …() {  +  8 -…rintln("Hello, world!")   8 +…nt := "Hello, world!"  +       9 +…rintln(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden index 90dcd606b64433a056bcf54b69e3467251d465a1..cb15f9065dee8dd7dc3a189dbe8540bb98112aac 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …) {   7  …) {  -  8 -…intln("Hello, world!")   8 +…t := "Hello, world!"  -       9 +…intln(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …) {   7  …) {  +  8 -…intln("Hello, world!")   8 +…t := "Hello, world!"  +       9 +…intln(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden index cede44c77dc6a1ad54e03e33a855ec1b8bee42eb..3c7fc14fe6f28e6505c453dbe8ba28802105606c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  … {   7  … {  -  8 -…ntln("Hello, world!")   8 +… := "Hello, world!"  -       9 +…ntln(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  … {   7  … {  +  8 -…ntln("Hello, world!")   8 +… := "Hello, world!"  +       9 +…ntln(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden index f7713314c869c193271796f8b44669708c12fd51..9391307c4864df8278226ab0a4b11031f5f0eaca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …{   7  …{  -  8 -…tln("Hello, world!")   8 +…:= "Hello, world!"  -       9 +…tln(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …{   7  …{  +  8 -…tln("Hello, world!")   8 +…:= "Hello, world!"  +       9 +…tln(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden index ec342bcd1a9dc48b955f1c585af2fd3c15591cdd..5df47877cf854360b115b8e4799a37a68d542c7e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…ln("Hello, world!")   8 +…= "Hello, world!"  -       9 +…ln(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…ln("Hello, world!")   8 +…= "Hello, world!"  +       9 +…ln(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden index 53cea6723e9d28d66cfac2371dc992d70a2bfd90..4ce601f6543d7b5b89452b08ef351e1c423d4315 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…n("Hello, world!")   8 +… "Hello, world!"  -       9 +…n(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…n("Hello, world!")   8 +… "Hello, world!"  +       9 +…n(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden index 2fb5652a4e2d05f3b4efd6e58cc9ecb71ce545c0..fcef78bca9399823199145133a26999a7c2dc2e0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…("Hello, world!")   8 +…"Hello, world!"  -       9 +…(content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…("Hello, world!")   8 +…"Hello, world!"  +       9 +…(content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden index adf8f07ef00c85c0bffc683abd31741b38d8f0d2..6f1af4f85f36e894a95895cda0d6b5cca1cbbed0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…"Hello, world!")   8 +…Hello, world!"  -       9 +…content)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…"Hello, world!")   8 +…Hello, world!"  +       9 +…content)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden index d7b7a7ea86c9d6477465c61aead42e974e1b938a..e95172efb5b4273238673f2e8f862c580bb54444 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…Hello, world!")   8 +…ello, world!"  -       9 +…ontent)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…Hello, world!")   8 +…ello, world!"  +       9 +…ontent)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden index 715237891b424eb91814b91a287b17d063a1d2b8..d7208ee2395040bd3fda5104b942b6728a5f8c3d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…ello, world!")   8 +…llo, world!"  -       9 +…ntent)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…ello, world!")   8 +…llo, world!"  +       9 +…ntent)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden index 6fa5925e13d0f617d23c8f62e692bbef68969dd2..5c0bdc4c4400432d7b35dafc89d44f7ac28200ab 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…llo, world!")   8 +…lo, world!"  -       9 +…tent)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…llo, world!")   8 +…lo, world!"  +       9 +…tent)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden index c0bf9235426e010557385870a5dd95e74bffb6b7..5e5a90e03fbf530a72e06633013cf86fd7b40886 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden @@ -1,7 +1,7 @@ -  …  @@ -5,5 +5,6 @@    …    -  5  …   5  …  -  6     6    -  7  …   7  …  -  8 -…lo, world!")   8 +…o, world!"  -       9 +…ent)  -  9  …  10  …  \ No newline at end of file +  …  @@ -5,5 +5,6 @@    …    +  5  …   5  …  +  6     6    +  7  …   7  …  +  8 -…lo, world!")   8 +…o, world!"  +       9 +…ent)  +  9  …  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden index 94b2873d06832d68d902b591c3e8ed07960d165f..a6d36a6489288364b085fba2622e42d4637f469d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  )  -  6   6    -  7   7  func main() {  -  8    -  fmt.Println("Hello, world!")  -     8 +  content := "Hello, world!"  -     9 +  fmt.Println(content)  -  9  10  }  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  )  +  6   6    +  7   7  func main() {  +  8    -  fmt.Println("Hello, world!")  +     8 +  content := "Hello, world!"  +     9 +  fmt.Println(content)  +  9  10  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden index 82e128dc76e583c6012e6bc43d81ed2142d2d98c..91caf4829d92fa626a187873b1c1cebfc8a559c1 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …unc main() {  -  8    -… fmt.Println("Hello, world!")  -     8 +… content := "Hello, world!"  -     9 +… fmt.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …unc main() {  +  8    -… fmt.Println("Hello, world!")  +     8 +… content := "Hello, world!"  +     9 +… fmt.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden index 69333d10986b5dfdf9a180e6a401c30944ec1686..78950359a2f9c0e22ae5d1a8d59df88c414ee637 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …nc main() {  -  8    -… fmt.Println("Hello, world!")  -     8 +… content := "Hello, world!"  -     9 +… fmt.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …nc main() {  +  8    -… fmt.Println("Hello, world!")  +     8 +… content := "Hello, world!"  +     9 +… fmt.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden index d57a93823a4a2927f8b583bee6f5a64b50ea427f..2454d4f72d88b8ec03e9aba1ffb03cc6481a719d 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …c main() {  -  8    -… fmt.Println("Hello, world!")  -     8 +… content := "Hello, world!"  -     9 +… fmt.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …c main() {  +  8    -… fmt.Println("Hello, world!")  +     8 +… content := "Hello, world!"  +     9 +… fmt.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden index 83b84378f67a116b64104064d37c9eeafdfc5184..0ac75887bc4f00bf37b98f82d15561231372c267 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  … main() {  -  8    -…fmt.Println("Hello, world!")  -     8 +…content := "Hello, world!"  -     9 +…fmt.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  … main() {  +  8    -…fmt.Println("Hello, world!")  +     8 +…content := "Hello, world!"  +     9 +…fmt.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden index 39923d1ad17cc9d079cb7e9ca069b666717f90e9..90c4d2f81484696490887b7d7f2aabbb7dcc2509 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …main() {  -  8    -…mt.Println("Hello, world!")  -     8 +…ontent := "Hello, world!"  -     9 +…mt.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …main() {  +  8    -…mt.Println("Hello, world!")  +     8 +…ontent := "Hello, world!"  +     9 +…mt.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden index 23bbc359dc2713c5e4efe289d49db739dc7febee..83e25c5797773a08506a74a088fd1bb41213a814 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …ain() {  -  8    -…t.Println("Hello, world!")  -     8 +…ntent := "Hello, world!"  -     9 +…t.Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …ain() {  +  8    -…t.Println("Hello, world!")  +     8 +…ntent := "Hello, world!"  +     9 +…t.Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden index 6d0051d415fe34d156c1a2e214c73b5b82f51fb4..d93060419ef9170b27e1deb5d8922f550081eebc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …in() {  -  8    -….Println("Hello, world!")  -     8 +…tent := "Hello, world!"  -     9 +….Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …in() {  +  8    -….Println("Hello, world!")  +     8 +…tent := "Hello, world!"  +     9 +….Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden index f0cbcccd3fac81c5887ff2cbb4c94391f81b4eef..dc99a03dd33325d514e81a2a1db2ce72caa798bf 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …n() {  -  8    -…Println("Hello, world!")  -     8 +…ent := "Hello, world!"  -     9 +…Println(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …n() {  +  8    -…Println("Hello, world!")  +     8 +…ent := "Hello, world!"  +     9 +…Println(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden index d129d6ea063bc43ca9af819f3c7f07abfca3bee5..1945fb2882ca044f817bb14c45ff19e8659eb131 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …() {  -  8    -…rintln("Hello, world!")  -     8 +…nt := "Hello, world!"  -     9 +…rintln(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …() {  +  8    -…rintln("Hello, world!")  +     8 +…nt := "Hello, world!"  +     9 +…rintln(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden index 61db3004e0a95b2862003b589a55a757aed32d51..a35d0a6fb876443dd690e056c26d90a6ec68c7c0 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …) {  -  8    -…intln("Hello, world!")  -     8 +…t := "Hello, world!"  -     9 +…intln(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …) {  +  8    -…intln("Hello, world!")  +     8 +…t := "Hello, world!"  +     9 +…intln(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden index c8e55835730a1cb2b483f4ccf3b28af8eb18acaa..8375de4d8b2ba3a9a8006ecfab5b63a400d4205a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  … {  -  8    -…ntln("Hello, world!")  -     8 +… := "Hello, world!"  -     9 +…ntln(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  … {  +  8    -…ntln("Hello, world!")  +     8 +… := "Hello, world!"  +     9 +…ntln(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden index 76c7f8169230514bbc56d1160ce2e0d6efc8bf79..d09581c1754df334793782a63de756ec8c05cade 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …{  -  8    -…tln("Hello, world!")  -     8 +…:= "Hello, world!"  -     9 +…tln(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …{  +  8    -…tln("Hello, world!")  +     8 +…:= "Hello, world!"  +     9 +…tln(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden index c4d1b3d033cb1107489f506b496ce550b124508a..d0065a8e701e80e4f409092bd185915a593801ce 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…ln("Hello, world!")  -     8 +…= "Hello, world!"  -     9 +…ln(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…ln("Hello, world!")  +     8 +…= "Hello, world!"  +     9 +…ln(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden index d203c18a305f714131a6bc021db50c4d24fd3571..e330e6b27bc0125e3906af14bb4c03acbfbdae04 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…n("Hello, world!")  -     8 +… "Hello, world!"  -     9 +…n(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…n("Hello, world!")  +     8 +… "Hello, world!"  +     9 +…n(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden index 8e1488eec270882434c254a3bab5208809affce9..17055e3f59c8ea0583df3ffa7edf89f1d2183e73 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…("Hello, world!")  -     8 +…"Hello, world!"  -     9 +…(content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…("Hello, world!")  +     8 +…"Hello, world!"  +     9 +…(content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden index 6e4045af203a729eca49b755654474a7b0c5929f..6154dc54cc259cd95afe136dfe244a549b809ede 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…"Hello, world!")  -     8 +…Hello, world!"  -     9 +…content)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…"Hello, world!")  +     8 +…Hello, world!"  +     9 +…content)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden index 1b6cc59882f6da641e3087576a5c9233e04c181e..d1f12f83ce72041803321b36c419b559823f94a1 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…Hello, world!")  -     8 +…ello, world!"  -     9 +…ontent)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…Hello, world!")  +     8 +…ello, world!"  +     9 +…ontent)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden index 33ee3c98182045eb4c38d9c1c6aae6c8757288ef..ea84ca3e8127195696a11792bede35dea3061571 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…ello, world!")  -     8 +…llo, world!"  -     9 +…ntent)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…ello, world!")  +     8 +…llo, world!"  +     9 +…ntent)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden index dede5300cd84025b5bd8fcaf9bef7b6bc9477f70..188782489f7bfec0b98ba913f2bdcc0282a41f50 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…llo, world!")  -     8 +…lo, world!"  -     9 +…tent)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…llo, world!")  +     8 +…lo, world!"  +     9 +…tent)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden index 2df1d43dd2dff9599f5e2adc0006941c98ae52c4..af76a8bdb2ffff2582a700559f63c58b60003b11 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden @@ -1,8 +1,8 @@ -  …   …  @@ -5,5 +5,6 @@   -  5   5  …  -  6   6    -  7   7  …  -  8    -…lo, world!")  -     8 +…o, world!"  -     9 +…ent)  -  9  10  …  \ No newline at end of file +  …   …  @@ -5,5 +5,6 @@   +  5   5  …  +  6   6    +  7   7  …  +  8    -…lo, world!")  +     8 +…o, world!"  +     9 +…ent)  +  9  10  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden index 8d4a293fdd17ce5cbd8d709656573105a8cc7b09..5f2744c16f6b8b93265fcdb6bf40e60a70b2f0fc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden @@ -1,5 +1,5 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden index 59b706f531489a560427504d00b4ed513a2f0429..bc11c063661ad5f9f80c0f9805b57ba8867984f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden @@ -1,5 +1,5 @@ -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  …  …   …  …  \ No newline at end of file +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden index a3e47b440f42bcadf6644a9ce09b4a3eced04193..2910f002652e0c3dc12d89e61a70423dd15c02a2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden @@ -1,5 +1,5 @@ -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  …  …   …  …  \ No newline at end of file +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden index 823ceecf70c4ba985ab52af71e5d73b502e486ef..49869421d07d3f6f2365c2be21488cae2e602ee3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden @@ -1,5 +1,5 @@ -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  …  …   …  …  \ No newline at end of file +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden index 51cc05362f49e9733efb56c02af96d584ed3b507..38a33f5bfdac3f747710eae67d9d9ad75f857586 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden @@ -1,5 +1,5 @@ -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden index f8052af3a03a3e0d71c7e6914ae61e0cfe1cd208..3dc43af25c832e501184f45a8c0988e5c1cd0911 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden @@ -1,5 +1,5 @@ -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  …  …   …  …  \ No newline at end of file +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden index 00209b6b75b82c568e0f04349dd366a8c303b9e0..7613ba0070299fcc23295ddccb729051d30e6589 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden @@ -1,5 +1,5 @@ -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  -  …  …   …  …  \ No newline at end of file +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden index 49f92c490c17a8d125f1a7ca6854573e72ef3e65..f49cef6677b1240a0830950fe078a076ab5b9566 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden @@ -1,5 +1,5 @@ -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    -  …  …   …  …  \ No newline at end of file +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden index 6f01089b12f29dff3c4a31bff325a543dc660355..95adec222e6960f163afc10bcd70453cbf4271b5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden @@ -1,5 +1,5 @@ -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  -  …  …   …  …  \ No newline at end of file +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden index d368d1e85520195ead3015f57012ffefa0502d0d..20fd806a960d41974be035b23750e50e11c5627e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden @@ -1,5 +1,5 @@ -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -  …  …   …  …  \ No newline at end of file +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden index e11e6df667cfa9dc3d909f30fef8895c16dc85c2..12156bccd3e9fd73c0866fea9973f91f940395f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden @@ -1,5 +1,5 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden index 52c1ff0ee9ddec7f746590d4a5efd7630eb97fd4..d9e5079b4b3a2b111e24a69014cfdeb2bb4fd616 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden @@ -1,5 +1,5 @@ -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  …   …  …  \ No newline at end of file +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden index 0d3ef94eccf5119a182afaecfdf5ad85880d3271..5c0cf7e4d5dcc1a6d3c5925c2c3117fe805bb6a6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden @@ -1,5 +1,5 @@ -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  …   …  …  \ No newline at end of file +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden index 37d7ae5851327dd0d05ecb6cfc8d1dcc447c0be7..d8b6dc50a6b23ef5ec57b730cd3ff7a153af9689 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden @@ -1,5 +1,5 @@ -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  …   …  …  \ No newline at end of file +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden index cdc84e4407a0ac070af67944cbf2b470182a865d..a61a550ce34665c0e2e7a5baa332c41ad3da0c2b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden @@ -1,5 +1,5 @@ -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden index 7d36fccbe412a8d49e3c1bc78ae91d2f5433e4de..878033a13b84ea8a174ae3065f8238581fa77abd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden @@ -1,5 +1,5 @@ -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  …   …  …  \ No newline at end of file +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden index 32c230ed26134c7427738a89829c8c511ea97922..b1e73c571d6ab0c768fb5bff6b89916b11e729e4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden @@ -1,5 +1,5 @@ -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  -  …   …  …  \ No newline at end of file +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden index 95f4c23477af7c7b87731b4170b96ce3bf94e755..d4334f15dc21c06f8373c0ae5668d0c1f4ba7174 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden @@ -1,5 +1,5 @@ -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    -  …   …  …  \ No newline at end of file +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden index bf5e674b322acebb23134ff841fbbbfa27eeb752..a644f472dfcffe9a80ad6503a786df25b7f8625c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden @@ -1,5 +1,5 @@ -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  -  …   …  …  \ No newline at end of file +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden index ad0bfca4be7b761b73d833849de6b0c369d92586..26ab2143aeb74e3242e75c04eaa357be41dd1cd5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden @@ -1,5 +1,5 @@ -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -  …   …  …  \ No newline at end of file +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden index 5998ba6ec7df46f91fe969858c19559fe873c330..47be3d191bc6b2929a20df044a255923ac52c6aa 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden @@ -1,5 +1,5 @@ - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -  …   …  …  \ No newline at end of file + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.golden index 8d4a293fdd17ce5cbd8d709656573105a8cc7b09..5f2744c16f6b8b93265fcdb6bf40e60a70b2f0fc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.golden @@ -1,5 +1,5 @@ -  …  @@ -2,6 +2,7 @@    …    -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -  …  …   …  …  \ No newline at end of file +  …  @@ -2,6 +2,7 @@    …    +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.golden index 59b706f531489a560427504d00b4ed513a2f0429..bc11c063661ad5f9f80c0f9805b57ba8867984f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.golden @@ -1,5 +1,5 @@ -  2     2    -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  …  …   …  …  \ No newline at end of file +  2     2    +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.golden index a3e47b440f42bcadf6644a9ce09b4a3eced04193..2910f002652e0c3dc12d89e61a70423dd15c02a2 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.golden @@ -1,5 +1,5 @@ -  3  import (   3  import (  -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  …  …   …  …  \ No newline at end of file +  3  import (   3  import (  +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.golden index 823ceecf70c4ba985ab52af71e5d73b502e486ef..49869421d07d3f6f2365c2be21488cae2e602ee3 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.golden @@ -1,5 +1,5 @@ -  4   "fmt"   4   "fmt"  -       5 +  "strings"  -  5  )   6  )  -  6     7    -  …  …   …  …  \ No newline at end of file +  4   "fmt"   4   "fmt"  +       5 +  "strings"  +  5  )   6  )  +  6     7    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.golden index 51cc05362f49e9733efb56c02af96d584ed3b507..38a33f5bfdac3f747710eae67d9d9ad75f857586 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.golden @@ -1,5 +1,5 @@ -       5 +  "strings"  -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file +       5 +  "strings"  +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.golden index f8052af3a03a3e0d71c7e6914ae61e0cfe1cd208..3dc43af25c832e501184f45a8c0988e5c1cd0911 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.golden @@ -1,5 +1,5 @@ -  5  )   6  )  -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  …  …   …  …  \ No newline at end of file +  5  )   6  )  +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.golden index 00209b6b75b82c568e0f04349dd366a8c303b9e0..7613ba0070299fcc23295ddccb729051d30e6589 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.golden @@ -1,5 +1,5 @@ -  6     7    -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  -  …  …   …  …  \ No newline at end of file +  6     7    +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.golden index 49f92c490c17a8d125f1a7ca6854573e72ef3e65..f49cef6677b1240a0830950fe078a076ab5b9566 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.golden @@ -1,5 +1,5 @@ -  7  func main() {   8  func main() {  -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    -  …  …   …  …  \ No newline at end of file +  7  func main() {   8  func main() {  +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.golden index 6f01089b12f29dff3c4a31bff325a543dc660355..95adec222e6960f163afc10bcd70453cbf4271b5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.golden @@ -1,5 +1,5 @@ -  …  @@ -9,5 +10,6 @@    …    -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  -  …  …   …  …  \ No newline at end of file +  …  @@ -9,5 +10,6 @@    …    +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.golden index d368d1e85520195ead3015f57012ffefa0502d0d..20fd806a960d41974be035b23750e50e11c5627e 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.golden @@ -1,5 +1,5 @@ -  9  }  10  }  - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -  …  …   …  …  \ No newline at end of file +  9  }  10  }  + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +  …  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.golden index 09c4fa2b1b7eb1941caf79650cd494e9b56727d0..7caf995c131a03db4c8362088eae2312b627ad7a 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.golden @@ -1,5 +1,5 @@ - 10    11    - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  \ No newline at end of file + 10    11    + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.golden index fca02b528feae2e2620f53d77bdbdc55e06096f0..65a88103081f6ab66e6bdcb5ee3854dc4b76b9fc 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.golden @@ -1,5 +1,5 @@ - 11  func getContent() string {  12  func getContent() string {  - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           \ No newline at end of file + 11  func getContent() string {  12  func getContent() string {  + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.golden index 5e347b97b1af201404fc830d47501dac3d6b8b36..543ac2c286103505ce0bcfe54730f9e6b5aaab15 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.golden @@ -1,5 +1,5 @@ - 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  -      14 +  return content  - 13  }  15  }  -           -           \ No newline at end of file + 12 -  return "Hello, world!"  13 +  content := strings.ToUpper("Hello, World!")  +      14 +  return content  + 13  }  15  }  +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.golden index 1496bd70374c1879a7b5a628ab923124242508c1..6d8f9d2ee28eac996f931186ab69527fbdb5869c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.golden @@ -1,5 +1,5 @@ -      14 +  return content  - 13  }  15  }  -           -           -           \ No newline at end of file +      14 +  return content  + 13  }  15  }  +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.golden index 80b0d239540b60cb3e84a3323a8085b86ad428fa..8953b980dde0b8bc5e0625f2bce50ab6580ae6af 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.golden @@ -1,5 +1,5 @@ - 13  }  15  }  -           -           -           -           \ No newline at end of file + 13  }  15  }  +           +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.golden index c989070ae313dcd1212208115acf3603671ceab6..3ec6c919be04c5a3787b63a184267ce6cbefe84f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.golden @@ -1,5 +1,5 @@ -           -           -           -           -           \ No newline at end of file +           +           +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.golden index c989070ae313dcd1212208115acf3603671ceab6..3ec6c919be04c5a3787b63a184267ce6cbefe84f 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.golden @@ -1,5 +1,5 @@ -           -           -           -           -           \ No newline at end of file +           +           +           +           +           \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.golden index e11e6df667cfa9dc3d909f30fef8895c16dc85c2..12156bccd3e9fd73c0866fea9973f91f940395f6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.golden @@ -1,5 +1,5 @@ -  …   …  @@ -2,6 +2,7 @@   -  2   2    -  3   3  import (  -  4   4   "fmt"  -  …   …  …  \ No newline at end of file +  …   …  @@ -2,6 +2,7 @@   +  2   2    +  3   3  import (  +  4   4   "fmt"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.golden index 52c1ff0ee9ddec7f746590d4a5efd7630eb97fd4..d9e5079b4b3a2b111e24a69014cfdeb2bb4fd616 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.golden @@ -1,5 +1,5 @@ -  2   2    -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  …   …  …  \ No newline at end of file +  2   2    +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.golden index 0d3ef94eccf5119a182afaecfdf5ad85880d3271..5c0cf7e4d5dcc1a6d3c5925c2c3117fe805bb6a6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.golden @@ -1,5 +1,5 @@ -  3   3  import (  -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  …   …  …  \ No newline at end of file +  3   3  import (  +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.golden index 37d7ae5851327dd0d05ecb6cfc8d1dcc447c0be7..d8b6dc50a6b23ef5ec57b730cd3ff7a153af9689 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.golden @@ -1,5 +1,5 @@ -  4   4   "fmt"  -     5 +  "strings"  -  5   6  )  -  6   7    -  …   …  …  \ No newline at end of file +  4   4   "fmt"  +     5 +  "strings"  +  5   6  )  +  6   7    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.golden index cdc84e4407a0ac070af67944cbf2b470182a865d..a61a550ce34665c0e2e7a5baa332c41ad3da0c2b 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.golden @@ -1,5 +1,5 @@ -     5 +  "strings"  -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file +     5 +  "strings"  +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.golden index 7d36fccbe412a8d49e3c1bc78ae91d2f5433e4de..878033a13b84ea8a174ae3065f8238581fa77abd 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.golden @@ -1,5 +1,5 @@ -  5   6  )  -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  …   …  …  \ No newline at end of file +  5   6  )  +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.golden index 32c230ed26134c7427738a89829c8c511ea97922..b1e73c571d6ab0c768fb5bff6b89916b11e729e4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.golden @@ -1,5 +1,5 @@ -  6   7    -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  -  …   …  …  \ No newline at end of file +  6   7    +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.golden index 95f4c23477af7c7b87731b4170b96ce3bf94e755..d4334f15dc21c06f8373c0ae5668d0c1f4ba7174 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.golden @@ -1,5 +1,5 @@ -  7   8  func main() {  -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    -  …   …  …  \ No newline at end of file +  7   8  func main() {  +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.golden index bf5e674b322acebb23134ff841fbbbfa27eeb752..a644f472dfcffe9a80ad6503a786df25b7f8625c 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.golden @@ -1,5 +1,5 @@ -  …   …  @@ -9,5 +10,6 @@   -  9  10  }  - 10  11    - 11  12  func getContent() string {  -  …   …  …  \ No newline at end of file +  …   …  @@ -9,5 +10,6 @@   +  9  10  }  + 10  11    + 11  12  func getContent() string {  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.golden index ad0bfca4be7b761b73d833849de6b0c369d92586..26ab2143aeb74e3242e75c04eaa357be41dd1cd5 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.golden @@ -1,5 +1,5 @@ -  9  10  }  - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -  …   …  …  \ No newline at end of file +  9  10  }  + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.golden index 5998ba6ec7df46f91fe969858c19559fe873c330..47be3d191bc6b2929a20df044a255923ac52c6aa 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.golden @@ -1,5 +1,5 @@ - 10  11    - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -  …   …  …  \ No newline at end of file + 10  11    + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +  …   …  …  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.golden index 5f686c57c49ca7f7db94c766fff568f55725fa36..efde66a2938b31b311bd5db398a7b79636855aca 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.golden @@ -1,5 +1,5 @@ - 11  12  func getContent() string {  - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  \ No newline at end of file + 11  12  func getContent() string {  + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.golden index 1d8d95395c0e5900b270bb4d6f03ddef56f9bbe3..e3ff1510a8d171df1b77b0de9371c9f49eec3c56 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.golden @@ -1,5 +1,5 @@ - 12    -  return "Hello, world!"  -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         \ No newline at end of file + 12    -  return "Hello, world!"  +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.golden index 469accfc86b39051e1f0d22944328f5ae0ddb911..4ba4c150f7c42c74bcfc1e6a9491c3bca278c2ab 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.golden @@ -1,5 +1,5 @@ -    13 +  content := strings.ToUpper("Hello, World!")  -    14 +  return content  - 13  15  }  -         -         \ No newline at end of file +    13 +  content := strings.ToUpper("Hello, World!")  +    14 +  return content  + 13  15  }  +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.golden index 547e576181a8e1abe5d24f3fce8f5dce2988bb3c..dd6b280851e7e1fd7c16f5ee328960dbf59f0ea4 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.golden @@ -1,5 +1,5 @@ -    14 +  return content  - 13  15  }  -         -         -         \ No newline at end of file +    14 +  return content  + 13  15  }  +         +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.golden index 005a5ea98096a1a703fb31ccd9b6e94ee0fe874a..d5989d13ee9e965779c66bdab0e0587347816110 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.golden @@ -1,5 +1,5 @@ - 13  15  }  -         -         -         -         \ No newline at end of file + 13  15  }  +         +         +         +         \ No newline at end of file diff --git a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.golden b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.golden index 933f56b9d1fc148d6d394cb271299f4eddc0a739..a6fe41cba248742a8a8caaf40e68c55e719071e6 100644 --- a/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.golden +++ b/internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.golden @@ -1,5 +1,5 @@ -         -         -         -         -         \ No newline at end of file +         +         +         +         +         \ No newline at end of file diff --git a/internal/tui/keys.go b/internal/tui/keys.go index 22c029dd355845b3ac7e2066a8a93bfb335c1d53..d055870e5ab24816fa002d2ad4f5fc171876d56e 100644 --- a/internal/tui/keys.go +++ b/internal/tui/keys.go @@ -20,8 +20,8 @@ func DefaultKeyMap() KeyMap { key.WithHelp("ctrl+c", "quit"), ), Help: key.NewBinding( - key.WithKeys("ctrl+?", "ctrl+_", "ctrl+/"), - key.WithHelp("ctrl+?", "more"), + key.WithKeys("ctrl+g"), + key.WithHelp("ctrl+g", "more"), ), Commands: key.NewBinding( key.WithKeys("ctrl+p"), @@ -33,62 +33,3 @@ func DefaultKeyMap() KeyMap { ), } } - -// FullHelp implements help.KeyMap. -func (k KeyMap) FullHelp() [][]key.Binding { - m := [][]key.Binding{} - slice := []key.Binding{ - k.Commands, - k.Sessions, - k.Quit, - k.Help, - } - slice = k.prependEscAndTab(slice) - slice = append(slice, k.pageBindings...) - // remove duplicates - seen := make(map[string]bool) - cleaned := []key.Binding{} - for _, b := range slice { - if !seen[b.Help().Key] { - seen[b.Help().Key] = true - cleaned = append(cleaned, b) - } - } - - for i := 0; i < len(cleaned); i += 3 { - end := min(i+3, len(cleaned)) - m = append(m, cleaned[i:end]) - } - return m -} - -func (k KeyMap) prependEscAndTab(bindings []key.Binding) []key.Binding { - var cancel key.Binding - var tab key.Binding - for _, b := range k.pageBindings { - if b.Help().Key == "esc" { - cancel = b - } - if b.Help().Key == "tab" { - tab = b - } - } - if tab.Help().Key != "" { - bindings = append([]key.Binding{tab}, bindings...) - } - if cancel.Help().Key != "" { - bindings = append([]key.Binding{cancel}, bindings...) - } - return bindings -} - -// ShortHelp implements help.KeyMap. -func (k KeyMap) ShortHelp() []key.Binding { - bindings := []key.Binding{ - k.Commands, - k.Sessions, - k.Quit, - k.Help, - } - return k.prependEscAndTab(bindings) -} diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index 59b8ac86da3901bfb5a3affe8aeedf27f293a507..5c4b7738580db046920ac7812c7a493c21e996ee 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -2,21 +2,29 @@ package chat import ( "context" - "strings" "time" + "github.com/charmbracelet/bubbles/v2/help" "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/bubbles/v2/spinner" tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/app" "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/history" "github.com/charmbracelet/crush/internal/message" + "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/session" + "github.com/charmbracelet/crush/internal/tui/components/anim" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/chat/editor" "github.com/charmbracelet/crush/internal/tui/components/chat/header" "github.com/charmbracelet/crush/internal/tui/components/chat/sidebar" + "github.com/charmbracelet/crush/internal/tui/components/chat/splash" + "github.com/charmbracelet/crush/internal/tui/components/completions" + "github.com/charmbracelet/crush/internal/tui/components/core" "github.com/charmbracelet/crush/internal/tui/components/core/layout" "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" + "github.com/charmbracelet/crush/internal/tui/components/dialogs/filepicker" "github.com/charmbracelet/crush/internal/tui/page" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" @@ -26,150 +34,223 @@ import ( var ChatPageID page.PageID = "chat" -const CompactModeBreakpoint = 120 // Width at which the chat page switches to compact mode - type ( OpenFilePickerMsg struct{} ChatFocusedMsg struct { - Focused bool // True if the chat input is focused, false otherwise + Focused bool } CancelTimerExpiredMsg struct{} ) +type PanelType string + +const ( + PanelTypeChat PanelType = "chat" + PanelTypeEditor PanelType = "editor" + PanelTypeSplash PanelType = "splash" +) + +const ( + CompactModeBreakpoint = 120 // Width at which the chat page switches to compact mode + EditorHeight = 5 // Height of the editor input area including padding + SideBarWidth = 31 // Width of the sidebar + SideBarDetailsPadding = 1 // Padding for the sidebar details section + HeaderHeight = 1 // Height of the header + + // Layout constants for borders and padding + BorderWidth = 1 // Width of component borders + LeftRightBorders = 2 // Left + right border width (1 + 1) + TopBottomBorders = 2 // Top + bottom border width (1 + 1) + DetailsPositioning = 2 // Positioning adjustment for details panel + + // Timing constants + CancelTimerDuration = 2 * time.Second // Duration before cancel timer expires +) + type ChatPage interface { util.Model layout.Help IsChatFocused() bool } +// cancelTimerCmd creates a command that expires the cancel timer +func cancelTimerCmd() tea.Cmd { + return tea.Tick(CancelTimerDuration, func(time.Time) tea.Msg { + return CancelTimerExpiredMsg{} + }) +} + type chatPage struct { - wWidth, wHeight int // Window dimensions - app *app.App + width, height int + detailsWidth, detailsHeight int + app *app.App + keyboardEnhancements tea.KeyboardEnhancementsMsg - layout layout.SplitPaneLayout + // Layout state + compact bool + forceCompact bool + focusedPane PanelType + // Session session session.Session + keyMap KeyMap + + // Components + header header.Header + sidebar sidebar.Sidebar + chat chat.MessageListCmp + editor editor.Editor + splash splash.Splash + + // Simple state flags + showingDetails bool + isCanceling bool + splashFullScreen bool + isOnboarding bool + isProjectInit bool +} - keyMap KeyMap - - chatFocused bool - - compactMode bool - forceCompactMode bool // Force compact mode regardless of window size - showDetails bool // Show details in the header - header header.Header - compactSidebar layout.Container - - cancelPending bool // True if ESC was pressed once and waiting for second press +func New(app *app.App) ChatPage { + return &chatPage{ + app: app, + keyMap: DefaultKeyMap(), + header: header.New(app.LSPClients), + sidebar: sidebar.New(app.History, app.LSPClients, false), + chat: chat.New(app), + editor: editor.New(app), + splash: splash.New(), + focusedPane: PanelTypeSplash, + } } func (p *chatPage) Init() tea.Cmd { + cfg := config.Get() + compact := cfg.Options.TUI.CompactMode + p.compact = compact + p.forceCompact = compact + p.sidebar.SetCompactMode(p.compact) + + // Set splash state based on config + if !config.HasInitialDataConfig() { + // First-time setup: show model selection + p.splash.SetOnboarding(true) + p.isOnboarding = true + p.splashFullScreen = true + } else if b, _ := config.ProjectNeedsInitialization(); b { + // Project needs CRUSH.md initialization + p.splash.SetProjectInit(true) + p.isProjectInit = true + p.splashFullScreen = true + } else { + // Ready to chat: focus editor, splash in background + p.focusedPane = PanelTypeEditor + p.splashFullScreen = false + } + return tea.Batch( - p.layout.Init(), - p.compactSidebar.Init(), - p.layout.FocusPanel(layout.BottomPanel), // Focus on the bottom panel (editor), + p.header.Init(), + p.sidebar.Init(), + p.chat.Init(), + p.editor.Init(), + p.splash.Init(), ) } -// cancelTimerCmd creates a command that expires the cancel timer after 2 seconds -func (p *chatPage) cancelTimerCmd() tea.Cmd { - return tea.Tick(2*time.Second, func(time.Time) tea.Msg { - return CancelTimerExpiredMsg{} - }) -} - func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { - case CancelTimerExpiredMsg: - p.cancelPending = false + case tea.KeyboardEnhancementsMsg: + p.keyboardEnhancements = msg return p, nil case tea.WindowSizeMsg: - h, cmd := p.header.Update(msg) - cmds = append(cmds, cmd) - p.header = h.(header.Header) - cmds = append(cmds, p.compactSidebar.SetSize(msg.Width-4, 0)) - // the mode is only relevant when there is a session - if p.session.ID != "" { - // Only auto-switch to compact mode if not forced - if !p.forceCompactMode { - if msg.Width <= CompactModeBreakpoint && p.wWidth > CompactModeBreakpoint { - p.wWidth = msg.Width - p.wHeight = msg.Height - cmds = append(cmds, p.setCompactMode(true)) - return p, tea.Batch(cmds...) - } else if msg.Width > CompactModeBreakpoint && p.wWidth <= CompactModeBreakpoint { - p.wWidth = msg.Width - p.wHeight = msg.Height - return p, p.setCompactMode(false) - } - } - } - p.wWidth = msg.Width - p.wHeight = msg.Height - layoutHeight := msg.Height - if p.compactMode { - // make space for the header - layoutHeight -= 1 + return p, p.SetSize(msg.Width, msg.Height) + case CancelTimerExpiredMsg: + p.isCanceling = false + return p, nil + case chat.SendMsg: + return p, p.sendMessage(msg.Text, msg.Attachments) + case chat.SessionSelectedMsg: + return p, p.setSession(msg) + case commands.ToggleCompactModeMsg: + p.forceCompact = !p.forceCompact + var cmd tea.Cmd + if p.forceCompact { + p.setCompactMode(true) + cmd = p.updateCompactConfig(true) + } else if p.width >= CompactModeBreakpoint { + p.setCompactMode(false) + cmd = p.updateCompactConfig(false) } - cmd = p.layout.SetSize(msg.Width, layoutHeight) + return p, tea.Batch(p.SetSize(p.width, p.height), cmd) + case pubsub.Event[session.Session]: + u, cmd := p.header.Update(msg) + p.header = u.(header.Header) + cmds = append(cmds, cmd) + u, cmd = p.sidebar.Update(msg) + p.sidebar = u.(sidebar.Sidebar) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + case chat.SessionClearedMsg: + u, cmd := p.header.Update(msg) + p.header = u.(header.Header) + cmds = append(cmds, cmd) + u, cmd = p.sidebar.Update(msg) + p.sidebar = u.(sidebar.Sidebar) + cmds = append(cmds, cmd) + u, cmd = p.chat.Update(msg) + p.chat = u.(chat.MessageListCmp) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + case filepicker.FilePickedMsg, + completions.CompletionsClosedMsg, + completions.SelectCompletionMsg: + u, cmd := p.editor.Update(msg) + p.editor = u.(editor.Editor) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + + case pubsub.Event[message.Message], + anim.StepMsg, + spinner.TickMsg: + u, cmd := p.chat.Update(msg) + p.chat = u.(chat.MessageListCmp) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + + case pubsub.Event[history.File], sidebar.SessionFilesMsg: + u, cmd := p.sidebar.Update(msg) + p.sidebar = u.(sidebar.Sidebar) cmds = append(cmds, cmd) return p, tea.Batch(cmds...) - case chat.SendMsg: - cmd := p.sendMessage(msg.Text, msg.Attachments) - if cmd != nil { - return p, cmd - } - case commands.ToggleCompactModeMsg: - // Only allow toggling if window width is larger than compact breakpoint - if p.wWidth > CompactModeBreakpoint { - p.forceCompactMode = !p.forceCompactMode - // If force compact mode is enabled, switch to compact mode - // If force compact mode is disabled, switch based on window size - if p.forceCompactMode { - return p, p.setCompactMode(true) - } else { - // Return to auto mode based on window size - shouldBeCompact := p.wWidth <= CompactModeBreakpoint - return p, p.setCompactMode(shouldBeCompact) - } - } case commands.CommandRunCustomMsg: - // Check if the agent is busy before executing custom commands if p.app.CoderAgent.IsBusy() { return p, util.ReportWarn("Agent is busy, please wait before executing a command...") } - // Handle custom command execution cmd := p.sendMessage(msg.Content, nil) if cmd != nil { return p, cmd } - case chat.SessionSelectedMsg: - if p.session.ID == "" { - cmd := p.setMessages() - if cmd != nil { - cmds = append(cmds, cmd) - } + case splash.OnboardingCompleteMsg: + p.splashFullScreen = false + if b, _ := config.ProjectNeedsInitialization(); b { + p.splash.SetProjectInit(true) + p.splashFullScreen = true + return p, p.SetSize(p.width, p.height) } - needsModeChange := p.session.ID == "" - p.session = msg - p.header.SetSession(msg) - if needsModeChange && (p.wWidth <= CompactModeBreakpoint || p.forceCompactMode) { - cmds = append(cmds, p.setCompactMode(true)) + err := p.app.InitCoderAgent() + if err != nil { + return p, util.ReportError(err) } + p.isOnboarding = false + p.isProjectInit = false + p.focusedPane = PanelTypeEditor + return p, p.SetSize(p.width, p.height) case tea.KeyPressMsg: switch { case key.Matches(msg, p.keyMap.NewSession): - p.session = session.Session{} - return p, tea.Batch( - p.clearMessages(), - util.CmdHandler(chat.SessionClearedMsg{}), - p.setCompactMode(false), - p.layout.FocusPanel(layout.BottomPanel), - util.CmdHandler(ChatFocusedMsg{Focused: false}), - ) + return p, p.newSession() case key.Matches(msg, p.keyMap.AddAttachment): agentCfg := config.Get().Agents["coder"] model := config.Get().GetModelByType(agentCfg.Model) @@ -180,171 +261,290 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case key.Matches(msg, p.keyMap.Tab): if p.session.ID == "" { - return p, nil - } - p.chatFocused = !p.chatFocused - if p.chatFocused { - cmds = append(cmds, p.layout.FocusPanel(layout.LeftPanel)) - cmds = append(cmds, util.CmdHandler(ChatFocusedMsg{Focused: true})) - } else { - cmds = append(cmds, p.layout.FocusPanel(layout.BottomPanel)) - cmds = append(cmds, util.CmdHandler(ChatFocusedMsg{Focused: false})) + u, cmd := p.splash.Update(msg) + p.splash = u.(splash.Splash) + return p, cmd } - return p, tea.Batch(cmds...) + p.changeFocus() + return p, nil case key.Matches(msg, p.keyMap.Cancel): - if p.session.ID != "" { - if p.cancelPending { - // Second ESC press - actually cancel the session - p.cancelPending = false - p.app.CoderAgent.Cancel(p.session.ID) - return p, nil - } else { - // First ESC press - start the timer - p.cancelPending = true - return p, p.cancelTimerCmd() - } + if p.session.ID != "" && p.app.CoderAgent.IsBusy() { + return p, p.cancel() } case key.Matches(msg, p.keyMap.Details): - if p.session.ID == "" || !p.compactMode { - return p, nil // No session to show details for - } - p.showDetails = !p.showDetails - p.header.SetDetailsOpen(p.showDetails) - if p.showDetails { - return p, tea.Batch() - } - + p.showDetails() return p, nil } + + switch p.focusedPane { + case PanelTypeChat: + u, cmd := p.chat.Update(msg) + p.chat = u.(chat.MessageListCmp) + cmds = append(cmds, cmd) + case PanelTypeEditor: + u, cmd := p.editor.Update(msg) + p.editor = u.(editor.Editor) + cmds = append(cmds, cmd) + case PanelTypeSplash: + u, cmd := p.splash.Update(msg) + p.splash = u.(splash.Splash) + cmds = append(cmds, cmd) + } + case tea.PasteMsg: + switch p.focusedPane { + case PanelTypeEditor: + u, cmd := p.editor.Update(msg) + p.editor = u.(editor.Editor) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + case PanelTypeChat: + u, cmd := p.chat.Update(msg) + p.chat = u.(chat.MessageListCmp) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + case PanelTypeSplash: + u, cmd := p.splash.Update(msg) + p.splash = u.(splash.Splash) + cmds = append(cmds, cmd) + return p, tea.Batch(cmds...) + } } - u, cmd := p.layout.Update(msg) - cmds = append(cmds, cmd) - p.layout = u.(layout.SplitPaneLayout) - h, cmd := p.header.Update(msg) - p.header = h.(header.Header) - cmds = append(cmds, cmd) - s, cmd := p.compactSidebar.Update(msg) - p.compactSidebar = s.(layout.Container) - cmds = append(cmds, cmd) return p, tea.Batch(cmds...) } -func (p *chatPage) setMessages() tea.Cmd { - messagesContainer := layout.NewContainer( - chat.NewMessagesListCmp(p.app), - layout.WithPadding(1, 1, 0, 1), - ) - return tea.Batch(p.layout.SetLeftPanel(messagesContainer), messagesContainer.Init()) +func (p *chatPage) Cursor() *tea.Cursor { + switch p.focusedPane { + case PanelTypeEditor: + return p.editor.Cursor() + case PanelTypeSplash: + return p.splash.Cursor() + default: + return nil + } } -func (p *chatPage) setSidebar() tea.Cmd { - sidebarContainer := sidebarCmp(p.app, false, p.session) - sidebarContainer.Init() - return p.layout.SetRightPanel(sidebarContainer) +func (p *chatPage) View() string { + var chatView string + t := styles.CurrentTheme() + + if p.session.ID == "" { + splashView := p.splash.View() + // Full screen during onboarding or project initialization + if p.splashFullScreen { + chatView = splashView + } else { + // Show splash + editor for new message state + editorView := p.editor.View() + chatView = lipgloss.JoinVertical( + lipgloss.Left, + t.S().Base.Render(splashView), + editorView, + ) + } + } else { + messagesView := p.chat.View() + editorView := p.editor.View() + if p.compact { + headerView := p.header.View() + chatView = lipgloss.JoinVertical( + lipgloss.Left, + headerView, + messagesView, + editorView, + ) + } else { + sidebarView := p.sidebar.View() + messages := lipgloss.JoinHorizontal( + lipgloss.Left, + messagesView, + sidebarView, + ) + chatView = lipgloss.JoinVertical( + lipgloss.Left, + messages, + p.editor.View(), + ) + } + } + + layers := []*lipgloss.Layer{ + lipgloss.NewLayer(chatView).X(0).Y(0), + } + + if p.showingDetails { + style := t.S().Base. + Width(p.detailsWidth). + Border(lipgloss.RoundedBorder()). + BorderForeground(t.BorderFocus) + version := t.S().Subtle.Width(p.detailsWidth - 2).AlignHorizontal(lipgloss.Right).Render(version.Version) + details := style.Render( + lipgloss.JoinVertical( + lipgloss.Left, + p.sidebar.View(), + version, + ), + ) + layers = append(layers, lipgloss.NewLayer(details).X(1).Y(1)) + } + canvas := lipgloss.NewCanvas( + layers..., + ) + return canvas.Render() } -func (p *chatPage) clearMessages() tea.Cmd { - return p.layout.ClearLeftPanel() +func (p *chatPage) updateCompactConfig(compact bool) tea.Cmd { + return func() tea.Msg { + err := config.Get().SetCompactMode(compact) + if err != nil { + return util.InfoMsg{ + Type: util.InfoTypeError, + Msg: "Failed to update compact mode configuration: " + err.Error(), + } + } + return nil + } } -func (p *chatPage) setCompactMode(compact bool) tea.Cmd { - p.compactMode = compact - var cmds []tea.Cmd +func (p *chatPage) setCompactMode(compact bool) { + if p.compact == compact { + return + } + p.compact = compact if compact { - // add offset for the header - p.layout.SetOffset(0, 1) - // make space for the header - cmds = append(cmds, p.layout.SetSize(p.wWidth, p.wHeight-1)) - // remove the sidebar - cmds = append(cmds, p.layout.ClearRightPanel()) - return tea.Batch(cmds...) + p.compact = true + p.sidebar.SetCompactMode(true) } else { - // remove the offset for the header - p.layout.SetOffset(0, 0) - // restore the original size - cmds = append(cmds, p.layout.SetSize(p.wWidth, p.wHeight)) - // set the sidebar - cmds = append(cmds, p.setSidebar()) - l, cmd := p.layout.Update(chat.SessionSelectedMsg(p.session)) - p.layout = l.(layout.SplitPaneLayout) - cmds = append(cmds, cmd) + p.compact = false + p.showingDetails = false + p.sidebar.SetCompactMode(false) + } +} - return tea.Batch(cmds...) +func (p *chatPage) handleCompactMode(newWidth int) { + if p.forceCompact { + return + } + if newWidth < CompactModeBreakpoint && !p.compact { + p.setCompactMode(true) + } + if newWidth >= CompactModeBreakpoint && p.compact { + p.setCompactMode(false) } } -func (p *chatPage) sendMessage(text string, attachments []message.Attachment) tea.Cmd { +func (p *chatPage) SetSize(width, height int) tea.Cmd { + p.handleCompactMode(width) + p.width = width + p.height = height var cmds []tea.Cmd + if p.session.ID == "" { - session, err := p.app.Sessions.Create(context.Background(), "New Session") - if err != nil { - return util.ReportError(err) + if p.splashFullScreen { + cmds = append(cmds, p.splash.SetSize(width, height)) + } else { + cmds = append(cmds, p.splash.SetSize(width, height-EditorHeight)) + cmds = append(cmds, p.editor.SetSize(width, EditorHeight)) + cmds = append(cmds, p.editor.SetPosition(0, height-EditorHeight)) } - - p.session = session - cmd := p.setMessages() - if cmd != nil { - cmds = append(cmds, cmd) + } else { + if p.compact { + cmds = append(cmds, p.chat.SetSize(width, height-EditorHeight-HeaderHeight)) + p.detailsWidth = width - DetailsPositioning + cmds = append(cmds, p.sidebar.SetSize(p.detailsWidth-LeftRightBorders, p.detailsHeight-TopBottomBorders)) + cmds = append(cmds, p.editor.SetSize(width, EditorHeight)) + cmds = append(cmds, p.header.SetWidth(width-BorderWidth)) + } else { + cmds = append(cmds, p.chat.SetSize(width-SideBarWidth, height-EditorHeight)) + cmds = append(cmds, p.editor.SetSize(width, EditorHeight)) + cmds = append(cmds, p.sidebar.SetSize(SideBarWidth, height-EditorHeight)) } - cmds = append(cmds, util.CmdHandler(chat.SessionSelectedMsg(session))) - } - - _, err := p.app.CoderAgent.Run(context.Background(), p.session.ID, text, attachments...) - if err != nil { - return util.ReportError(err) + cmds = append(cmds, p.editor.SetPosition(0, height-EditorHeight)) } return tea.Batch(cmds...) } -func (p *chatPage) SetSize(width, height int) tea.Cmd { - return p.layout.SetSize(width, height) +func (p *chatPage) newSession() tea.Cmd { + if p.session.ID == "" { + return nil + } + + p.session = session.Session{} + p.focusedPane = PanelTypeEditor + p.isCanceling = false + return tea.Batch( + util.CmdHandler(chat.SessionClearedMsg{}), + p.SetSize(p.width, p.height), + ) } -func (p *chatPage) GetSize() (int, int) { - return p.layout.GetSize() +func (p *chatPage) setSession(session session.Session) tea.Cmd { + if p.session.ID == session.ID { + return nil + } + + var cmds []tea.Cmd + p.session = session + + cmds = append(cmds, p.SetSize(p.width, p.height)) + cmds = append(cmds, p.chat.SetSession(session)) + cmds = append(cmds, p.sidebar.SetSession(session)) + cmds = append(cmds, p.header.SetSession(session)) + cmds = append(cmds, p.editor.SetSession(session)) + + return tea.Sequence(cmds...) } -func (p *chatPage) View() string { - if !p.compactMode || p.session.ID == "" { - // If not in compact mode or there is no session, we don't show the header - return p.layout.View() +func (p *chatPage) changeFocus() { + if p.session.ID == "" { + return } - layoutView := p.layout.View() - chatView := strings.Join( - []string{ - p.header.View(), - layoutView, - }, "\n", - ) - layers := []*lipgloss.Layer{ - lipgloss.NewLayer(chatView).X(0).Y(0), + switch p.focusedPane { + case PanelTypeChat: + p.focusedPane = PanelTypeEditor + p.editor.Focus() + p.chat.Blur() + case PanelTypeEditor: + p.focusedPane = PanelTypeChat + p.chat.Focus() + p.editor.Blur() } - if p.showDetails { - t := styles.CurrentTheme() - style := t.S().Base. - Border(lipgloss.RoundedBorder()). - BorderForeground(t.BorderFocus) - version := t.S().Subtle.Padding(0, 1).AlignHorizontal(lipgloss.Right).Width(p.wWidth - 4).Render(version.Version) - details := style.Render( - lipgloss.JoinVertical( - lipgloss.Left, - p.compactSidebar.View(), - version, - ), - ) - layers = append(layers, lipgloss.NewLayer(details).X(1).Y(1)) +} + +func (p *chatPage) cancel() tea.Cmd { + if p.isCanceling { + p.isCanceling = false + p.app.CoderAgent.Cancel(p.session.ID) + return nil } - canvas := lipgloss.NewCanvas( - layers..., - ) - return canvas.Render() + + p.isCanceling = true + return cancelTimerCmd() } -func (p *chatPage) Cursor() *tea.Cursor { - if v, ok := p.layout.(util.Cursor); ok { - return v.Cursor() +func (p *chatPage) showDetails() { + if p.session.ID == "" || !p.compact { + return + } + p.showingDetails = !p.showingDetails + p.header.SetDetailsOpen(p.showingDetails) +} + +func (p *chatPage) sendMessage(text string, attachments []message.Attachment) tea.Cmd { + session := p.session + var cmds []tea.Cmd + if p.session.ID == "" { + newSession, err := p.app.Sessions.Create(context.Background(), "New Session") + if err != nil { + return util.ReportError(err) + } + session = newSession + cmds = append(cmds, util.CmdHandler(chat.SessionSelectedMsg(session))) + } + _, err := p.app.CoderAgent.Run(context.Background(), session.ID, text, attachments...) + if err != nil { + return util.ReportError(err) } - return nil + return tea.Batch(cmds...) } func (p *chatPage) Bindings() []key.Binding { @@ -352,9 +552,9 @@ func (p *chatPage) Bindings() []key.Binding { p.keyMap.NewSession, p.keyMap.AddAttachment, } - if p.app.CoderAgent.IsBusy() { + if p.app.CoderAgent != nil && p.app.CoderAgent.IsBusy() { cancelBinding := p.keyMap.Cancel - if p.cancelPending { + if p.isCanceling { cancelBinding = key.NewBinding( key.WithKeys("esc"), key.WithHelp("esc", "press again to cancel"), @@ -363,61 +563,261 @@ func (p *chatPage) Bindings() []key.Binding { bindings = append([]key.Binding{cancelBinding}, bindings...) } - if p.chatFocused { + switch p.focusedPane { + case PanelTypeChat: bindings = append([]key.Binding{ key.NewBinding( key.WithKeys("tab"), key.WithHelp("tab", "focus editor"), ), }, bindings...) - } else { + bindings = append(bindings, p.chat.Bindings()...) + case PanelTypeEditor: bindings = append([]key.Binding{ key.NewBinding( key.WithKeys("tab"), key.WithHelp("tab", "focus chat"), ), }, bindings...) + bindings = append(bindings, p.editor.Bindings()...) + case PanelTypeSplash: + bindings = append(bindings, p.splash.Bindings()...) } - bindings = append(bindings, p.layout.Bindings()...) return bindings } -func sidebarCmp(app *app.App, compact bool, session session.Session) layout.Container { - padding := layout.WithPadding(1, 1, 1, 1) - if compact { - padding = layout.WithPadding(0, 1, 1, 1) - } - sidebar := sidebar.NewSidebarCmp(app.History, app.LSPClients, compact) - if session.ID != "" { - sidebar.SetSession(session) +func (a *chatPage) Help() help.KeyMap { + var shortList []key.Binding + var fullList [][]key.Binding + switch { + case a.isOnboarding && !a.splash.IsShowingAPIKey(): + shortList = append(shortList, + // Choose model + key.NewBinding( + key.WithKeys("up", "down"), + key.WithHelp("↑/↓", "choose"), + ), + // Accept selection + key.NewBinding( + key.WithKeys("enter", "ctrl+y"), + key.WithHelp("enter", "accept"), + ), + // Quit + key.NewBinding( + key.WithKeys("ctrl+c"), + key.WithHelp("ctrl+c", "quit"), + ), + ) + // keep them the same + for _, v := range shortList { + fullList = append(fullList, []key.Binding{v}) + } + case a.isOnboarding && a.splash.IsShowingAPIKey(): + shortList = append(shortList, + // Go back + key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "back"), + ), + // Quit + key.NewBinding( + key.WithKeys("ctrl+c"), + key.WithHelp("ctrl+c", "quit"), + ), + ) + // keep them the same + for _, v := range shortList { + fullList = append(fullList, []key.Binding{v}) + } + case a.isProjectInit: + shortList = append(shortList, + key.NewBinding( + key.WithKeys("ctrl+c"), + key.WithHelp("ctrl+c", "quit"), + ), + ) + // keep them the same + for _, v := range shortList { + fullList = append(fullList, []key.Binding{v}) + } + default: + if a.editor.IsCompletionsOpen() { + shortList = append(shortList, + key.NewBinding( + key.WithKeys("tab", "enter"), + key.WithHelp("tab/enter", "complete"), + ), + key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "cancel"), + ), + key.NewBinding( + key.WithKeys("up", "down"), + key.WithHelp("↑/↓", "choose"), + ), + ) + for _, v := range shortList { + fullList = append(fullList, []key.Binding{v}) + } + return core.NewSimpleHelp(shortList, fullList) + } + if a.app.CoderAgent != nil && a.app.CoderAgent.IsBusy() { + cancelBinding := key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "cancel"), + ) + if a.isCanceling { + cancelBinding = key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "press again to cancel"), + ) + } + shortList = append(shortList, cancelBinding) + fullList = append(fullList, + []key.Binding{ + cancelBinding, + }, + ) + } + globalBindings := []key.Binding{} + // we are in a session + if a.session.ID != "" { + tabKey := key.NewBinding( + key.WithKeys("tab"), + key.WithHelp("tab", "focus chat"), + ) + if a.focusedPane == PanelTypeChat { + tabKey = key.NewBinding( + key.WithKeys("tab"), + key.WithHelp("tab", "focus editor"), + ) + } + shortList = append(shortList, tabKey) + globalBindings = append(globalBindings, tabKey) + } + commandsBinding := key.NewBinding( + key.WithKeys("ctrl+p"), + key.WithHelp("ctrl+p", "commands"), + ) + helpBinding := key.NewBinding( + key.WithKeys("ctrl+g"), + key.WithHelp("ctrl+g", "more"), + ) + globalBindings = append(globalBindings, commandsBinding) + globalBindings = append(globalBindings, + key.NewBinding( + key.WithKeys("ctrl+s"), + key.WithHelp("ctrl+s", "sessions"), + ), + ) + if a.session.ID != "" { + globalBindings = append(globalBindings, + key.NewBinding( + key.WithKeys("ctrl+n"), + key.WithHelp("ctrl+n", "new sessions"), + )) + } + shortList = append(shortList, + // Commands + commandsBinding, + ) + fullList = append(fullList, globalBindings) + + if a.focusedPane == PanelTypeChat { + shortList = append(shortList, + key.NewBinding( + key.WithKeys("up", "down"), + key.WithHelp("↑↓", "scroll"), + ), + ) + fullList = append(fullList, + []key.Binding{ + key.NewBinding( + key.WithKeys("up", "down"), + key.WithHelp("↑↓", "scroll"), + ), + key.NewBinding( + key.WithKeys("shift+up", "shift+down"), + key.WithHelp("shift+↑↓", "next/prev item"), + ), + key.NewBinding( + key.WithKeys("pgup", "b"), + key.WithHelp("b/pgup", "page up"), + ), + key.NewBinding( + key.WithKeys("pgdown", " ", "f"), + key.WithHelp("f/pgdn", "page down"), + ), + }, + []key.Binding{ + key.NewBinding( + key.WithKeys("u"), + key.WithHelp("u", "half page up"), + ), + key.NewBinding( + key.WithKeys("d"), + key.WithHelp("d", "half page down"), + ), + key.NewBinding( + key.WithKeys("g", "home"), + key.WithHelp("g", "hone"), + ), + key.NewBinding( + key.WithKeys("G", "end"), + key.WithHelp("G", "end"), + ), + }, + ) + } else if a.focusedPane == PanelTypeEditor { + newLineBinding := key.NewBinding( + key.WithKeys("shift+enter", "ctrl+j"), + // "ctrl+j" is a common keybinding for newline in many editors. If + // the terminal supports "shift+enter", we substitute the help text + // to reflect that. + key.WithHelp("ctrl+j", "newline"), + ) + if a.keyboardEnhancements.SupportsKeyDisambiguation() { + newLineBinding.SetHelp("shift+enter", newLineBinding.Help().Desc) + } + shortList = append(shortList, newLineBinding) + fullList = append(fullList, + []key.Binding{ + newLineBinding, + key.NewBinding( + key.WithKeys("ctrl+f"), + key.WithHelp("ctrl+f", "add image"), + ), + key.NewBinding( + key.WithKeys("/"), + key.WithHelp("/", "add file"), + ), + key.NewBinding( + key.WithKeys("ctrl+v"), + key.WithHelp("ctrl+v", "open editor"), + ), + }) + } + shortList = append(shortList, + // Quit + key.NewBinding( + key.WithKeys("ctrl+c"), + key.WithHelp("ctrl+c", "quit"), + ), + // Help + helpBinding, + ) + fullList = append(fullList, []key.Binding{ + key.NewBinding( + key.WithKeys("ctrl+g"), + key.WithHelp("ctrl+g", "less"), + ), + }) } - return layout.NewContainer( - sidebar, - padding, - ) -} - -func NewChatPage(app *app.App) ChatPage { - editorContainer := layout.NewContainer( - editor.NewEditorCmp(app), - ) - return &chatPage{ - app: app, - layout: layout.NewSplitPane( - layout.WithRightPanel(sidebarCmp(app, false, session.Session{})), - layout.WithBottomPanel(editorContainer), - layout.WithFixedBottomHeight(5), - layout.WithFixedRightWidth(31), - ), - compactSidebar: sidebarCmp(app, true, session.Session{}), - keyMap: DefaultKeyMap(), - header: header.New(app.LSPClients), - } + return core.NewSimpleHelp(shortList, fullList) } -// IsChatFocused returns whether the chat messages are focused (true) or editor is focused (false) func (p *chatPage) IsChatFocused() bool { - return p.chatFocused + return p.focusedPane == PanelTypeChat } diff --git a/internal/tui/styles/crush.go b/internal/tui/styles/crush.go index f59b78ac2202a268337af48913fd2e3a397f4ef5..48911d7096f7b0d104b0361ae5f6632c9658e536 100644 --- a/internal/tui/styles/crush.go +++ b/internal/tui/styles/crush.go @@ -16,7 +16,7 @@ func NewCrushTheme() *Theme { // Backgrounds BgBase: charmtone.Pepper, - BgBaseLighter: Lighten(charmtone.Pepper, 2), + BgBaseLighter: charmtone.BBQ, BgSubtle: charmtone.Charcoal, BgOverlay: charmtone.Iron, diff --git a/internal/tui/tui.go b/internal/tui/tui.go index dd0d4f9085d92b20aa92c8d2f25227b5e2206816..365db72299865897feb94879f837baa93bff5e43 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -13,13 +13,13 @@ import ( "github.com/charmbracelet/crush/internal/pubsub" cmpChat "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/completions" + "github.com/charmbracelet/crush/internal/tui/components/core" "github.com/charmbracelet/crush/internal/tui/components/core/layout" "github.com/charmbracelet/crush/internal/tui/components/core/status" "github.com/charmbracelet/crush/internal/tui/components/dialogs" "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" "github.com/charmbracelet/crush/internal/tui/components/dialogs/compact" "github.com/charmbracelet/crush/internal/tui/components/dialogs/filepicker" - initDialog "github.com/charmbracelet/crush/internal/tui/components/dialogs/init" "github.com/charmbracelet/crush/internal/tui/components/dialogs/models" "github.com/charmbracelet/crush/internal/tui/components/dialogs/permissions" "github.com/charmbracelet/crush/internal/tui/components/dialogs/quit" @@ -88,22 +88,7 @@ func (a appModel) Init() tea.Cmd { cmd = a.status.Init() cmds = append(cmds, cmd) - // Check if we should show the init dialog - cmds = append(cmds, func() tea.Msg { - shouldShow, err := config.ProjectNeedsInitialization() - if err != nil { - return util.InfoMsg{ - Type: util.InfoTypeError, - Msg: "Failed to check init status: " + err.Error(), - } - } - if shouldShow { - return dialogs.OpenDialogMsg{ - Model: initDialog.NewInitDialogCmp(), - } - } - return nil - }) + cmds = append(cmds, tea.EnableMouseAllMotion) return tea.Batch(cmds...) } @@ -115,8 +100,16 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyboardEnhancementsMsg: - return a, nil + for id, page := range a.pages { + m, pageCmd := page.Update(msg) + a.pages[id] = m.(util.Model) + if pageCmd != nil { + cmds = append(cmds, pageCmd) + } + } + return a, tea.Batch(cmds...) case tea.WindowSizeMsg: + a.completions.Update(msg) return a, a.handleWindowResize(msg.Width, msg.Height) // Completions messages @@ -127,9 +120,11 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Dialog messages case dialogs.OpenDialogMsg, dialogs.CloseDialogMsg: + u, completionCmd := a.completions.Update(completions.CloseCompletionsMsg{}) + a.completions = u.(completions.Completions) u, dialogCmd := a.dialog.Update(msg) a.dialog = u.(dialogs.DialogCmp) - return a, dialogCmd + return a, tea.Batch(completionCmd, dialogCmd) case commands.ShowArgumentsDialogMsg: return a, util.CmdHandler( dialogs.OpenDialogMsg{ @@ -179,7 +174,7 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Model Switch case models.ModelSelectedMsg: - config.UpdatePreferredModel(msg.ModelType, msg.Model) + config.Get().UpdatePreferredModel(msg.ModelType, msg.Model) // Update the agent with the new model/provider configuration if err := a.app.UpdateAgentModel(); err != nil { @@ -266,7 +261,7 @@ func (a *appModel) handleWindowResize(width, height int) tea.Cmd { var cmds []tea.Cmd a.wWidth, a.wHeight = width, height if a.showingFullHelp { - height -= 4 + height -= 5 } else { height -= 2 } @@ -332,6 +327,9 @@ func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd { // If the commands dialog is already open, close it return util.CmdHandler(dialogs.CloseDialogMsg{}) } + if a.dialog.HasDialogs() { + return nil // Don't open commands dialog if another dialog is active + } return util.CmdHandler(dialogs.OpenDialogMsg{ Model: commands.NewCommandDialog(a.selectedSessionID), }) @@ -393,10 +391,9 @@ func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd { // View renders the complete application interface including pages, dialogs, and overlays. func (a *appModel) View() tea.View { page := a.pages[a.currentPage] - if withHelp, ok := page.(layout.Help); ok { - a.keyMap.pageBindings = withHelp.Bindings() + if withHelp, ok := page.(core.KeyMapHelp); ok { + a.status.SetKeyMap(withHelp.Help()) } - a.status.SetKeyMap(a.keyMap) pageView := page.View() components := []string{ pageView, @@ -449,14 +446,14 @@ func (a *appModel) View() tea.View { // New creates and initializes a new TUI application model. func New(app *app.App) tea.Model { - chatPage := chat.NewChatPage(app) + chatPage := chat.New(app) keyMap := DefaultKeyMap() keyMap.pageBindings = chatPage.Bindings() model := &appModel{ currentPage: chat.ChatPageID, app: app, - status: status.NewStatusCmp(keyMap), + status: status.NewStatusCmp(), loadedPages: make(map[page.PageID]bool), keyMap: keyMap, diff --git a/internal/tui/util/util.go b/internal/tui/util/util.go index d737acb3f06a155ab52cc7eed7d32a634d85d582..1f4ea30c49c8fb0517a5068d3b7f05970638743a 100644 --- a/internal/tui/util/util.go +++ b/internal/tui/util/util.go @@ -1,6 +1,7 @@ package util import ( + "log/slog" "time" tea "github.com/charmbracelet/bubbletea/v2" @@ -22,6 +23,7 @@ func CmdHandler(msg tea.Msg) tea.Cmd { } func ReportError(err error) tea.Cmd { + slog.Error("Error reported", "error", err) return CmdHandler(InfoMsg{ Type: InfoTypeError, Msg: err.Error(), diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum deleted file mode 100644 index c592f283b6bdb1cb2b13aa4b0769b94811a1cfe9..0000000000000000000000000000000000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum +++ /dev/null @@ -1,60 +0,0 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0-beta.1 h1:ODs3brnqQM99Tq1PffODpAViYv3Bf8zOg464MU7p5ew= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0-beta.1/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/charmbracelet/bubbles/v2/textarea/textarea.go b/vendor/github.com/charmbracelet/bubbles/v2/textarea/textarea.go index 673985e67c6f53e82324c64c0a640671805600d1..f68db029188ba330e82c40b8cc89ecb30a0b258f 100644 --- a/vendor/github.com/charmbracelet/bubbles/v2/textarea/textarea.go +++ b/vendor/github.com/charmbracelet/bubbles/v2/textarea/textarea.go @@ -133,6 +133,13 @@ type LineInfo struct { CharOffset int } +// PromptInfo is a struct that can be used to store information about the +// prompt. +type PromptInfo struct { + LineNumber int + Focused bool +} + // CursorStyle is the style for real and virtual cursors. type CursorStyle struct { // Style styles the cursor block. @@ -287,7 +294,7 @@ type Model struct { // If promptFunc is set, it replaces Prompt as a generator for // prompt strings at the beginning of each line. - promptFunc func(line int, focused bool) string + promptFunc func(PromptInfo) string // promptWidth is the width of the prompt. promptWidth int @@ -983,14 +990,14 @@ func (m Model) Width() int { return m.width } -// moveToBegin moves the cursor to the beginning of the input. -func (m *Model) moveToBegin() { +// MoveToBegin moves the cursor to the beginning of the input. +func (m *Model) MoveToBegin() { m.row = 0 m.SetCursorColumn(0) } -// moveToEnd moves the cursor to the end of the input. -func (m *Model) moveToEnd() { +// MoveToEnd moves the cursor to the end of the input. +func (m *Model) MoveToEnd() { m.row = len(m.value) - 1 m.SetCursorColumn(len(m.value[m.row])) } @@ -1052,7 +1059,7 @@ func (m *Model) SetWidth(w int) { // promptWidth, it will be padded to the left. If it returns a prompt that is // longer, display artifacts may occur; the caller is responsible for computing // an adequate promptWidth. -func (m *Model) SetPromptFunc(promptWidth int, fn func(lineIndex int, focused bool) string) { +func (m *Model) SetPromptFunc(promptWidth int, fn func(PromptInfo) string) { m.promptFunc = fn m.promptWidth = promptWidth } @@ -1170,9 +1177,9 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { case key.Matches(msg, m.KeyMap.WordBackward): m.wordLeft() case key.Matches(msg, m.KeyMap.InputBegin): - m.moveToBegin() + m.MoveToBegin() case key.Matches(msg, m.KeyMap.InputEnd): - m.moveToEnd() + m.MoveToEnd() case key.Matches(msg, m.KeyMap.LowercaseWordForward): m.lowercaseRight() case key.Matches(msg, m.KeyMap.UppercaseWordForward): @@ -1320,7 +1327,10 @@ func (m Model) promptView(displayLine int) (prompt string) { if m.promptFunc == nil { return prompt } - prompt = m.promptFunc(displayLine, m.focus) + prompt = m.promptFunc(PromptInfo{ + LineNumber: displayLine, + Focused: m.focus, + }) width := lipgloss.Width(prompt) if width < m.promptWidth { prompt = fmt.Sprintf("%*s%s", m.promptWidth-width, "", prompt) diff --git a/vendor/github.com/charmbracelet/bubbletea/v2/tea.go b/vendor/github.com/charmbracelet/bubbletea/v2/tea.go index 5320e4463a3b673a2a980009ed2fb25bc2853c71..1a6be630366d40aaac4706f9ee1e775306091c4e 100644 --- a/vendor/github.com/charmbracelet/bubbletea/v2/tea.go +++ b/vendor/github.com/charmbracelet/bubbletea/v2/tea.go @@ -624,6 +624,10 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { switch msg.Mode { case ansi.AltScreenSaveCursorMode: p.renderer.enterAltScreen() + // Main and alternate screen have their own Kitty keyboard + // stack. We need to request keyboard enhancements again + // when entering/exiting the alternate screen. + p.requestKeyboardEnhancements() case ansi.TextCursorEnableMode: p.renderer.showCursor() case ansi.GraphemeClusteringMode: @@ -645,6 +649,10 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { switch msg.Mode { case ansi.AltScreenSaveCursorMode: p.renderer.exitAltScreen() + // Main and alternate screen have their own Kitty keyboard + // stack. We need to request keyboard enhancements again + // when entering/exiting the alternate screen. + p.requestKeyboardEnhancements() case ansi.TextCursorEnableMode: p.renderer.hideCursor() default: @@ -1410,13 +1418,16 @@ func (p *Program) stopRenderer(kill bool) { // requestKeyboardEnhancements tries to enable keyboard enhancements and read // the active keyboard enhancements from the terminal. func (p *Program) requestKeyboardEnhancements() { + // XXX: We write to the renderer directly so that we synchronize with the + // alt-screen state of the renderer. This is because the main screen and + // alternate screen have their own Kitty keyboard state stack. if p.requestedEnhancements.modifyOtherKeys > 0 { - p.execute(ansi.KeyModifierOptions(4, p.requestedEnhancements.modifyOtherKeys)) //nolint:mnd - p.execute(ansi.QueryModifyOtherKeys) + _, _ = p.renderer.writeString(ansi.KeyModifierOptions(4, p.requestedEnhancements.modifyOtherKeys)) //nolint:mnd + _, _ = p.renderer.writeString(ansi.QueryModifyOtherKeys) } if p.requestedEnhancements.kittyFlags > 0 { - p.execute(ansi.PushKittyKeyboard(p.requestedEnhancements.kittyFlags)) - p.execute(ansi.RequestKittyKeyboard) + _, _ = p.renderer.writeString(ansi.PushKittyKeyboard(p.requestedEnhancements.kittyFlags)) + _, _ = p.renderer.writeString(ansi.RequestKittyKeyboard) } } diff --git a/vendor/github.com/charmbracelet/fang/README.md b/vendor/github.com/charmbracelet/fang/README.md index 88a225cfd6e698d15dd29a9af0a5dca74b61ecf7..575b40ce13fa57eb0e41082943a3c21e05c82777 100644 --- a/vendor/github.com/charmbracelet/fang/README.md +++ b/vendor/github.com/charmbracelet/fang/README.md @@ -1,7 +1,7 @@ # Fang

- Charm Fang + Charm Fang

Latest Release @@ -12,7 +12,7 @@ The CLI starter kit. A small, experimental library for batteries-included [Cobra][cobra] applications.

- fang-02 + The Charm Fang mascot and title treatment

## Features @@ -45,6 +45,7 @@ To use it, invoke `fang.Execute` passing your root `*cobra.Command`: package main import ( + "context" "os" "github.com/charmbracelet/fang" @@ -56,7 +57,7 @@ func main() { Use: "example", Short: "A simple example program!", } - if err := fang.Execute(context.TODO(), cmd); err != nil { + if err := fang.Execute(context.Background(), cmd); err != nil { os.Exit(1) } } diff --git a/vendor/github.com/charmbracelet/fang/fang.go b/vendor/github.com/charmbracelet/fang/fang.go index c1f9bc06a5299c991bac569aa6868e3d08fcd37c..6a6ab99a63fc4debf404694473d23e0a576d2fab 100644 --- a/vendor/github.com/charmbracelet/fang/fang.go +++ b/vendor/github.com/charmbracelet/fang/fang.go @@ -4,11 +4,14 @@ package fang import ( "context" "fmt" + "io" "os" + "os/signal" "runtime/debug" "github.com/charmbracelet/colorprofile" "github.com/charmbracelet/lipgloss/v2" + "github.com/charmbracelet/x/term" mango "github.com/muesli/mango-cobra" "github.com/muesli/roff" "github.com/spf13/cobra" @@ -16,12 +19,24 @@ import ( const shaLen = 7 +// ErrorHandler handles an error, printing them to the given [io.Writer]. +// +// Note that this will only be used if the STDERR is a terminal, and should +// be used for styling only. +type ErrorHandler = func(w io.Writer, styles Styles, err error) + +// ColorSchemeFunc gets a [lipgloss.LightDarkFunc] and returns a [ColorScheme]. +type ColorSchemeFunc = func(lipgloss.LightDarkFunc) ColorScheme + type settings struct { completions bool manpages bool + skipVersion bool version string commit string - theme *ColorScheme + colorscheme ColorSchemeFunc + errHandler ErrorHandler + signals []os.Signal } // Option changes fang settings. @@ -41,10 +56,21 @@ func WithoutManpage() Option { } } +// WithColorSchemeFunc sets a function that return colorscheme. +func WithColorSchemeFunc(cs ColorSchemeFunc) Option { + return func(s *settings) { + s.colorscheme = cs + } +} + // WithTheme sets the colorscheme. +// +// Deprecated: use [WithColorSchemeFunc] instead. func WithTheme(theme ColorScheme) Option { return func(s *settings) { - s.theme = &theme + s.colorscheme = func(lipgloss.LightDarkFunc) ColorScheme { + return theme + } } } @@ -55,6 +81,13 @@ func WithVersion(version string) Option { } } +// WithoutVersion skips the `-v`/`--version` functionality. +func WithoutVersion() Option { + return func(s *settings) { + s.skipVersion = true + } +} + // WithCommit sets the commit SHA. func WithCommit(commit string) Option { return func(s *settings) { @@ -62,30 +95,45 @@ func WithCommit(commit string) Option { } } +// WithErrorHandler sets the error handler. +func WithErrorHandler(handler ErrorHandler) Option { + return func(s *settings) { + s.errHandler = handler + } +} + +// WithNotifySignal sets the signals that should interrupt the execution of the +// program. +func WithNotifySignal(signals ...os.Signal) Option { + return func(s *settings) { + s.signals = signals + } +} + // Execute applies fang to the command and executes it. func Execute(ctx context.Context, root *cobra.Command, options ...Option) error { opts := settings{ manpages: true, completions: true, + colorscheme: DefaultColorScheme, + errHandler: DefaultErrorHandler, } + for _, option := range options { option(&opts) } - if opts.theme == nil { - isDark := lipgloss.HasDarkBackground(os.Stdin, os.Stderr) - t := DefaultTheme(isDark) - opts.theme = &t + helpFunc := func(c *cobra.Command, _ []string) { + w := colorprofile.NewWriter(c.OutOrStdout(), os.Environ()) + helpFn(c, w, makeStyles(mustColorscheme(opts.colorscheme))) } - styles := makeStyles(*opts.theme) - - root.SetHelpFunc(func(c *cobra.Command, _ []string) { - w := colorprofile.NewWriter(c.OutOrStdout(), os.Environ()) - helpFn(c, w, styles) - }) root.SilenceUsage = true root.SilenceErrors = true + if !opts.skipVersion { + root.Version = buildVersion(opts) + } + root.SetHelpFunc(helpFunc) if opts.manpages { root.AddCommand(&cobra.Command{ @@ -108,34 +156,49 @@ func Execute(ctx context.Context, root *cobra.Command, options ...Option) error }) } - if opts.completions { - root.InitDefaultCompletionCmd() - } else { + if !opts.completions { root.CompletionOptions.DisableDefaultCmd = true } - if opts.version == "" { - if info, ok := debug.ReadBuildInfo(); ok && info.Main.Sum != "" { - opts.version = info.Main.Version - opts.commit = getKey(info, "vcs.revision") - } else { - opts.version = "unknown (built from source)" - } - } - if len(opts.commit) >= shaLen { - opts.version += " (" + opts.commit[:shaLen] + ")" + if len(opts.signals) > 0 { + var cancel context.CancelFunc + ctx, cancel = signal.NotifyContext(ctx, opts.signals...) + defer cancel() } - root.Version = opts.version - if err := root.ExecuteContext(ctx); err != nil { + if w, ok := root.ErrOrStderr().(term.File); ok { + // if stderr is not a tty, simply print the error without any + // styling or going through an [ErrorHandler]: + if !term.IsTerminal(w.Fd()) { + _, _ = fmt.Fprintln(w, err.Error()) + return err //nolint:wrapcheck + } + } w := colorprofile.NewWriter(root.ErrOrStderr(), os.Environ()) - writeError(w, styles, err) + opts.errHandler(w, makeStyles(mustColorscheme(opts.colorscheme)), err) return err //nolint:wrapcheck } return nil } +func buildVersion(opts settings) string { + commit := opts.commit + version := opts.version + if version == "" { + if info, ok := debug.ReadBuildInfo(); ok && info.Main.Sum != "" { + version = info.Main.Version + commit = getKey(info, "vcs.revision") + } else { + version = "unknown (built from source)" + } + } + if len(commit) >= shaLen { + version += " (" + commit[:shaLen] + ")" + } + return version +} + func getKey(info *debug.BuildInfo, key string) string { if info == nil { return "" diff --git a/vendor/github.com/charmbracelet/fang/help.go b/vendor/github.com/charmbracelet/fang/help.go index 340090eadf1f779c0e702b03440d7e7efb29b62b..ba2a6185844787e83753c51c3415d5ccc06e36ec 100644 --- a/vendor/github.com/charmbracelet/fang/help.go +++ b/vendor/github.com/charmbracelet/fang/help.go @@ -3,7 +3,10 @@ package fang import ( "cmp" "fmt" + "io" + "iter" "os" + "reflect" "regexp" "strconv" "strings" @@ -20,6 +23,7 @@ import ( const ( minSpace = 10 shortPad = 2 + longPad = 4 ) var width = sync.OnceValue(func() int { @@ -45,65 +49,95 @@ func helpFn(c *cobra.Command, w *colorprofile.Writer, styles Styles) { blockWidth = max(blockWidth, lipgloss.Width(ex)) } blockWidth = min(width()-padding, blockWidth+padding) + blockStyle := styles.Codeblock.Base.Width(blockWidth) - styles.Codeblock.Base = styles.Codeblock.Base.Width(blockWidth) + // if the color profile is ascii or notty, or if the block has no + // background color set, remove the vertical padding. + if w.Profile <= colorprofile.Ascii || reflect.DeepEqual(blockStyle.GetBackground(), lipgloss.NoColor{}) { + blockStyle = blockStyle.PaddingTop(0).PaddingBottom(0) + } _, _ = fmt.Fprintln(w, styles.Title.Render("usage")) - _, _ = fmt.Fprintln(w, styles.Codeblock.Base.Render(usage)) + _, _ = fmt.Fprintln(w, blockStyle.Render(usage)) if len(examples) > 0 { - cw := styles.Codeblock.Base.GetWidth() - styles.Codeblock.Base.GetHorizontalPadding() + cw := blockStyle.GetWidth() - blockStyle.GetHorizontalPadding() _, _ = fmt.Fprintln(w, styles.Title.Render("examples")) for i, example := range examples { if lipgloss.Width(example) > cw { examples[i] = ansi.Truncate(example, cw, "…") } } - _, _ = fmt.Fprintln(w, styles.Codeblock.Base.Render(strings.Join(examples, "\n"))) + _, _ = fmt.Fprintln(w, blockStyle.Render(strings.Join(examples, "\n"))) } + groups, groupKeys := evalGroups(c) cmds, cmdKeys := evalCmds(c, styles) flags, flagKeys := evalFlags(c, styles) space := calculateSpace(cmdKeys, flagKeys) - leftPadding := 4 - if len(cmds) > 0 { - _, _ = fmt.Fprintln(w, styles.Title.Render("commands")) - for _, k := range cmdKeys { - _, _ = fmt.Fprintln(w, lipgloss.JoinHorizontal( - lipgloss.Left, - lipgloss.NewStyle().PaddingLeft(leftPadding).Render(k), - strings.Repeat(" ", space-lipgloss.Width(k)), - cmds[k], - )) + for _, groupID := range groupKeys { + group := cmds[groupID] + if len(group) == 0 { + continue } + renderGroup(w, styles, space, groups[groupID], func(yield func(string, string) bool) { + for _, k := range cmdKeys { + cmds, ok := group[k] + if !ok { + continue + } + if !yield(k, cmds) { + return + } + } + }) } if len(flags) > 0 { - _, _ = fmt.Fprintln(w, styles.Title.Render("flags")) - for _, k := range flagKeys { - _, _ = fmt.Fprintln(w, lipgloss.JoinHorizontal( - lipgloss.Left, - lipgloss.NewStyle().PaddingLeft(leftPadding).Render(k), - strings.Repeat(" ", space-lipgloss.Width(k)), - flags[k], - )) - } + renderGroup(w, styles, space, "flags", func(yield func(string, string) bool) { + for _, k := range flagKeys { + if !yield(k, flags[k]) { + return + } + } + }) } _, _ = fmt.Fprintln(w) } -func writeError(w *colorprofile.Writer, styles Styles, err error) { +// DefaultErrorHandler is the default [ErrorHandler] implementation. +func DefaultErrorHandler(w io.Writer, styles Styles, err error) { _, _ = fmt.Fprintln(w, styles.ErrorHeader.String()) _, _ = fmt.Fprintln(w, styles.ErrorText.Render(err.Error()+".")) _, _ = fmt.Fprintln(w) - _, _ = fmt.Fprintln(w, lipgloss.JoinHorizontal( - lipgloss.Left, - styles.ErrorText.UnsetWidth().Render("Try"), - styles.Program.Flag.Render("--help"), - styles.ErrorText.UnsetWidth().UnsetMargins().UnsetTransform().PaddingLeft(1).Render("for usage."), - )) - _, _ = fmt.Fprintln(w) + if isUsageError(err) { + _, _ = fmt.Fprintln(w, lipgloss.JoinHorizontal( + lipgloss.Left, + styles.ErrorText.UnsetWidth().Render("Try"), + styles.Program.Flag.Render(" --help "), + styles.ErrorText.UnsetWidth().UnsetMargins().UnsetTransform().Render("for usage."), + )) + _, _ = fmt.Fprintln(w) + } +} + +// XXX: this is a hack to detect usage errors. +// See: https://github.com/spf13/cobra/pull/2266 +func isUsageError(err error) bool { + s := err.Error() + for _, prefix := range []string{ + "flag needs an argument:", + "unknown flag:", + "unknown shorthand flag:", + "unknown command", + "invalid argument", + } { + if strings.HasPrefix(s, prefix) { + return true + } + } + return false } func writeLongShort(w *colorprofile.Writer, styles Styles, longShort string) { @@ -118,8 +152,10 @@ var otherArgsRe = regexp.MustCompile(`(\[.*\])`) // styleUsage stylized styleUsage line for a given command. func styleUsage(c *cobra.Command, styles Program, complete bool) string { - // XXX: maybe use c.UseLine() here? u := c.Use + if complete { + u = c.UseLine() + } hasArgs := strings.Contains(u, "[args]") hasFlags := strings.Contains(u, "[flags]") || strings.Contains(u, "[--flags]") || c.HasFlags() || c.HasPersistentFlags() || c.HasAvailableFlags() hasCommands := strings.Contains(u, "[command]") || c.HasAvailableSubCommands() @@ -139,34 +175,38 @@ func styleUsage(c *cobra.Command, styles Program, complete bool) string { u = strings.TrimSpace(u) - useLine := []string{ - styles.Name.Render(u), - } - if !complete { - useLine[0] = styles.Command.Render(u) + useLine := []string{} + if complete { + parts := strings.Fields(u) + useLine = append(useLine, styles.Name.Render(parts[0])) + if len(parts) > 1 { + useLine = append(useLine, styles.Command.Render(" "+strings.Join(parts[1:], " "))) + } + } else { + useLine = append(useLine, styles.Command.Render(u)) } if hasCommands { useLine = append( useLine, - styles.DimmedArgument.Render("[command]"), + styles.DimmedArgument.Render(" [command]"), ) } if hasArgs { useLine = append( useLine, - styles.DimmedArgument.Render("[args]"), + styles.DimmedArgument.Render(" [args]"), ) } for _, arg := range otherArgs { useLine = append( useLine, - styles.DimmedArgument.Render(arg), + styles.DimmedArgument.Render(" "+arg), ) } if hasFlags { useLine = append( useLine, - styles.DimmedArgument.Render("[--flags]"), + styles.DimmedArgument.Render(" [--flags]"), ) } return lipgloss.JoinHorizontal(lipgloss.Left, useLine...) @@ -180,19 +220,21 @@ func styleExamples(c *cobra.Command, styles Styles) []string { } usage := []string{} examples := strings.Split(c.Example, "\n") + var indent bool for i, line := range examples { line = strings.TrimSpace(line) if (i == 0 || i == len(examples)-1) && line == "" { continue } - s := styleExample(c, line, styles.Codeblock) + s := styleExample(c, line, indent, styles.Codeblock) usage = append(usage, s) + indent = len(line) > 1 && (line[len(line)-1] == '\\' || line[len(line)-1] == '|') } return usage } -func styleExample(c *cobra.Command, line string, styles Codeblock) string { +func styleExample(c *cobra.Command, line string, indent bool, styles Codeblock) string { if strings.HasPrefix(line, "# ") { return lipgloss.JoinHorizontal( lipgloss.Left, @@ -200,66 +242,110 @@ func styleExample(c *cobra.Command, line string, styles Codeblock) string { ) } - args := strings.Fields(line) - var nextIsFlag bool var isQuotedString bool + var foundProgramName bool + var isRedirecting bool + programName := c.Root().Name() + args := strings.Fields(line) + var cleanArgs []string for i, arg := range args { - if i == 0 { - args[i] = styles.Program.Name.Render(arg) - continue + isQuoteStart := arg[0] == '"' || arg[0] == '\'' + isQuoteEnd := arg[len(arg)-1] == '"' || arg[len(arg)-1] == '\'' + isFlag := arg[0] == '-' + + switch i { + case 0: + args[i] = "" + if indent { + args[i] = styles.Program.DimmedArgument.Render(" ") + indent = false + } + default: + args[i] = styles.Program.DimmedArgument.Render(" ") } - quoteStart := arg[0] == '"' - quoteEnd := arg[len(arg)-1] == '"' - flagStart := arg[0] == '-' - if i == 1 && !quoteStart && !flagStart { - args[i] = styles.Program.Command.Render(arg) + if isRedirecting { + args[i] += styles.Program.DimmedArgument.Render(arg) + isRedirecting = false continue } - if quoteStart { - isQuotedString = true - } - if isQuotedString { - args[i] = styles.Program.QuotedString.Render(arg) - if quoteEnd { - isQuotedString = false + + switch arg { + case "\\": + if i == len(args)-1 { + args[i] += styles.Program.DimmedArgument.Render(arg) + continue } + case "|", "||", "-", "&", "&&": + args[i] += styles.Program.DimmedArgument.Render(arg) continue } - if nextIsFlag { - args[i] = styles.Program.Flag.Render(arg) + + if isRedirect(arg) { + args[i] += styles.Program.DimmedArgument.Render(arg) + isRedirecting = true continue } - var dashes string - if strings.HasPrefix(arg, "-") { - dashes = "-" + + if !foundProgramName { //nolint:nestif + if isQuotedString { + args[i] += styles.Program.QuotedString.Render(arg) + isQuotedString = !isQuoteEnd + continue + } + if left, right, ok := strings.Cut(arg, "="); ok { + args[i] += styles.Program.Flag.Render(left + "=") + if right[0] == '"' { + isQuotedString = true + args[i] += styles.Program.QuotedString.Render(right) + continue + } + args[i] += styles.Program.Argument.Render(right) + continue + } + + if arg == programName { + args[i] += styles.Program.Name.Render(arg) + foundProgramName = true + continue + } } - if strings.HasPrefix(arg, "--") { - dashes = "--" + + if !isQuoteStart && !isQuotedString && !isFlag { + cleanArgs = append(cleanArgs, arg) + } + + if !isQuoteStart && !isFlag && isSubCommand(c, cleanArgs, arg) { + args[i] += styles.Program.Command.Render(arg) + continue + } + isQuotedString = isQuotedString || isQuoteStart + if isQuotedString { + args[i] += styles.Program.QuotedString.Render(arg) + isQuotedString = !isQuoteEnd + continue } // handle a flag - if dashes != "" { + if isFlag { name, value, ok := strings.Cut(arg, "=") - name = strings.TrimPrefix(name, dashes) // it is --flag=value if ok { - args[i] = lipgloss.JoinHorizontal( + args[i] += lipgloss.JoinHorizontal( lipgloss.Left, - styles.Program.Flag.Render(dashes+name+"="), - styles.Program.Argument.UnsetPadding().Render(value), + styles.Program.Flag.Render(name+"="), + styles.Program.Argument.Render(value), ) continue } // it is either --bool-flag or --flag value - args[i] = lipgloss.JoinHorizontal( + args[i] += lipgloss.JoinHorizontal( lipgloss.Left, - styles.Program.Flag.Render(dashes+name), + styles.Program.Flag.Render(name), ) - // if the flag is not a bool flag, next arg continues current flag - nextIsFlag = !isFlagBool(c, name) continue } - args[i] = styles.Program.Argument.Render(arg) + + args[i] += styles.Program.Argument.Render(arg) } return lipgloss.JoinHorizontal( @@ -284,8 +370,7 @@ func evalFlags(c *cobra.Command, styles Styles) (map[string]string, []string) { } else { parts = append( parts, - styles.Program.Flag.Render("-"+f.Shorthand), - styles.Program.Flag.Render("--"+f.Name), + styles.Program.Flag.Render("-"+f.Shorthand+" --"+f.Name), ) } key := lipgloss.JoinHorizontal(lipgloss.Left, parts...) @@ -303,22 +388,50 @@ func evalFlags(c *cobra.Command, styles Styles) (map[string]string, []string) { return flags, keys } -func evalCmds(c *cobra.Command, styles Styles) (map[string]string, []string) { +// result is map[groupID]map[styled cmd name]styled cmd help, and the keys in +// the order they are defined. +func evalCmds(c *cobra.Command, styles Styles) (map[string](map[string]string), []string) { padStyle := lipgloss.NewStyle().PaddingLeft(0) //nolint:mnd keys := []string{} - cmds := map[string]string{} + cmds := map[string]map[string]string{} for _, sc := range c.Commands() { if sc.Hidden { continue } + if _, ok := cmds[sc.GroupID]; !ok { + cmds[sc.GroupID] = map[string]string{} + } key := padStyle.Render(styleUsage(sc, styles.Program, false)) help := styles.FlagDescription.Render(sc.Short) - cmds[key] = help + cmds[sc.GroupID][key] = help keys = append(keys, key) } return cmds, keys } +func evalGroups(c *cobra.Command) (map[string]string, []string) { + // make sure the default group is the first + ids := []string{""} + groups := map[string]string{"": "commands"} + for _, g := range c.Groups() { + groups[g.ID] = g.Title + ids = append(ids, g.ID) + } + return groups, ids +} + +func renderGroup(w io.Writer, styles Styles, space int, name string, items iter.Seq2[string, string]) { + _, _ = fmt.Fprintln(w, styles.Title.Render(name)) + for key, help := range items { + _, _ = fmt.Fprintln(w, lipgloss.JoinHorizontal( + lipgloss.Left, + lipgloss.NewStyle().PaddingLeft(longPad).Render(key), + strings.Repeat(" ", space-lipgloss.Width(key)), + help, + )) + } +} + func calculateSpace(k1, k2 []string) int { const spaceBetween = 2 space := minSpace @@ -328,13 +441,18 @@ func calculateSpace(k1, k2 []string) int { return space } -func isFlagBool(c *cobra.Command, name string) bool { - flag := c.Flags().Lookup(name) - if flag == nil && len(name) == 1 { - flag = c.Flags().ShorthandLookup(name) - } - if flag == nil { - return false +func isSubCommand(c *cobra.Command, args []string, word string) bool { + cmd, _, _ := c.Root().Traverse(args) + return cmd != nil && cmd.Name() == word +} + +var redirectPrefixes = []string{">", "<", "&>", "2>", "1>", ">>", "2>>"} + +func isRedirect(s string) bool { + for _, p := range redirectPrefixes { + if strings.HasPrefix(s, p) { + return true + } } - return flag.Value.Type() == "bool" + return false } diff --git a/vendor/github.com/charmbracelet/fang/theme.go b/vendor/github.com/charmbracelet/fang/theme.go index 8e3389f6e84b4cc66ed0369f2425c4cc7c27d1b4..12cc868089d475d397691e757f55614a4614e44d 100644 --- a/vendor/github.com/charmbracelet/fang/theme.go +++ b/vendor/github.com/charmbracelet/fang/theme.go @@ -2,10 +2,12 @@ package fang import ( "image/color" + "os" "strings" "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/x/exp/charmtone" + "github.com/charmbracelet/x/term" "golang.org/x/text/cases" "golang.org/x/text/language" ) @@ -31,8 +33,14 @@ type ColorScheme struct { } // DefaultTheme is the default colorscheme. +// +// Deprecated: use [DefaultColorScheme] instead. func DefaultTheme(isDark bool) ColorScheme { - c := lipgloss.LightDark(isDark) + return DefaultColorScheme(lipgloss.LightDark(isDark)) +} + +// DefaultColorScheme is the default colorscheme. +func DefaultColorScheme(c lipgloss.LightDarkFunc) ColorScheme { return ColorScheme{ Base: c(charmtone.Charcoal, charmtone.Ash), Title: charmtone.Charple, @@ -45,7 +53,7 @@ func DefaultTheme(isDark bool) ColorScheme { Argument: c(charmtone.Charcoal, charmtone.Ash), Description: c(charmtone.Charcoal, charmtone.Ash), // flag and command descriptions FlagDefault: c(charmtone.Smoke, charmtone.Squid), // flag default values in descriptions - QuotedString: c(charmtone.Charcoal, charmtone.Ash), + QuotedString: c(charmtone.Coral, charmtone.Salmon), ErrorHeader: [2]color.Color{ charmtone.Butter, charmtone.Cherry, @@ -53,6 +61,26 @@ func DefaultTheme(isDark bool) ColorScheme { } } +// AnsiColorScheme is a ANSI colorscheme. +func AnsiColorScheme(c lipgloss.LightDarkFunc) ColorScheme { + base := c(lipgloss.Black, lipgloss.White) + return ColorScheme{ + Base: base, + Title: lipgloss.Blue, + Description: base, + Comment: c(lipgloss.BrightWhite, lipgloss.BrightBlack), + Flag: lipgloss.Magenta, + FlagDefault: lipgloss.BrightMagenta, + Command: lipgloss.Cyan, + QuotedString: lipgloss.Green, + Argument: base, + Help: base, + Dash: base, + ErrorHeader: [2]color.Color{lipgloss.Black, lipgloss.Red}, + ErrorDetails: lipgloss.Red, + } +} + // Styles represents all the styles used. type Styles struct { Text lipgloss.Style @@ -84,6 +112,14 @@ type Program struct { QuotedString lipgloss.Style } +func mustColorscheme(cs func(lipgloss.LightDarkFunc) ColorScheme) ColorScheme { + var isDark bool + if term.IsTerminal(os.Stdout.Fd()) { + isDark = lipgloss.HasDarkBackground(os.Stdin, os.Stdout) + } + return cs(lipgloss.LightDark(isDark)) +} + func makeStyles(cs ColorScheme) Styles { //nolint:mnd return Styles{ @@ -98,8 +134,7 @@ func makeStyles(cs ColorScheme) Styles { Foreground(cs.Description). Transform(titleFirstWord), FlagDefault: lipgloss.NewStyle(). - Foreground(cs.FlagDefault). - PaddingLeft(1), + Foreground(cs.FlagDefault), Codeblock: Codeblock{ Base: lipgloss.NewStyle(). Background(cs.Codeblock). @@ -116,23 +151,18 @@ func makeStyles(cs ColorScheme) Styles { Background(cs.Codeblock). Foreground(cs.Program), Flag: lipgloss.NewStyle(). - PaddingLeft(1). Background(cs.Codeblock). Foreground(cs.Flag), Argument: lipgloss.NewStyle(). - PaddingLeft(1). Background(cs.Codeblock). Foreground(cs.Argument), DimmedArgument: lipgloss.NewStyle(). - PaddingLeft(1). Background(cs.Codeblock). Foreground(cs.DimmedArgument), Command: lipgloss.NewStyle(). - PaddingLeft(1). Background(cs.Codeblock). Foreground(cs.Command), QuotedString: lipgloss.NewStyle(). - PaddingLeft(1). Background(cs.Codeblock). Foreground(cs.QuotedString), }, @@ -141,18 +171,14 @@ func makeStyles(cs ColorScheme) Styles { Name: lipgloss.NewStyle(). Foreground(cs.Program), Argument: lipgloss.NewStyle(). - PaddingLeft(1). Foreground(cs.Argument), DimmedArgument: lipgloss.NewStyle(). - PaddingLeft(1). Foreground(cs.DimmedArgument), Flag: lipgloss.NewStyle(). - PaddingLeft(1). Foreground(cs.Flag), Command: lipgloss.NewStyle(). Foreground(cs.Command), QuotedString: lipgloss.NewStyle(). - PaddingLeft(1). Foreground(cs.QuotedString), }, Span: lipgloss.NewStyle(). diff --git a/vendor/github.com/charmbracelet/lipgloss/v2/get.go b/vendor/github.com/charmbracelet/lipgloss/v2/get.go index c54cf647de0e60e0250880d7a3ac662e857dc3b6..350bbc79edd06d313129032a6f95d6b112c8ba93 100644 --- a/vendor/github.com/charmbracelet/lipgloss/v2/get.go +++ b/vendor/github.com/charmbracelet/lipgloss/v2/get.go @@ -135,6 +135,16 @@ func (s Style) GetPaddingLeft() int { return s.getAsInt(paddingLeftKey) } +// GetPaddingChar returns the style's padding character. If no value is set a +// space (`\u0020`) is returned. +func (s Style) GetPaddingChar() rune { + char := s.getAsRune(paddingCharKey) + if char == 0 { + return ' ' + } + return char +} + // GetHorizontalPadding returns the style's left and right padding. Unset // values are measured as 0. func (s Style) GetHorizontalPadding() int { @@ -186,6 +196,16 @@ func (s Style) GetMarginLeft() int { return s.getAsInt(marginLeftKey) } +// GetMarginChar returns the style's padding character. If no value is set a +// space (`\u0020`) is returned. +func (s Style) GetMarginChar() rune { + char := s.getAsRune(marginCharKey) + if char == 0 { + return ' ' + } + return char +} + // GetHorizontalMargins returns the style's left and right margins. Unset // values are measured as 0. func (s Style) GetHorizontalMargins() int { @@ -432,6 +452,19 @@ func (s Style) isSet(k propKey) bool { return s.props.has(k) } +func (s Style) getAsRune(k propKey) rune { + if !s.isSet(k) { + return 0 + } + switch k { //nolint:exhaustive + case paddingCharKey: + return s.paddingChar + case marginCharKey: + return s.marginChar + } + return 0 +} + func (s Style) getAsBool(k propKey, defaultVal bool) bool { if !s.isSet(k) { return defaultVal diff --git a/vendor/github.com/charmbracelet/lipgloss/v2/set.go b/vendor/github.com/charmbracelet/lipgloss/v2/set.go index 0934c9c205ba4879a844c9b42eaa994d1ca9d106..32893668b6ade932583f9151b2563eece25cef1d 100644 --- a/vendor/github.com/charmbracelet/lipgloss/v2/set.go +++ b/vendor/github.com/charmbracelet/lipgloss/v2/set.go @@ -29,6 +29,8 @@ func (s *Style) set(key propKey, value any) { s.paddingBottom = max(0, value.(int)) case paddingLeftKey: s.paddingLeft = max(0, value.(int)) + case paddingCharKey: + s.paddingChar = value.(rune) case marginTopKey: s.marginTop = max(0, value.(int)) case marginRightKey: @@ -39,6 +41,8 @@ func (s *Style) set(key propKey, value any) { s.marginLeft = max(0, value.(int)) case marginBackgroundKey: s.marginBgColor = colorOrNil(value) + case marginCharKey: + s.marginChar = value.(rune) case borderStyleKey: s.borderStyle = value.(Border) case borderTopForegroundKey: @@ -111,6 +115,8 @@ func (s *Style) setFrom(key propKey, i Style) { s.set(paddingBottomKey, i.paddingBottom) case paddingLeftKey: s.set(paddingLeftKey, i.paddingLeft) + case paddingCharKey: + s.set(paddingCharKey, i.paddingChar) case marginTopKey: s.set(marginTopKey, i.marginTop) case marginRightKey: @@ -121,6 +127,8 @@ func (s *Style) setFrom(key propKey, i Style) { s.set(marginLeftKey, i.marginLeft) case marginBackgroundKey: s.set(marginBackgroundKey, i.marginBgColor) + case marginCharKey: + s.set(marginCharKey, i.marginChar) case borderStyleKey: s.set(borderStyleKey, i.borderStyle) case borderTopForegroundKey: @@ -320,6 +328,18 @@ func (s Style) PaddingBottom(i int) Style { return s } +// PaddingChar sets the character used for padding. This is useful for +// rendering blocks with a specific character, such as a space or a dot. +// Example of using [NBSP] as padding to prevent line breaks: +// +// ```go +// s := lipgloss.NewStyle().PaddingChar(lipgloss.NBSP) +// ``` +func (s Style) PaddingChar(r rune) Style { + s.set(paddingCharKey, r) + return s +} + // ColorWhitespace determines whether or not the background color should be // applied to the padding. This is true by default as it's more than likely the // desired and expected behavior, but it can be disabled for certain graphic @@ -390,6 +410,13 @@ func (s Style) MarginBackground(c color.Color) Style { return s } +// MarginChar sets the character used for the margin. This is useful for +// rendering blocks with a specific character, such as a space or a dot. +func (s Style) MarginChar(r rune) Style { + s.set(marginCharKey, r) + return s +} + // Border is shorthand for setting the border style and which sides should // have a border at once. The variadic argument sides works as follows: // diff --git a/vendor/github.com/charmbracelet/lipgloss/v2/style.go b/vendor/github.com/charmbracelet/lipgloss/v2/style.go index 5a40a94a367c2070f73cd8815aa349302dae01aa..ef13f6a4476cd1c3c0e4619795dd62d92804d7e1 100644 --- a/vendor/github.com/charmbracelet/lipgloss/v2/style.go +++ b/vendor/github.com/charmbracelet/lipgloss/v2/style.go @@ -10,7 +10,8 @@ import ( ) const ( - nbsp = '\u00A0' + // NBSP is the non-breaking space rune. + NBSP = '\u00A0' tabWidthDefault = 4 ) @@ -44,6 +45,7 @@ const ( paddingRightKey paddingBottomKey paddingLeftKey + paddingCharKey // Margins. marginTopKey @@ -51,6 +53,7 @@ const ( marginBottomKey marginLeftKey marginBackgroundKey + marginCharKey // Border runes. borderStyleKey @@ -128,12 +131,14 @@ type Style struct { paddingRight int paddingBottom int paddingLeft int + paddingChar rune marginTop int marginRight int marginBottom int marginLeft int marginBgColor color.Color + marginChar rune borderStyle Border borderTopFgColor color.Color @@ -387,23 +392,24 @@ func (s Style) Render(strs ...string) string { // Padding if !inline { //nolint:nestif + padChar := s.paddingChar + if padChar == 0 { + padChar = ' ' + } if leftPadding > 0 { var st *ansi.Style if colorWhitespace || styleWhitespace { st = &teWhitespace } - str = padLeft(str, leftPadding, st, nbsp) + str = padLeft(str, leftPadding, st, padChar) } - // XXX: We use a non-breaking space to pad so that the padding is - // preserved when the string is copied and pasted. - if rightPadding > 0 { var st *ansi.Style if colorWhitespace || styleWhitespace { st = &teWhitespace } - str = padRight(str, rightPadding, st, nbsp) + str = padRight(str, rightPadding, st, padChar) } if topPadding > 0 { @@ -494,8 +500,12 @@ func (s Style) applyMargins(str string, inline bool) string { } // Add left and right margin - str = padLeft(str, leftMargin, &style, ' ') - str = padRight(str, rightMargin, &style, ' ') + marginChar := s.marginChar + if marginChar == 0 { + marginChar = ' ' + } + str = padLeft(str, leftMargin, &style, marginChar) + str = padRight(str, rightMargin, &style, marginChar) // Top/bottom margin if !inline { diff --git a/vendor/github.com/charmbracelet/lipgloss/v2/unset.go b/vendor/github.com/charmbracelet/lipgloss/v2/unset.go index 1086e722686bfa48a5910c5aac110057977a501d..b6f96607c0e0c8b31f23540ef492f4d25e22c346 100644 --- a/vendor/github.com/charmbracelet/lipgloss/v2/unset.go +++ b/vendor/github.com/charmbracelet/lipgloss/v2/unset.go @@ -96,6 +96,13 @@ func (s Style) UnsetPadding() Style { s.unset(paddingRightKey) s.unset(paddingTopKey) s.unset(paddingBottomKey) + s.unset(paddingCharKey) + return s +} + +// UnsetPaddingChar removes the padding character style rule, if set. +func (s Style) UnsetPaddingChar() Style { + s.unset(paddingCharKey) return s } diff --git a/vendor/github.com/charmbracelet/x/exp/charmtone/charmtone.go b/vendor/github.com/charmbracelet/x/exp/charmtone/charmtone.go index 48cb93adfb19bfedfcda0e1ce2fcb42c2f64785e..6e32f7f5405de89eeea58003f8860e255861ccee 100644 --- a/vendor/github.com/charmbracelet/x/exp/charmtone/charmtone.go +++ b/vendor/github.com/charmbracelet/x/exp/charmtone/charmtone.go @@ -65,7 +65,7 @@ const ( Citron Zest Pepper - Barbeque + BBQ Charcoal Iron Oyster @@ -74,6 +74,22 @@ const ( Ash Salt Butter + + // Diffs: additions. The brightest color in this set is Julep, defined + // above. + Pickle + Gator + Spinach + + // Diffs: deletions. The brightest color in this set is Cherry, defined + // above. + Pom + Steak + Toast + + // Provisional. + NeueGuac + NeueZinc ) // RGBA returns the red, green, blue, and alpha values of the color. It @@ -139,7 +155,7 @@ func (k Key) String() string { Citron: "Citron", Zest: "Zest", Pepper: "Pepper", - Barbeque: "Barbeque", + BBQ: "BBQ", Charcoal: "Charcoal", Iron: "Iron", Oyster: "Oyster", @@ -148,6 +164,20 @@ func (k Key) String() string { Salt: "Salt", Ash: "Ash", Butter: "Butter", + + // Diffs: additions. + Pickle: "Pickle", + Gator: "Gator", + Spinach: "Spinach", + + // Diffs: deletions. + Pom: "Pom", + Steak: "Steak", + Toast: "Toast", + + // Provisional. + NeueGuac: "Neue Guac", + NeueZinc: "Neue Zinc", }[k] } @@ -193,17 +223,17 @@ func (k Key) Hex() string { Damson: "#007AB8", Malibu: "#00A4FF", Sardine: "#4FBEFE", - Zinc: "#0e9996", + Zinc: "#10B1AE", Turtle: "#0ADCD9", Lichen: "#5CDFEA", - Guac: "#00b875", + Guac: "#12C78F", Julep: "#00FFB2", Bok: "#68FFD6", Mustard: "#F5EF34", Citron: "#E8FF27", Zest: "#E8FE96", Pepper: "#201F26", - Barbeque: "#2d2c35", + BBQ: "#2d2c35", Charcoal: "#3A3943", Iron: "#4D4C57", Oyster: "#605F6B", @@ -212,6 +242,20 @@ func (k Key) Hex() string { Ash: "#DFDBDD", Salt: "#F1EFEF", Butter: "#FFFAF1", + + // Diffs: additions. + Pickle: "#00A475", + Gator: "#18463D", + Spinach: "#1C3634", + + // Diffs: deletions. + Pom: "#AB2454", + Steak: "#582238", + Toast: "#412130", + + // Provisional. + NeueGuac: "#00b875", + NeueZinc: "#0e9996", }[k] } @@ -267,7 +311,7 @@ func Keys() []Key { Citron, Zest, Pepper, - Barbeque, + BBQ, Charcoal, Iron, Oyster, @@ -276,6 +320,8 @@ func Keys() []Key { Ash, Salt, Butter, + + // XXX: additions and deletions are not included, yet. } } diff --git a/vendor/github.com/mark3labs/mcp-go/client/client.go b/vendor/github.com/mark3labs/mcp-go/client/client.go index dd0e31a013595ccbb900a10fe413e02d1ed9d0ad..e2c466586050cf69e2015e83056fdaf6eda949f6 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/client.go +++ b/vendor/github.com/mark3labs/mcp-go/client/client.go @@ -22,6 +22,7 @@ type Client struct { requestID atomic.Int64 clientCapabilities mcp.ClientCapabilities serverCapabilities mcp.ServerCapabilities + samplingHandler SamplingHandler } type ClientOption func(*Client) @@ -33,6 +34,21 @@ func WithClientCapabilities(capabilities mcp.ClientCapabilities) ClientOption { } } +// WithSamplingHandler sets the sampling handler for the client. +// When set, the client will declare sampling capability during initialization. +func WithSamplingHandler(handler SamplingHandler) ClientOption { + return func(c *Client) { + c.samplingHandler = handler + } +} + +// WithSession assumes a MCP Session has already been initialized +func WithSession() ClientOption { + return func(c *Client) { + c.initialized = true + } +} + // NewClient creates a new MCP client with the given transport. // Usage: // @@ -71,6 +87,12 @@ func (c *Client) Start(ctx context.Context) error { handler(notification) } }) + + // Set up request handler for bidirectional communication (e.g., sampling) + if bidirectional, ok := c.transport.(transport.BidirectionalInterface); ok { + bidirectional.SetRequestHandler(c.handleIncomingRequest) + } + return nil } @@ -127,6 +149,12 @@ func (c *Client) Initialize( ctx context.Context, request mcp.InitializeRequest, ) (*mcp.InitializeResult, error) { + // Merge client capabilities with sampling capability if handler is configured + capabilities := request.Params.Capabilities + if c.samplingHandler != nil { + capabilities.Sampling = &struct{}{} + } + // Ensure we send a params object with all required fields params := struct { ProtocolVersion string `json:"protocolVersion"` @@ -135,7 +163,7 @@ func (c *Client) Initialize( }{ ProtocolVersion: request.Params.ProtocolVersion, ClientInfo: request.Params.ClientInfo, - Capabilities: request.Params.Capabilities, // Will be empty struct if not set + Capabilities: capabilities, } response, err := c.sendRequest(ctx, "initialize", params) @@ -398,6 +426,64 @@ func (c *Client) Complete( return &result, nil } +// handleIncomingRequest processes incoming requests from the server. +// This is the main entry point for server-to-client requests like sampling. +func (c *Client) handleIncomingRequest(ctx context.Context, request transport.JSONRPCRequest) (*transport.JSONRPCResponse, error) { + switch request.Method { + case string(mcp.MethodSamplingCreateMessage): + return c.handleSamplingRequestTransport(ctx, request) + default: + return nil, fmt.Errorf("unsupported request method: %s", request.Method) + } +} + +// handleSamplingRequestTransport handles sampling requests at the transport level. +func (c *Client) handleSamplingRequestTransport(ctx context.Context, request transport.JSONRPCRequest) (*transport.JSONRPCResponse, error) { + if c.samplingHandler == nil { + return nil, fmt.Errorf("no sampling handler configured") + } + + // Parse the request parameters + var params mcp.CreateMessageParams + if request.Params != nil { + paramsBytes, err := json.Marshal(request.Params) + if err != nil { + return nil, fmt.Errorf("failed to marshal params: %w", err) + } + if err := json.Unmarshal(paramsBytes, ¶ms); err != nil { + return nil, fmt.Errorf("failed to unmarshal params: %w", err) + } + } + + // Create the MCP request + mcpRequest := mcp.CreateMessageRequest{ + Request: mcp.Request{ + Method: string(mcp.MethodSamplingCreateMessage), + }, + CreateMessageParams: params, + } + + // Call the sampling handler + result, err := c.samplingHandler.CreateMessage(ctx, mcpRequest) + if err != nil { + return nil, err + } + + // Marshal the result + resultBytes, err := json.Marshal(result) + if err != nil { + return nil, fmt.Errorf("failed to marshal result: %w", err) + } + + // Create the transport response + response := &transport.JSONRPCResponse{ + JSONRPC: mcp.JSONRPC_VERSION, + ID: request.ID, + Result: json.RawMessage(resultBytes), + } + + return response, nil +} func listByPage[T any]( ctx context.Context, client *Client, @@ -432,3 +518,17 @@ func (c *Client) GetServerCapabilities() mcp.ServerCapabilities { func (c *Client) GetClientCapabilities() mcp.ClientCapabilities { return c.clientCapabilities } + +// GetSessionId returns the session ID of the transport. +// If the transport does not support sessions, it returns an empty string. +func (c *Client) GetSessionId() string { + if c.transport == nil { + return "" + } + return c.transport.GetSessionId() +} + +// IsInitialized returns true if the client has been initialized. +func (c *Client) IsInitialized() bool { + return c.initialized +} diff --git a/vendor/github.com/mark3labs/mcp-go/client/http.go b/vendor/github.com/mark3labs/mcp-go/client/http.go index cb3be35d64cfc731efe2cef0c268a018c53a9538..d001a1e63d08e42d7457adbf5c497d93d029e203 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/http.go +++ b/vendor/github.com/mark3labs/mcp-go/client/http.go @@ -13,5 +13,10 @@ func NewStreamableHttpClient(baseURL string, options ...transport.StreamableHTTP if err != nil { return nil, fmt.Errorf("failed to create SSE transport: %w", err) } - return NewClient(trans), nil + clientOptions := make([]ClientOption, 0) + sessionID := trans.GetSessionId() + if sessionID != "" { + clientOptions = append(clientOptions, WithSession()) + } + return NewClient(trans, clientOptions...), nil } diff --git a/vendor/github.com/mark3labs/mcp-go/client/sampling.go b/vendor/github.com/mark3labs/mcp-go/client/sampling.go new file mode 100644 index 0000000000000000000000000000000000000000..245e2c1f7f305ddb75658a345eddcaba5e2898e3 --- /dev/null +++ b/vendor/github.com/mark3labs/mcp-go/client/sampling.go @@ -0,0 +1,20 @@ +package client + +import ( + "context" + + "github.com/mark3labs/mcp-go/mcp" +) + +// SamplingHandler defines the interface for handling sampling requests from servers. +// Clients can implement this interface to provide LLM sampling capabilities to servers. +type SamplingHandler interface { + // CreateMessage handles a sampling request from the server and returns the generated message. + // The implementation should: + // 1. Validate the request parameters + // 2. Optionally prompt the user for approval (human-in-the-loop) + // 3. Select an appropriate model based on preferences + // 4. Generate the response using the selected model + // 5. Return the result with model information and stop reason + CreateMessage(ctx context.Context, request mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) +} diff --git a/vendor/github.com/mark3labs/mcp-go/client/stdio.go b/vendor/github.com/mark3labs/mcp-go/client/stdio.go index 100c08a7cc0529ca30ca1386f74f6ea4f9be4654..199ec14c381b57c12d691495179cf0c45029d29e 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/stdio.go +++ b/vendor/github.com/mark3labs/mcp-go/client/stdio.go @@ -19,10 +19,26 @@ func NewStdioMCPClient( env []string, args ...string, ) (*Client, error) { + return NewStdioMCPClientWithOptions(command, env, args) +} + +// NewStdioMCPClientWithOptions creates a new stdio-based MCP client that communicates with a subprocess. +// It launches the specified command with given arguments and sets up stdin/stdout pipes for communication. +// Optional configuration functions can be provided to customize the transport before it starts, +// such as setting a custom command function. +// +// NOTICE: NewStdioMCPClientWithOptions automatically starts the underlying transport. +// Don't call the Start method manually. +// This is for backward compatibility. +func NewStdioMCPClientWithOptions( + command string, + env []string, + args []string, + opts ...transport.StdioOption, +) (*Client, error) { + stdioTransport := transport.NewStdioWithOptions(command, env, args, opts...) - stdioTransport := transport.NewStdio(command, env, args...) - err := stdioTransport.Start(context.Background()) - if err != nil { + if err := stdioTransport.Start(context.Background()); err != nil { return nil, fmt.Errorf("failed to start stdio transport: %w", err) } diff --git a/vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go b/vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go index 90fc2fae1f05ebf635b46d0fc415e0260348d3a0..0e2393f0731bcf361d5544da99304d1f07e08706 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go +++ b/vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go @@ -68,3 +68,7 @@ func (c *InProcessTransport) SetNotificationHandler(handler func(notification mc func (*InProcessTransport) Close() error { return nil } + +func (c *InProcessTransport) GetSessionId() string { + return "" +} diff --git a/vendor/github.com/mark3labs/mcp-go/client/transport/interface.go b/vendor/github.com/mark3labs/mcp-go/client/transport/interface.go index c83c7c65a3a8b0c7a301564144516242919fe2a5..5f8ed6180b6404a1a0f4085c5557aeb1789e3485 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/transport/interface.go +++ b/vendor/github.com/mark3labs/mcp-go/client/transport/interface.go @@ -29,6 +29,22 @@ type Interface interface { // Close the connection. Close() error + + // GetSessionId returns the session ID of the transport. + GetSessionId() string +} + +// RequestHandler defines a function that handles incoming requests from the server. +type RequestHandler func(ctx context.Context, request JSONRPCRequest) (*JSONRPCResponse, error) + +// BidirectionalInterface extends Interface to support incoming requests from the server. +// This is used for features like sampling where the server can send requests to the client. +type BidirectionalInterface interface { + Interface + + // SetRequestHandler sets the handler for incoming requests from the server. + // The handler should process the request and return a response. + SetRequestHandler(handler RequestHandler) } type JSONRPCRequest struct { @@ -41,10 +57,10 @@ type JSONRPCRequest struct { type JSONRPCResponse struct { JSONRPC string `json:"jsonrpc"` ID mcp.RequestId `json:"id"` - Result json.RawMessage `json:"result"` + Result json.RawMessage `json:"result,omitempty"` Error *struct { Code int `json:"code"` Message string `json:"message"` Data json.RawMessage `json:"data"` - } `json:"error"` + } `json:"error,omitempty"` } diff --git a/vendor/github.com/mark3labs/mcp-go/client/transport/sse.go b/vendor/github.com/mark3labs/mcp-go/client/transport/sse.go index b22ff62d40124b765b633d2b1700c7407d92d041..ffe3247f0ecd87a4e9c68df72b726a8cc44a7736 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/transport/sse.go +++ b/vendor/github.com/mark3labs/mcp-go/client/transport/sse.go @@ -428,6 +428,12 @@ func (c *SSE) Close() error { return nil } +// GetSessionId returns the session ID of the transport. +// Since SSE does not maintain a session ID, it returns an empty string. +func (c *SSE) GetSessionId() string { + return "" +} + // SendNotification sends a JSON-RPC notification to the server without expecting a response. func (c *SSE) SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error { if c.endpoint == nil { diff --git a/vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go b/vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go index c300c405f7e3880f0b94e1e09e3ee5ca7def732a..c36dc2d37737d71d9028ba11485932c23bb09f9f 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go +++ b/vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go @@ -23,6 +23,7 @@ type Stdio struct { env []string cmd *exec.Cmd + cmdFunc CommandFunc stdin io.WriteCloser stdout *bufio.Reader stderr io.ReadCloser @@ -31,6 +32,28 @@ type Stdio struct { done chan struct{} onNotification func(mcp.JSONRPCNotification) notifyMu sync.RWMutex + onRequest RequestHandler + requestMu sync.RWMutex + ctx context.Context + ctxMu sync.RWMutex +} + +// StdioOption defines a function that configures a Stdio transport instance. +// Options can be used to customize the behavior of the transport before it starts, +// such as setting a custom command function. +type StdioOption func(*Stdio) + +// CommandFunc is a factory function that returns a custom exec.Cmd used to launch the MCP subprocess. +// It can be used to apply sandboxing, custom environment control, working directories, etc. +type CommandFunc func(ctx context.Context, command string, env []string, args []string) (*exec.Cmd, error) + +// WithCommandFunc sets a custom command factory function for the stdio transport. +// The CommandFunc is responsible for constructing the exec.Cmd used to launch the subprocess, +// allowing control over attributes like environment, working directory, and system-level sandboxing. +func WithCommandFunc(f CommandFunc) StdioOption { + return func(s *Stdio) { + s.cmdFunc = f + } } // NewIO returns a new stdio-based transport using existing input, output, and @@ -44,6 +67,7 @@ func NewIO(input io.Reader, output io.WriteCloser, logging io.ReadCloser) *Stdio responses: make(map[string]chan *JSONRPCResponse), done: make(chan struct{}), + ctx: context.Background(), } } @@ -55,20 +79,43 @@ func NewStdio( env []string, args ...string, ) *Stdio { + return NewStdioWithOptions(command, env, args) +} - client := &Stdio{ +// NewStdioWithOptions creates a new stdio transport to communicate with a subprocess. +// It launches the specified command with given arguments and sets up stdin/stdout pipes for communication. +// Returns an error if the subprocess cannot be started or the pipes cannot be created. +// Optional configuration functions can be provided to customize the transport before it starts, +// such as setting a custom command factory. +func NewStdioWithOptions( + command string, + env []string, + args []string, + opts ...StdioOption, +) *Stdio { + s := &Stdio{ command: command, args: args, env: env, responses: make(map[string]chan *JSONRPCResponse), done: make(chan struct{}), + ctx: context.Background(), + } + + for _, opt := range opts { + opt(s) } - return client + return s } func (c *Stdio) Start(ctx context.Context) error { + // Store the context for use in request handling + c.ctxMu.Lock() + c.ctx = ctx + c.ctxMu.Unlock() + if err := c.spawnCommand(ctx); err != nil { return err } @@ -83,18 +130,25 @@ func (c *Stdio) Start(ctx context.Context) error { return nil } -// spawnCommand spawns a new process running c.command. +// spawnCommand spawns a new process running the configured command, args, and env. +// If an (optional) cmdFunc custom command factory function was configured, it will be used to construct the subprocess; +// otherwise, the default behavior uses exec.CommandContext with the merged environment. +// Initializes stdin, stdout, and stderr pipes for JSON-RPC communication. func (c *Stdio) spawnCommand(ctx context.Context) error { if c.command == "" { return nil } - cmd := exec.CommandContext(ctx, c.command, c.args...) - - mergedEnv := os.Environ() - mergedEnv = append(mergedEnv, c.env...) + var cmd *exec.Cmd + var err error - cmd.Env = mergedEnv + // Standard behavior if no command func present. + if c.cmdFunc == nil { + cmd = exec.CommandContext(ctx, c.command, c.args...) + cmd.Env = append(os.Environ(), c.env...) + } else if cmd, err = c.cmdFunc(ctx, c.command, c.env, c.args); err != nil { + return err + } stdin, err := cmd.StdinPipe() if err != nil { @@ -148,6 +202,12 @@ func (c *Stdio) Close() error { return nil } +// GetSessionId returns the session ID of the transport. +// Since stdio does not maintain a session ID, it returns an empty string. +func (c *Stdio) GetSessionId() string { + return "" +} + // SetNotificationHandler sets the handler function to be called when a notification is received. // Only one handler can be set at a time; setting a new one replaces the previous handler. func (c *Stdio) SetNotificationHandler( @@ -158,6 +218,14 @@ func (c *Stdio) SetNotificationHandler( c.onNotification = handler } +// SetRequestHandler sets the handler function to be called when a request is received from the server. +// This enables bidirectional communication for features like sampling. +func (c *Stdio) SetRequestHandler(handler RequestHandler) { + c.requestMu.Lock() + defer c.requestMu.Unlock() + c.onRequest = handler +} + // readResponses continuously reads and processes responses from the server's stdout. // It handles both responses to requests and notifications, routing them appropriately. // Runs until the done channel is closed or an error occurs reading from stdout. @@ -175,13 +243,18 @@ func (c *Stdio) readResponses() { return } - var baseMessage JSONRPCResponse + // First try to parse as a generic message to check for ID field + var baseMessage struct { + JSONRPC string `json:"jsonrpc"` + ID *mcp.RequestId `json:"id,omitempty"` + Method string `json:"method,omitempty"` + } if err := json.Unmarshal([]byte(line), &baseMessage); err != nil { continue } - // Handle notification - if baseMessage.ID.IsNil() { + // If it has a method but no ID, it's a notification + if baseMessage.Method != "" && baseMessage.ID == nil { var notification mcp.JSONRPCNotification if err := json.Unmarshal([]byte(line), ¬ification); err != nil { continue @@ -194,15 +267,30 @@ func (c *Stdio) readResponses() { continue } + // If it has a method and an ID, it's an incoming request + if baseMessage.Method != "" && baseMessage.ID != nil { + var request JSONRPCRequest + if err := json.Unmarshal([]byte(line), &request); err == nil { + c.handleIncomingRequest(request) + continue + } + } + + // Otherwise, it's a response to our request + var response JSONRPCResponse + if err := json.Unmarshal([]byte(line), &response); err != nil { + continue + } + // Create string key for map lookup - idKey := baseMessage.ID.String() + idKey := response.ID.String() c.mu.RLock() ch, exists := c.responses[idKey] c.mu.RUnlock() if exists { - ch <- &baseMessage + ch <- &response c.mu.Lock() delete(c.responses, idKey) c.mu.Unlock() @@ -281,6 +369,96 @@ func (c *Stdio) SendNotification( return nil } +// handleIncomingRequest processes incoming requests from the server. +// It calls the registered request handler and sends the response back to the server. +func (c *Stdio) handleIncomingRequest(request JSONRPCRequest) { + c.requestMu.RLock() + handler := c.onRequest + c.requestMu.RUnlock() + + if handler == nil { + // Send error response if no handler is configured + errorResponse := JSONRPCResponse{ + JSONRPC: mcp.JSONRPC_VERSION, + ID: request.ID, + Error: &struct { + Code int `json:"code"` + Message string `json:"message"` + Data json.RawMessage `json:"data"` + }{ + Code: mcp.METHOD_NOT_FOUND, + Message: "No request handler configured", + }, + } + c.sendResponse(errorResponse) + return + } + + // Handle the request in a goroutine to avoid blocking + go func() { + c.ctxMu.RLock() + ctx := c.ctx + c.ctxMu.RUnlock() + + // Check if context is already cancelled before processing + select { + case <-ctx.Done(): + errorResponse := JSONRPCResponse{ + JSONRPC: mcp.JSONRPC_VERSION, + ID: request.ID, + Error: &struct { + Code int `json:"code"` + Message string `json:"message"` + Data json.RawMessage `json:"data"` + }{ + Code: mcp.INTERNAL_ERROR, + Message: ctx.Err().Error(), + }, + } + c.sendResponse(errorResponse) + return + default: + } + + response, err := handler(ctx, request) + + if err != nil { + errorResponse := JSONRPCResponse{ + JSONRPC: mcp.JSONRPC_VERSION, + ID: request.ID, + Error: &struct { + Code int `json:"code"` + Message string `json:"message"` + Data json.RawMessage `json:"data"` + }{ + Code: mcp.INTERNAL_ERROR, + Message: err.Error(), + }, + } + c.sendResponse(errorResponse) + return + } + + if response != nil { + c.sendResponse(*response) + } + }() +} + +// sendResponse sends a response back to the server. +func (c *Stdio) sendResponse(response JSONRPCResponse) { + responseBytes, err := json.Marshal(response) + if err != nil { + fmt.Printf("Error marshaling response: %v\n", err) + return + } + responseBytes = append(responseBytes, '\n') + + if _, err := c.stdin.Write(responseBytes); err != nil { + fmt.Printf("Error writing response: %v\n", err) + } +} + // Stderr returns a reader for the stderr output of the subprocess. // This can be used to capture error messages or logs from the subprocess. func (c *Stdio) Stderr() io.Reader { diff --git a/vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go b/vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go index 50bde9c288d39e32e00bc5691cbaf75addd740f5..e358751b3344c3783be539cc5daa3e09ffa81020 100644 --- a/vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go +++ b/vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go @@ -17,10 +17,24 @@ import ( "time" "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/util" ) type StreamableHTTPCOption func(*StreamableHTTP) +// WithContinuousListening enables receiving server-to-client notifications when no request is in flight. +// In particular, if you want to receive global notifications from the server (like ToolListChangedNotification), +// you should enable this option. +// +// It will establish a standalone long-live GET HTTP connection to the server. +// https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#listening-for-messages-from-the-server +// NOTICE: Even enabled, the server may not support this feature. +func WithContinuousListening() StreamableHTTPCOption { + return func(sc *StreamableHTTP) { + sc.getListeningEnabled = true + } +} + // WithHTTPClient sets a custom HTTP client on the StreamableHTTP transport. func WithHTTPBasicClient(client *http.Client) StreamableHTTPCOption { return func(sc *StreamableHTTP) { @@ -54,6 +68,19 @@ func WithHTTPOAuth(config OAuthConfig) StreamableHTTPCOption { } } +func WithLogger(logger util.Logger) StreamableHTTPCOption { + return func(sc *StreamableHTTP) { + sc.logger = logger + } +} + +// WithSession creates a client with a pre-configured session +func WithSession(sessionID string) StreamableHTTPCOption { + return func(sc *StreamableHTTP) { + sc.sessionID.Store(sessionID) + } +} + // StreamableHTTP implements Streamable HTTP transport. // // It transmits JSON-RPC messages over individual HTTP requests. One message per request. @@ -64,19 +91,22 @@ func WithHTTPOAuth(config OAuthConfig) StreamableHTTPCOption { // // The current implementation does not support the following features: // - batching -// - continuously listening for server notifications when no request is in flight -// (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#listening-for-messages-from-the-server) // - resuming stream // (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#resumability-and-redelivery) // - server -> client request type StreamableHTTP struct { - serverURL *url.URL - httpClient *http.Client - headers map[string]string - headerFunc HTTPHeaderFunc + serverURL *url.URL + httpClient *http.Client + headers map[string]string + headerFunc HTTPHeaderFunc + logger util.Logger + getListeningEnabled bool sessionID atomic.Value // string + initialized chan struct{} + initializedOnce sync.Once + notificationHandler func(mcp.JSONRPCNotification) notifyMu sync.RWMutex @@ -95,15 +125,19 @@ func NewStreamableHTTP(serverURL string, options ...StreamableHTTPCOption) (*Str } smc := &StreamableHTTP{ - serverURL: parsedURL, - httpClient: &http.Client{}, - headers: make(map[string]string), - closed: make(chan struct{}), + serverURL: parsedURL, + httpClient: &http.Client{}, + headers: make(map[string]string), + closed: make(chan struct{}), + logger: util.DefaultLogger(), + initialized: make(chan struct{}), } smc.sessionID.Store("") // set initial value to simplify later usage for _, opt := range options { - opt(smc) + if opt != nil { + opt(smc) + } } // If OAuth is configured, set the base URL for metadata discovery @@ -118,7 +152,20 @@ func NewStreamableHTTP(serverURL string, options ...StreamableHTTPCOption) (*Str // Start initiates the HTTP connection to the server. func (c *StreamableHTTP) Start(ctx context.Context) error { - // For Streamable HTTP, we don't need to establish a persistent connection + // For Streamable HTTP, we don't need to establish a persistent connection by default + if c.getListeningEnabled { + go func() { + select { + case <-c.initialized: + ctx, cancel := c.contextAwareOfClientClose(ctx) + defer cancel() + c.listenForever(ctx) + case <-c.closed: + return + } + }() + } + return nil } @@ -142,13 +189,13 @@ func (c *StreamableHTTP) Close() error { defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodDelete, c.serverURL.String(), nil) if err != nil { - fmt.Printf("failed to create close request\n: %v", err) + c.logger.Errorf("failed to create close request: %v", err) return } req.Header.Set(headerKeySessionID, sessionId) res, err := c.httpClient.Do(req) if err != nil { - fmt.Printf("failed to send close request\n: %v", err) + c.logger.Errorf("failed to send close request: %v", err) return } res.Body.Close() @@ -185,77 +232,29 @@ func (c *StreamableHTTP) SendRequest( request JSONRPCRequest, ) (*JSONRPCResponse, error) { - // Create a combined context that could be canceled when the client is closed - newCtx, cancel := context.WithCancel(ctx) - defer cancel() - go func() { - select { - case <-c.closed: - cancel() - case <-newCtx.Done(): - // The original context was canceled, no need to do anything - } - }() - ctx = newCtx - // Marshal request requestBody, err := json.Marshal(request) if err != nil { return nil, fmt.Errorf("failed to marshal request: %w", err) } - // Create HTTP request - req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.serverURL.String(), bytes.NewReader(requestBody)) - if err != nil { - return nil, fmt.Errorf("failed to create request: %w", err) - } - - // Set headers - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json, text/event-stream") - sessionID := c.sessionID.Load() - if sessionID != "" { - req.Header.Set(headerKeySessionID, sessionID.(string)) - } - for k, v := range c.headers { - req.Header.Set(k, v) - } - - // Add OAuth authorization if configured - if c.oauthHandler != nil { - authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx) - if err != nil { - // If we get an authorization error, return a specific error that can be handled by the client - if err.Error() == "no valid token available, authorization required" { - return nil, &OAuthAuthorizationRequiredError{ - Handler: c.oauthHandler, - } - } - return nil, fmt.Errorf("failed to get authorization header: %w", err) - } - req.Header.Set("Authorization", authHeader) - } - - if c.headerFunc != nil { - for k, v := range c.headerFunc(ctx) { - req.Header.Set(k, v) - } - } + ctx, cancel := c.contextAwareOfClientClose(ctx) + defer cancel() - // Send request - resp, err := c.httpClient.Do(req) + resp, err := c.sendHTTP(ctx, http.MethodPost, bytes.NewReader(requestBody), "application/json, text/event-stream") if err != nil { - return nil, fmt.Errorf("failed to send request: %w", err) + if errors.Is(err, ErrSessionTerminated) && request.Method == string(mcp.MethodInitialize) { + // If the request is initialize, should not return a SessionTerminated error + // It should be a genuine endpoint-routing issue. + // ( Fall through to return StatusCode checking. ) + } else { + return nil, fmt.Errorf("failed to send request: %w", err) + } } defer resp.Body.Close() // Check if we got an error response if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { - // handle session closed - if resp.StatusCode == http.StatusNotFound { - c.sessionID.CompareAndSwap(sessionID, "") - return nil, fmt.Errorf("session terminated (404). need to re-initialize") - } // Handle OAuth unauthorized error if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil { @@ -279,6 +278,10 @@ func (c *StreamableHTTP) SendRequest( if sessionID := resp.Header.Get(headerKeySessionID); sessionID != "" { c.sessionID.Store(sessionID) } + + c.initializedOnce.Do(func() { + close(c.initialized) + }) } // Handle different response types @@ -300,16 +303,77 @@ func (c *StreamableHTTP) SendRequest( case "text/event-stream": // Server is using SSE for streaming responses - return c.handleSSEResponse(ctx, resp.Body) + return c.handleSSEResponse(ctx, resp.Body, false) default: return nil, fmt.Errorf("unexpected content type: %s", resp.Header.Get("Content-Type")) } } +func (c *StreamableHTTP) sendHTTP( + ctx context.Context, + method string, + body io.Reader, + acceptType string, +) (resp *http.Response, err error) { + + // Create HTTP request + req, err := http.NewRequestWithContext(ctx, method, c.serverURL.String(), body) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + // Set headers + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", acceptType) + sessionID := c.sessionID.Load().(string) + if sessionID != "" { + req.Header.Set(headerKeySessionID, sessionID) + } + for k, v := range c.headers { + req.Header.Set(k, v) + } + + // Add OAuth authorization if configured + if c.oauthHandler != nil { + authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx) + if err != nil { + // If we get an authorization error, return a specific error that can be handled by the client + if err.Error() == "no valid token available, authorization required" { + return nil, &OAuthAuthorizationRequiredError{ + Handler: c.oauthHandler, + } + } + return nil, fmt.Errorf("failed to get authorization header: %w", err) + } + req.Header.Set("Authorization", authHeader) + } + + if c.headerFunc != nil { + for k, v := range c.headerFunc(ctx) { + req.Header.Set(k, v) + } + } + + // Send request + resp, err = c.httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to send request: %w", err) + } + + // universal handling for session terminated + if resp.StatusCode == http.StatusNotFound { + c.sessionID.CompareAndSwap(sessionID, "") + return nil, ErrSessionTerminated + } + + return resp, nil +} + // handleSSEResponse processes an SSE stream for a specific request. // It returns the final result for the request once received, or an error. -func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCloser) (*JSONRPCResponse, error) { +// If ignoreResponse is true, it won't return when a response messge is received. This is for continuous listening. +func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCloser, ignoreResponse bool) (*JSONRPCResponse, error) { // Create a channel for this specific request responseChan := make(chan *JSONRPCResponse, 1) @@ -328,7 +392,7 @@ func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCl var message JSONRPCResponse if err := json.Unmarshal([]byte(data), &message); err != nil { - fmt.Printf("failed to unmarshal message: %v\n", err) + c.logger.Errorf("failed to unmarshal message: %v", err) return } @@ -336,7 +400,7 @@ func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCl if message.ID.IsNil() { var notification mcp.JSONRPCNotification if err := json.Unmarshal([]byte(data), ¬ification); err != nil { - fmt.Printf("failed to unmarshal notification: %v\n", err) + c.logger.Errorf("failed to unmarshal notification: %v", err) return } c.notifyMu.RLock() @@ -347,7 +411,9 @@ func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCl return } - responseChan <- &message + if !ignoreResponse { + responseChan <- &message + } }) }() @@ -393,7 +459,7 @@ func (c *StreamableHTTP) readSSE(ctx context.Context, reader io.ReadCloser, hand case <-ctx.Done(): return default: - fmt.Printf("SSE stream error: %v\n", err) + c.logger.Errorf("SSE stream error: %v", err) return } } @@ -432,44 +498,10 @@ func (c *StreamableHTTP) SendNotification(ctx context.Context, notification mcp. } // Create HTTP request - req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.serverURL.String(), bytes.NewReader(requestBody)) - if err != nil { - return fmt.Errorf("failed to create request: %w", err) - } - - // Set headers - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json, text/event-stream") - if sessionID := c.sessionID.Load(); sessionID != "" { - req.Header.Set(headerKeySessionID, sessionID.(string)) - } - for k, v := range c.headers { - req.Header.Set(k, v) - } - - // Add OAuth authorization if configured - if c.oauthHandler != nil { - authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx) - if err != nil { - // If we get an authorization error, return a specific error that can be handled by the client - if errors.Is(err, ErrOAuthAuthorizationRequired) { - return &OAuthAuthorizationRequiredError{ - Handler: c.oauthHandler, - } - } - return fmt.Errorf("failed to get authorization header: %w", err) - } - req.Header.Set("Authorization", authHeader) - } - - if c.headerFunc != nil { - for k, v := range c.headerFunc(ctx) { - req.Header.Set(k, v) - } - } + ctx, cancel := c.contextAwareOfClientClose(ctx) + defer cancel() - // Send request - resp, err := c.httpClient.Do(req) + resp, err := c.sendHTTP(ctx, http.MethodPost, bytes.NewReader(requestBody), "application/json, text/event-stream") if err != nil { return fmt.Errorf("failed to send request: %w", err) } @@ -513,3 +545,84 @@ func (c *StreamableHTTP) GetOAuthHandler() *OAuthHandler { func (c *StreamableHTTP) IsOAuthEnabled() bool { return c.oauthHandler != nil } + +func (c *StreamableHTTP) listenForever(ctx context.Context) { + c.logger.Infof("listening to server forever") + for { + err := c.createGETConnectionToServer(ctx) + if errors.Is(err, ErrGetMethodNotAllowed) { + // server does not support listening + c.logger.Errorf("server does not support listening") + return + } + + select { + case <-ctx.Done(): + return + default: + } + + if err != nil { + c.logger.Errorf("failed to listen to server. retry in 1 second: %v", err) + } + time.Sleep(retryInterval) + } +} + +var ( + ErrSessionTerminated = fmt.Errorf("session terminated (404). need to re-initialize") + ErrGetMethodNotAllowed = fmt.Errorf("GET method not allowed") + + retryInterval = 1 * time.Second // a variable is convenient for testing +) + +func (c *StreamableHTTP) createGETConnectionToServer(ctx context.Context) error { + + resp, err := c.sendHTTP(ctx, http.MethodGet, nil, "text/event-stream") + if err != nil { + return fmt.Errorf("failed to send request: %w", err) + } + defer resp.Body.Close() + + // Check if we got an error response + if resp.StatusCode == http.StatusMethodNotAllowed { + return ErrGetMethodNotAllowed + } + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("request failed with status %d: %s", resp.StatusCode, body) + } + + // handle SSE response + contentType := resp.Header.Get("Content-Type") + if contentType != "text/event-stream" { + return fmt.Errorf("unexpected content type: %s", contentType) + } + + // When ignoreResponse is true, the function will never return expect context is done. + // NOTICE: Due to the ambiguity of the specification, other SDKs may use the GET connection to transfer the response + // messages. To be more compatible, we should handle this response, however, as the transport layer is message-based, + // currently, there is no convenient way to handle this response. + // So we ignore the response here. It's not a bug, but may be not compatible with other SDKs. + _, err = c.handleSSEResponse(ctx, resp.Body, true) + if err != nil { + return fmt.Errorf("failed to handle SSE response: %w", err) + } + + return nil +} + +func (c *StreamableHTTP) contextAwareOfClientClose(ctx context.Context) (context.Context, context.CancelFunc) { + newCtx, cancel := context.WithCancel(ctx) + go func() { + select { + case <-c.closed: + cancel() + case <-newCtx.Done(): + // The original context was canceled + cancel() + } + }() + return newCtx, cancel +} diff --git a/vendor/github.com/mark3labs/mcp-go/mcp/tools.go b/vendor/github.com/mark3labs/mcp-go/mcp/tools.go index 5f3524b0212d12a89b14fd1e2f4b2e6ba4dbd806..3e3931b09c9aedfce1f6e58a80be180e107b3116 100644 --- a/vendor/github.com/mark3labs/mcp-go/mcp/tools.go +++ b/vendor/github.com/mark3labs/mcp-go/mcp/tools.go @@ -945,7 +945,20 @@ func PropertyNames(schema map[string]any) PropertyOption { } } -// Items defines the schema for array items +// Items defines the schema for array items. +// Accepts any schema definition for maximum flexibility. +// +// Example: +// +// Items(map[string]any{ +// "type": "object", +// "properties": map[string]any{ +// "name": map[string]any{"type": "string"}, +// "age": map[string]any{"type": "number"}, +// }, +// }) +// +// For simple types, use ItemsString(), ItemsNumber(), ItemsBoolean() instead. func Items(schema any) PropertyOption { return func(schemaMap map[string]any) { schemaMap["items"] = schema @@ -972,3 +985,94 @@ func UniqueItems(unique bool) PropertyOption { schema["uniqueItems"] = unique } } + +// WithStringItems configures an array's items to be of type string. +// +// Supported options: Description(), DefaultString(), Enum(), MaxLength(), MinLength(), Pattern() +// Note: Options like Required() are not valid for item schemas and will be ignored. +// +// Examples: +// +// mcp.WithArray("tags", mcp.WithStringItems()) +// mcp.WithArray("colors", mcp.WithStringItems(mcp.Enum("red", "green", "blue"))) +// mcp.WithArray("names", mcp.WithStringItems(mcp.MinLength(1), mcp.MaxLength(50))) +// +// Limitations: Only supports simple string arrays. Use Items() for complex objects. +func WithStringItems(opts ...PropertyOption) PropertyOption { + return func(schema map[string]any) { + itemSchema := map[string]any{ + "type": "string", + } + + for _, opt := range opts { + opt(itemSchema) + } + + schema["items"] = itemSchema + } +} + +// WithStringEnumItems configures an array's items to be of type string with a specified enum. +// Example: +// +// mcp.WithArray("priority", mcp.WithStringEnumItems([]string{"low", "medium", "high"})) +// +// Limitations: Only supports string enums. Use WithStringItems(Enum(...)) for more flexibility. +func WithStringEnumItems(values []string) PropertyOption { + return func(schema map[string]any) { + schema["items"] = map[string]any{ + "type": "string", + "enum": values, + } + } +} + +// WithNumberItems configures an array's items to be of type number. +// +// Supported options: Description(), DefaultNumber(), Min(), Max(), MultipleOf() +// Note: Options like Required() are not valid for item schemas and will be ignored. +// +// Examples: +// +// mcp.WithArray("scores", mcp.WithNumberItems(mcp.Min(0), mcp.Max(100))) +// mcp.WithArray("prices", mcp.WithNumberItems(mcp.Min(0))) +// +// Limitations: Only supports simple number arrays. Use Items() for complex objects. +func WithNumberItems(opts ...PropertyOption) PropertyOption { + return func(schema map[string]any) { + itemSchema := map[string]any{ + "type": "number", + } + + for _, opt := range opts { + opt(itemSchema) + } + + schema["items"] = itemSchema + } +} + +// WithBooleanItems configures an array's items to be of type boolean. +// +// Supported options: Description(), DefaultBool() +// Note: Options like Required() are not valid for item schemas and will be ignored. +// +// Examples: +// +// mcp.WithArray("flags", mcp.WithBooleanItems()) +// mcp.WithArray("permissions", mcp.WithBooleanItems(mcp.Description("User permissions"))) +// +// Limitations: Only supports simple boolean arrays. Use Items() for complex objects. +func WithBooleanItems(opts ...PropertyOption) PropertyOption { + return func(schema map[string]any) { + itemSchema := map[string]any{ + "type": "boolean", + } + + for _, opt := range opts { + opt(itemSchema) + } + + schema["items"] = itemSchema + } +} diff --git a/vendor/github.com/mark3labs/mcp-go/mcp/types.go b/vendor/github.com/mark3labs/mcp-go/mcp/types.go index 0091d2e42d380253ee03d0d1b5cde8597775be8f..241b55ce9b549941d764a2ca5b4ba11e551d301d 100644 --- a/vendor/github.com/mark3labs/mcp-go/mcp/types.go +++ b/vendor/github.com/mark3labs/mcp-go/mcp/types.go @@ -763,6 +763,11 @@ const ( /* Sampling */ +const ( + // MethodSamplingCreateMessage allows servers to request LLM completions from clients + MethodSamplingCreateMessage MCPMethod = "sampling/createMessage" +) + // CreateMessageRequest is a request from the server to sample an LLM via the // client. The client has full discretion over which model to select. The client // should also inform the user before beginning sampling, to allow them to inspect @@ -865,6 +870,22 @@ type AudioContent struct { func (AudioContent) isContent() {} +// ResourceLink represents a link to a resource that the client can access. +type ResourceLink struct { + Annotated + Type string `json:"type"` // Must be "resource_link" + // The URI of the resource. + URI string `json:"uri"` + // The name of the resource. + Name string `json:"name"` + // The description of the resource. + Description string `json:"description"` + // The MIME type of the resource. + MIMEType string `json:"mimeType"` +} + +func (ResourceLink) isContent() {} + // EmbeddedResource represents the contents of a resource, embedded into a prompt or tool call result. // // It is up to the client how best to render embedded resources for the diff --git a/vendor/github.com/mark3labs/mcp-go/mcp/utils.go b/vendor/github.com/mark3labs/mcp-go/mcp/utils.go index 55bef7a997e2a406f111b2fb399812ca1941ab96..3e652efd7e842d24bc6ab13fa119d21f272a8ba7 100644 --- a/vendor/github.com/mark3labs/mcp-go/mcp/utils.go +++ b/vendor/github.com/mark3labs/mcp-go/mcp/utils.go @@ -222,6 +222,17 @@ func NewAudioContent(data, mimeType string) AudioContent { } } +// Helper function to create a new ResourceLink +func NewResourceLink(uri, name, description, mimeType string) ResourceLink { + return ResourceLink{ + Type: "resource_link", + URI: uri, + Name: name, + Description: description, + MIMEType: mimeType, + } +} + // Helper function to create a new EmbeddedResource func NewEmbeddedResource(resource ResourceContents) EmbeddedResource { return EmbeddedResource{ @@ -476,6 +487,16 @@ func ParseContent(contentMap map[string]any) (Content, error) { } return NewAudioContent(data, mimeType), nil + case "resource_link": + uri := ExtractString(contentMap, "uri") + name := ExtractString(contentMap, "name") + description := ExtractString(contentMap, "description") + mimeType := ExtractString(contentMap, "mimeType") + if uri == "" || name == "" { + return nil, fmt.Errorf("resource_link uri or name is missing") + } + return NewResourceLink(uri, name, description, mimeType), nil + case "resource": resourceMap := ExtractMap(contentMap, "resource") if resourceMap == nil { diff --git a/vendor/github.com/mark3labs/mcp-go/server/sampling.go b/vendor/github.com/mark3labs/mcp-go/server/sampling.go new file mode 100644 index 0000000000000000000000000000000000000000..b633b24d07ebfeeedd9b49468d7aadb411c87b4c --- /dev/null +++ b/vendor/github.com/mark3labs/mcp-go/server/sampling.go @@ -0,0 +1,37 @@ +package server + +import ( + "context" + "fmt" + + "github.com/mark3labs/mcp-go/mcp" +) + +// EnableSampling enables sampling capabilities for the server. +// This allows the server to send sampling requests to clients that support it. +func (s *MCPServer) EnableSampling() { + s.capabilitiesMu.Lock() + defer s.capabilitiesMu.Unlock() +} + +// RequestSampling sends a sampling request to the client. +// The client must have declared sampling capability during initialization. +func (s *MCPServer) RequestSampling(ctx context.Context, request mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) { + session := ClientSessionFromContext(ctx) + if session == nil { + return nil, fmt.Errorf("no active session") + } + + // Check if the session supports sampling requests + if samplingSession, ok := session.(SessionWithSampling); ok { + return samplingSession.RequestSampling(ctx, request) + } + + return nil, fmt.Errorf("session does not support sampling") +} + +// SessionWithSampling extends ClientSession to support sampling requests. +type SessionWithSampling interface { + ClientSession + RequestSampling(ctx context.Context, request mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) +} diff --git a/vendor/github.com/mark3labs/mcp-go/server/stdio.go b/vendor/github.com/mark3labs/mcp-go/server/stdio.go index 746a7d96f6c3635ec05c6bc2d7b92820824a8e20..33ac9bb8854527db09ea31a0be4d109521fa0c37 100644 --- a/vendor/github.com/mark3labs/mcp-go/server/stdio.go +++ b/vendor/github.com/mark3labs/mcp-go/server/stdio.go @@ -9,6 +9,7 @@ import ( "log" "os" "os/signal" + "sync" "sync/atomic" "syscall" @@ -51,10 +52,21 @@ func WithStdioContextFunc(fn StdioContextFunc) StdioOption { // stdioSession is a static client session, since stdio has only one client. type stdioSession struct { - notifications chan mcp.JSONRPCNotification - initialized atomic.Bool - loggingLevel atomic.Value - clientInfo atomic.Value // stores session-specific client info + notifications chan mcp.JSONRPCNotification + initialized atomic.Bool + loggingLevel atomic.Value + clientInfo atomic.Value // stores session-specific client info + writer io.Writer // for sending requests to client + requestID atomic.Int64 // for generating unique request IDs + mu sync.RWMutex // protects writer + pendingRequests map[int64]chan *samplingResponse // for tracking pending sampling requests + pendingMu sync.RWMutex // protects pendingRequests +} + +// samplingResponse represents a response to a sampling request +type samplingResponse struct { + result *mcp.CreateMessageResult + err error } func (s *stdioSession) SessionID() string { @@ -100,14 +112,86 @@ func (s *stdioSession) GetLogLevel() mcp.LoggingLevel { return level.(mcp.LoggingLevel) } +// RequestSampling sends a sampling request to the client and waits for the response. +func (s *stdioSession) RequestSampling(ctx context.Context, request mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) { + s.mu.RLock() + writer := s.writer + s.mu.RUnlock() + + if writer == nil { + return nil, fmt.Errorf("no writer available for sending requests") + } + + // Generate a unique request ID + id := s.requestID.Add(1) + + // Create a response channel for this request + responseChan := make(chan *samplingResponse, 1) + s.pendingMu.Lock() + s.pendingRequests[id] = responseChan + s.pendingMu.Unlock() + + // Cleanup function to remove the pending request + cleanup := func() { + s.pendingMu.Lock() + delete(s.pendingRequests, id) + s.pendingMu.Unlock() + } + defer cleanup() + + // Create the JSON-RPC request + jsonRPCRequest := struct { + JSONRPC string `json:"jsonrpc"` + ID int64 `json:"id"` + Method string `json:"method"` + Params mcp.CreateMessageParams `json:"params"` + }{ + JSONRPC: mcp.JSONRPC_VERSION, + ID: id, + Method: string(mcp.MethodSamplingCreateMessage), + Params: request.CreateMessageParams, + } + + // Marshal and send the request + requestBytes, err := json.Marshal(jsonRPCRequest) + if err != nil { + return nil, fmt.Errorf("failed to marshal sampling request: %w", err) + } + requestBytes = append(requestBytes, '\n') + + if _, err := writer.Write(requestBytes); err != nil { + return nil, fmt.Errorf("failed to write sampling request: %w", err) + } + + // Wait for the response or context cancellation + select { + case <-ctx.Done(): + return nil, ctx.Err() + case response := <-responseChan: + if response.err != nil { + return nil, response.err + } + return response.result, nil + } +} + +// SetWriter sets the writer for sending requests to the client. +func (s *stdioSession) SetWriter(writer io.Writer) { + s.mu.Lock() + defer s.mu.Unlock() + s.writer = writer +} + var ( _ ClientSession = (*stdioSession)(nil) _ SessionWithLogging = (*stdioSession)(nil) _ SessionWithClientInfo = (*stdioSession)(nil) + _ SessionWithSampling = (*stdioSession)(nil) ) var stdioSessionInstance = stdioSession{ - notifications: make(chan mcp.JSONRPCNotification, 100), + notifications: make(chan mcp.JSONRPCNotification, 100), + pendingRequests: make(map[int64]chan *samplingResponse), } // NewStdioServer creates a new stdio server wrapper around an MCPServer. @@ -224,6 +308,9 @@ func (s *StdioServer) Listen( defer s.server.UnregisterSession(ctx, stdioSessionInstance.SessionID()) ctx = s.server.WithContext(ctx, &stdioSessionInstance) + // Set the writer for sending requests to the client + stdioSessionInstance.SetWriter(stdout) + // Add in any custom context. if s.contextFunc != nil { ctx = s.contextFunc(ctx) @@ -256,7 +343,29 @@ func (s *StdioServer) processMessage( return s.writeResponse(response, writer) } - // Handle the message using the wrapped server + // Check if this is a response to a sampling request + if s.handleSamplingResponse(rawMessage) { + return nil + } + + // Check if this is a tool call that might need sampling (and thus should be processed concurrently) + var baseMessage struct { + Method string `json:"method"` + } + if json.Unmarshal(rawMessage, &baseMessage) == nil && baseMessage.Method == "tools/call" { + // Process tool calls concurrently to avoid blocking on sampling requests + go func() { + response := s.server.HandleMessage(ctx, rawMessage) + if response != nil { + if err := s.writeResponse(response, writer); err != nil { + s.errLogger.Printf("Error writing tool response: %v", err) + } + } + }() + return nil + } + + // Handle other messages synchronously response := s.server.HandleMessage(ctx, rawMessage) // Only write response if there is one (not for notifications) @@ -269,6 +378,65 @@ func (s *StdioServer) processMessage( return nil } +// handleSamplingResponse checks if the message is a response to a sampling request +// and routes it to the appropriate pending request channel. +func (s *StdioServer) handleSamplingResponse(rawMessage json.RawMessage) bool { + return stdioSessionInstance.handleSamplingResponse(rawMessage) +} + +// handleSamplingResponse handles incoming sampling responses for this session +func (s *stdioSession) handleSamplingResponse(rawMessage json.RawMessage) bool { + // Try to parse as a JSON-RPC response + var response struct { + JSONRPC string `json:"jsonrpc"` + ID json.Number `json:"id"` + Result json.RawMessage `json:"result,omitempty"` + Error *struct { + Code int `json:"code"` + Message string `json:"message"` + } `json:"error,omitempty"` + } + + if err := json.Unmarshal(rawMessage, &response); err != nil { + return false + } + // Parse the ID as int64 + idInt64, err := response.ID.Int64() + if err != nil || (response.Result == nil && response.Error == nil) { + return false + } + + // Look for a pending request with this ID + s.pendingMu.RLock() + responseChan, exists := s.pendingRequests[idInt64] + s.pendingMu.RUnlock() + + if !exists { + return false + } // Parse and send the response + samplingResp := &samplingResponse{} + + if response.Error != nil { + samplingResp.err = fmt.Errorf("sampling request failed: %s", response.Error.Message) + } else { + var result mcp.CreateMessageResult + if err := json.Unmarshal(response.Result, &result); err != nil { + samplingResp.err = fmt.Errorf("failed to unmarshal sampling response: %w", err) + } else { + samplingResp.result = &result + } + } + + // Send the response (non-blocking) + select { + case responseChan <- samplingResp: + default: + // Channel is full or closed, ignore + } + + return true +} + // writeResponse marshals and writes a JSON-RPC response message followed by a newline. // Returns an error if marshaling or writing fails. func (s *StdioServer) writeResponse( diff --git a/vendor/github.com/mark3labs/mcp-go/server/streamable_http.go b/vendor/github.com/mark3labs/mcp-go/server/streamable_http.go index e9a011fb1c31b46771e3baeffe666ef9a71ef1a1..1312c9753a5ddc2d37a2d3c9f6266cc80d517e2e 100644 --- a/vendor/github.com/mark3labs/mcp-go/server/streamable_http.go +++ b/vendor/github.com/mark3labs/mcp-go/server/streamable_http.go @@ -40,7 +40,9 @@ func WithEndpointPath(endpointPath string) StreamableHTTPOption { // to StatelessSessionIdManager. func WithStateLess(stateLess bool) StreamableHTTPOption { return func(s *StreamableHTTPServer) { - s.sessionIdManager = &StatelessSessionIdManager{} + if stateLess { + s.sessionIdManager = &StatelessSessionIdManager{} + } } } @@ -374,7 +376,7 @@ func (s *StreamableHTTPServer) handleGet(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") - w.WriteHeader(http.StatusAccepted) + w.WriteHeader(http.StatusOK) flusher, ok := w.(http.Flusher) if !ok { diff --git a/vendor/modules.txt b/vendor/modules.txt index e256e639e4098adadaf25a32fa4a05937e2066d7..ebdc8318f987500b38cb989a7a0de6bea45caf5f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -242,7 +242,7 @@ github.com/bmatcuk/doublestar/v4 github.com/charlievieth/fastwalk github.com/charlievieth/fastwalk/internal/dirent github.com/charlievieth/fastwalk/internal/fmtdirent -# github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250607113720-eb5e1cf3b09e +# github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250710161907-a4c42b579198 ## explicit; go 1.23.0 github.com/charmbracelet/bubbles/v2/cursor github.com/charmbracelet/bubbles/v2/filepicker @@ -254,14 +254,14 @@ github.com/charmbracelet/bubbles/v2/spinner github.com/charmbracelet/bubbles/v2/textarea github.com/charmbracelet/bubbles/v2/textinput github.com/charmbracelet/bubbles/v2/viewport -# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891 -## explicit; go 1.24.3 +# github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.1 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595 +## explicit; go 1.24.0 github.com/charmbracelet/bubbletea/v2 # github.com/charmbracelet/colorprofile v0.3.1 ## explicit; go 1.23.0 github.com/charmbracelet/colorprofile -# github.com/charmbracelet/fang v0.1.0 -## explicit; go 1.23.0 +# github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674 +## explicit; go 1.24.0 github.com/charmbracelet/fang # github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe ## explicit; go 1.23.0 @@ -269,7 +269,7 @@ github.com/charmbracelet/glamour/v2 github.com/charmbracelet/glamour/v2/ansi github.com/charmbracelet/glamour/v2/internal/autolink github.com/charmbracelet/glamour/v2/styles -# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.2.0.20250703152125-8e1c474f8a71 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093 +# github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb ## explicit; go 1.24.2 github.com/charmbracelet/lipgloss/v2 github.com/charmbracelet/lipgloss/v2/table @@ -288,7 +288,7 @@ github.com/charmbracelet/x/ansi/parser # github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa ## explicit; go 1.23.0 github.com/charmbracelet/x/cellbuf -# github.com/charmbracelet/x/exp/charmtone v0.0.0-20250627134340-c144409e381c +# github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 ## explicit; go 1.23.0 github.com/charmbracelet/x/exp/charmtone # github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a @@ -403,7 +403,7 @@ github.com/kylelemons/godebug/pretty # github.com/lucasb-eyer/go-colorful v1.2.0 ## explicit; go 1.12 github.com/lucasb-eyer/go-colorful -# github.com/mark3labs/mcp-go v0.32.0 +# github.com/mark3labs/mcp-go v0.33.0 ## explicit; go 1.23 github.com/mark3labs/mcp-go/client github.com/mark3labs/mcp-go/client/transport @@ -838,5 +838,5 @@ mvdan.cc/sh/v3/fileutil mvdan.cc/sh/v3/interp mvdan.cc/sh/v3/pattern mvdan.cc/sh/v3/syntax -# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250708152737-144080f3d891 -# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250708152830-0fa4ef151093 +# github.com/charmbracelet/bubbletea/v2 => github.com/charmbracelet/bubbletea-internal/v2 v2.0.0-20250710185017-3c0ffd25e595 +# github.com/charmbracelet/lipgloss/v2 => github.com/charmbracelet/lipgloss-internal/v2 v2.0.0-20250710185058-03664cb9cecb