nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: charmbracelet/bubbletea
Pull request #721 (2023-04-17 14:40:13)

feat: allow to disable signals
Extracted from #352

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>


Patch:
diff --git a/options.go b/options.go
index 17d05ba..7a63c67 100644
--- a/options.go
+++ b/options.go
@@ -28,7 +28,11 @@ func WithContext(ctx context.Context) ProgramOption {
 // won't need to use this.
 func WithOutput(output io.Writer) ProgramOption {
 	return func(p *Program) {
-		p.output = termenv.NewOutput(output, termenv.WithColorCache(true))
+		if o, ok := output.(*termenv.Output); ok {
+			p.output = o
+		} else {
+			p.output = termenv.NewOutput(output, termenv.WithColorCache(true))
+		}
 	}
 }
 
@@ -66,6 +70,14 @@ func WithoutCatchPanics() ProgramOption {
 	}
 }
 
+// WithoutSignals will ignore OS signals.
+// This is mainly useful for testing.
+func WithoutSignals() ProgramOption {
+	return func(p *Program) {
+		p.ignoreSignals = true
+	}
+}
+
 // WithAltScreen starts the program with the alternate screen buffer enabled
 // (i.e. the program starts in full window mode). Note that the altscreen will
 // be automatically exited when the program quits.
diff --git a/tea.go b/tea.go
index f5ae4e9..e61bb5a 100644
--- a/tea.go
+++ b/tea.go
@@ -97,8 +97,9 @@ type Program struct {
 	ctx    context.Context
 	cancel context.CancelFunc
 
-	msgs chan Msg
-	errs chan error
+	msgs     chan Msg
+	errs     chan error
+	finished chan struct{}
 
 	// where to send output, this will usually be os.Stdout.
 	output        *termenv.Output
@@ -366,6 +367,7 @@ func (p *Program) Run() (Model, error) {
 	handlers := handlers{}
 	cmds := make(chan Cmd)
 	p.errs = make(chan error)
+	p.finished = make(chan struct{}, 1)
 
 	defer p.cancel()
 
@@ -555,6 +557,11 @@ func (p *Program) Kill() {
 	p.cancel()
 }
 
+// Wait waits/blocks until the underlying Program finished shutting down.
+func (p *Program) Wait() {
+	<-p.finished
+}
+
 // shutdown performs operations to free up resources and restore the terminal
 // to its original state.
 func (p *Program) shutdown(kill bool) {
@@ -570,6 +577,7 @@ func (p *Program) shutdown(kill bool) {
 	if p.restoreOutput != nil {
 		_ = p.restoreOutput()
 	}
+	p.finished <- struct{}{}
 }
 
 // ReleaseTerminal restores the original terminal state and cancels the input


Test patch:
diff --git a/options_test.go b/options_test.go
index 71a3c6c..a66483d 100644
--- a/options_test.go
+++ b/options_test.go
@@ -35,6 +35,13 @@ func TestOptions(t *testing.T) {
 		}
 	})
 
+	t.Run("without signals", func(t *testing.T) {
+		p := NewProgram(nil, WithoutSignals())
+		if !p.ignoreSignals {
+			t.Errorf("ignore signals should have been set")
+		}
+	})
+
 	t.Run("filter", func(t *testing.T) {
 		p := NewProgram(nil, WithFilter(func(_ Model, msg Msg) Msg { return msg }))
 		if p.filter == nil {