nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: charmbracelet/bubbletea
Pull request #1314 (2025-02-06 18:40:07)

feat: add WithWindowSize option to set the initial window size
This adds a new option to set the initial window size of the terminal window. This is useful in testing and required for teatest/v2 after the changes in the renderer. The cell-based cursed renderer heavily relies on the terminal size, and it's important to have a way to set the size manually for tests to run in a non-interactive environment.


Patch:
diff --git a/options.go b/options.go
index f63abd5..41e7a44 100644
--- a/options.go
+++ b/options.go
@@ -295,3 +295,14 @@ func WithColorProfile(profile colorprofile.Profile) ProgramOption {
 		p.profile = profile
 	}
 }
+
+// WithWindowSize sets the initial size of the terminal window. This is useful
+// when you need to set the initial size of the terminal window, for example
+// during testing or when you want to run your program in a non-interactive
+// environment.
+func WithWindowSize(width, height int) ProgramOption {
+	return func(p *Program) {
+		p.width = width
+		p.height = height
+	}
+}


Test patch:
diff --git a/screen_test.go b/screen_test.go
index 4af55d6..d4f61c8 100644
--- a/screen_test.go
+++ b/screen_test.go
@@ -94,10 +94,9 @@ func TestClearMsg(t *testing.T) {
 					"TERM=xterm-256color", // always use xterm and 256 colors for tests
 				}),
 				// Use ANSI256 to increase test coverage.
-				WithColorProfile(colorprofile.ANSI256))
-
-			// Set the initial window size for the program.
-			p.width, p.height = 80, 24
+				WithColorProfile(colorprofile.ANSI256),
+				// Set the initial window size for the program.
+				WithWindowSize(80, 24))
 
 			go p.Send(append(test.cmds, Quit))
Repository: charmbracelet/bubbletea
Pull request #496 (2022-10-07 12:49:40)

fix(key): recover the insert key
We started supporting insert in #418, but then accidentally removed it during a rebase in #396. Oops.

:facepalm: 

cc @muesli @meowgorithm 

muesli: Well this is embarrassing, I reviewed/rebased this as carefully as possible 🙈 Thanks @knz!

Patch:
diff --git a/key.go b/key.go
index 8a27702..444fc57 100644
--- a/key.go
+++ b/key.go
@@ -390,6 +390,10 @@ var sequences = map[string]Key{
 	// Miscellaneous keys
 	"\x1b[Z": {Type: KeyShiftTab},
 
+	"\x1b[2~":     {Type: KeyInsert},
+	"\x1b[3;2~":   {Type: KeyInsert, Alt: true},
+	"\x1b\x1b[2~": {Type: KeyInsert, Alt: true}, // urxvt
+
 	"\x1b[3~":     {Type: KeyDelete},
 	"\x1b[3;3~":   {Type: KeyDelete, Alt: true},
 	"\x1b\x1b[3~": {Type: KeyDelete, Alt: true}, // urxvt


Test patch:
diff --git a/key_test.go b/key_test.go
index c119cda..07c2743 100644
--- a/key_test.go
+++ b/key_test.go
@@ -145,6 +145,14 @@ func TestReadInput(t *testing.T) {
 				},
 			},
 		},
+		{"insert",
+			[]byte{'\x1b', '[', '2', '~'},
+			[]Msg{
+				KeyMsg{
+					Type: KeyInsert,
+				},
+			},
+		},
 		{"alt+ctrl+a",
 			[]byte{'\x1b', byte(keySOH)},
 			[]Msg{
Repository: charmbracelet/bubbletea
Pull request #503 (2022-10-07 18:29:55)

feat: make signal handler optional
You can now initialize a tea app without a signal handler:

p := NewProgram(model, WithoutSignalHandler())


Patch:
diff --git a/options.go b/options.go
index 6ede540..3aad18c 100644
--- a/options.go
+++ b/options.go
@@ -38,6 +38,14 @@ func WithInputTTY() ProgramOption {
 	}
 }
 
+// WithoutSignalHandler disables the signal handler that Bubble Tea sets up for
+// Programs. This is useful if you want to handle signals yourself.
+func WithoutSignalHandler() ProgramOption {
+	return func(p *Program) {
+		p.startupOptions |= withoutSignalHandler
+	}
+}
+
 // WithoutCatchPanics disables the panic catching that Bubble Tea does by
 // default. If panic catching is disabled the terminal will be in a fairly
 // unusable state after a panic because Bubble Tea will not perform its usual
diff --git a/tea.go b/tea.go
index 52bd09b..82afda5 100644
--- a/tea.go
+++ b/tea.go
@@ -71,6 +71,7 @@ const (
 	withInputTTY
 	withCustomInput
 	withANSICompressor
+	withoutSignalHandler
 )
 
 // Program is a terminal user interface.
@@ -375,7 +376,12 @@ func (p *Program) StartReturningModel() (Model, error) {
 	}
 
 	// Handle signals.
-	sigintLoopDone := p.handleSignals()
+	sigintLoopDone := make(chan struct{})
+	if !p.startupOptions.has(withoutSignalHandler) {
+		sigintLoopDone = p.handleSignals()
+	} else {
+		close(sigintLoopDone)
+	}
 
 	if p.CatchPanics {
 		defer func() {


Test patch:
diff --git a/options_test.go b/options_test.go
index 6648ddd..ba44410 100644
--- a/options_test.go
+++ b/options_test.go
@@ -62,6 +62,10 @@ func TestOptions(t *testing.T) {
 			exercise(t, WithANSICompressor(), withANSICompressor)
 		})
 
+		t.Run("without signal handler", func(t *testing.T) {
+			exercise(t, WithoutSignalHandler(), withoutSignalHandler)
+		})
+
 		t.Run("mouse cell motion", func(t *testing.T) {
 			p := NewProgram(nil, WithMouseAllMotion(), WithMouseCellMotion())
 			if !p.startupOptions.has(withMouseCellMotion) {
Repository: charmbracelet/bubbletea
Pull request #571 (2022-10-23 01:46:06)

feat: tea.WithContext ProgramOption to supply a context
WithContext lets you specify a context in which to run the Program. This is useful if you want to cancel the execution from outside. When a Program gets cancelled it will exit with an error ErrProgramKilled.


Patch:
diff --git a/options.go b/options.go
index 59d0685..d9ce42c 100644
--- a/options.go
+++ b/options.go
@@ -1,6 +1,7 @@
 package tea
 
 import (
+	"context"
 	"io"
 
 	"github.com/muesli/termenv"
@@ -14,6 +15,15 @@ import (
 //	p := NewProgram(model, WithInput(someInput), WithOutput(someOutput))
 type ProgramOption func(*Program)
 
+// WithContext lets you specify a context in which to run the Program. This is
+// useful if you want to cancel the execution from outside. When a Program gets
+// cancelled it will exit with an error ErrProgramKilled.
+func WithContext(ctx context.Context) ProgramOption {
+	return func(p *Program) {
+		p.ctx = ctx
+	}
+}
+
 // WithOutput sets the output which, by default, is stdout. In most cases you
 // won't need to use this.
 func WithOutput(output io.Writer) ProgramOption {
diff --git a/tea.go b/tea.go
index d2c19ff..6736d6a 100644
--- a/tea.go
+++ b/tea.go
@@ -141,8 +141,14 @@ func NewProgram(model Model, opts ...ProgramOption) *Program {
 		msgs:         make(chan Msg),
 	}
 
+	// A context can be provided with a ProgramOption, but if none was provided
+	// we'll use the default background context.
+	if p.ctx == nil {
+		p.ctx = context.Background()
+	}
+
 	// Initialize context and teardown channel.
-	p.ctx, p.cancel = context.WithCancel(context.Background())
+	p.ctx, p.cancel = context.WithCancel(p.ctx)
 
 	// Apply all options to the program.
 	for _, opt := range opts {


Test patch:
diff --git a/tea_test.go b/tea_test.go
index 6140677..142f42d 100644
--- a/tea_test.go
+++ b/tea_test.go
@@ -2,6 +2,7 @@ package tea
 
 import (
 	"bytes"
+	"context"
 	"sync/atomic"
 	"testing"
 	"time"
@@ -97,6 +98,28 @@ func TestTeaKill(t *testing.T) {
 	}
 }
 
+func TestTeaContext(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	var buf bytes.Buffer
+	var in bytes.Buffer
+
+	m := &testModel{}
+	p := NewProgram(m, WithContext(ctx), WithInput(&in), WithOutput(&buf))
+	go func() {
+		for {
+			time.Sleep(time.Millisecond)
+			if m.executed.Load() != nil {
+				cancel()
+				return
+			}
+		}
+	}()
+
+	if _, err := p.Run(); err != ErrProgramKilled {
+		t.Fatalf("Expected %v, got %v", ErrProgramKilled, err)
+	}
+}
+
 func TestTeaBatchMsg(t *testing.T) {
 	var buf bytes.Buffer
 	var in bytes.Buffer