nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: charmbracelet/bubbletea
Pull request #46 (2021-01-17 15:11:58)

Add a tea.Sequentially command
The idea is to produce a single command that sequentially runs the given commands, returning the first non-nil msg.

Useful for things like saving the current state before quitting, or saving something and then refreshing a list...

Extracted from: https://github.com/caarlos0/tasktimer


Patch:
diff --git a/commands.go b/commands.go
index 117f7a6..5a4d3f0 100644
--- a/commands.go
+++ b/commands.go
@@ -51,3 +51,27 @@ func Tick(d time.Duration, fn func(time.Time) Msg) Cmd {
 		return fn(<-t.C)
 	}
 }
+
+// Sequentially produces a command that sequentially executes the given
+// commands.
+// The Msg returned is the first non-nil message returned by a Cmd.
+//
+//   func saveStateCmd() Msg {
+//   	if err := save(); err != nil {
+//    		return errMsg{err}
+//    	}
+//   	return nil
+//   }
+//
+//   cmd := Sequentially(saveStateCmd, Quit)
+//
+func Sequentially(cmds ...Cmd) Cmd {
+	return func() Msg {
+		for _, cmd := range cmds {
+			if msg := cmd(); msg != nil {
+				return msg
+			}
+		}
+		return nil
+	}
+}


Test patch:
diff --git a/commands_test.go b/commands_test.go
new file mode 100644
index 0000000..2a11fbc
--- /dev/null
+++ b/commands_test.go
@@ -0,0 +1,56 @@
+package tea
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestSequentially(t *testing.T) {
+	var expectedErrMsg = fmt.Errorf("some err")
+	var expectedStrMsg = "some msg"
+
+	var nilReturnCmd = func() Msg {
+		return nil
+	}
+
+	tests := []struct {
+		name     string
+		cmds     []Cmd
+		expected Msg
+	}{
+		{
+			name:     "all nil",
+			cmds:     []Cmd{nilReturnCmd, nilReturnCmd},
+			expected: nil,
+		},
+		{
+			name: "one error",
+			cmds: []Cmd{
+				nilReturnCmd,
+				func() Msg {
+					return expectedErrMsg
+				},
+				nilReturnCmd,
+			},
+			expected: expectedErrMsg,
+		},
+		{
+			name: "some msg",
+			cmds: []Cmd{
+				nilReturnCmd,
+				func() Msg {
+					return expectedStrMsg
+				},
+				nilReturnCmd,
+			},
+			expected: expectedStrMsg,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			if msg := Sequentially(test.cmds...)(); msg != test.expected {
+				t.Fatalf("expected a msg %v but got %v", test.expected, msg)
+			}
+		})
+	}
+}
Repository: charmbracelet/bubbletea
Pull request #217 (2022-02-03 13:54:10)

feat: tea.Batch returns nil if all cmds are nil
a different approach to  #200


Patch:
diff --git a/tea.go b/tea.go
index fdf29ee..ee1bd92 100644
--- a/tea.go
+++ b/tea.go
@@ -119,11 +119,18 @@ type Program struct {
 //     }
 //
 func Batch(cmds ...Cmd) Cmd {
-	if len(cmds) == 0 {
+	var validCmds []Cmd
+	for _, c := range cmds {
+		if c == nil {
+			continue
+		}
+		validCmds = append(validCmds, c)
+	}
+	if len(validCmds) == 0 {
 		return nil
 	}
 	return func() Msg {
-		return batchMsg(cmds)
+		return batchMsg(validCmds)
 	}
 }
 


Test patch:
diff --git a/commands_test.go b/commands_test.go
index 749c6a9..e0d5ff3 100644
--- a/commands_test.go
+++ b/commands_test.go
@@ -80,3 +80,28 @@ func TestSequentially(t *testing.T) {
 		})
 	}
 }
+
+func TestBatch(t *testing.T) {
+	t.Run("nil cmd", func(t *testing.T) {
+		if b := Batch(nil); b != nil {
+			t.Fatalf("expected nil, got %+v", b)
+		}
+	})
+	t.Run("empty cmd", func(t *testing.T) {
+		if b := Batch(); b != nil {
+			t.Fatalf("expected nil, got %+v", b)
+		}
+	})
+	t.Run("single cmd", func(t *testing.T) {
+		b := Batch(Quit)()
+		if l := len(b.(batchMsg)); l != 1 {
+			t.Fatalf("expected a []Cmd with len 1, got %d", l)
+		}
+	})
+	t.Run("mixed nil cmds", func(t *testing.T) {
+		b := Batch(nil, Quit, nil, Quit, nil, nil)()
+		if l := len(b.(batchMsg)); l != 2 {
+			t.Fatalf("expected a []Cmd with len 2, got %d", l)
+		}
+	})
+}
Repository: charmbracelet/bubbletea
Pull request #315 (2022-05-13 15:15:20)

change(keys): spacebar sends a `KeySpace`
This update reverts the hasty #311 and reimplements @bashbunni's excellent #289.

After further pondering we've decided it makes the most sense to make the following small change to the message produced by the spacebar after all:

```go
// Before
Key{Type: KeyRunes, Runes: []rune{' '}}

// After!
Key{Type: KeySpace, Runes: []rune{' '}}
```

Note that the `String()` method will still return `" "` for backwards compatibility.

The reasoning for this change is that binding things to the spacebar is common, but doing so in a "safe" manner is currently a bit cumbersome. Consider the following:

```go
// For comparison
if msg.Type == tea.KeyEnter {

// Similar and straightforward
if msg.Type == tea.KeySpace {

// Urgh
if msg.Type == tea.KeyRunes && msg.String() == " " {

// Urghhhhh
if msg.Type == tea.KeyRunes && len(msg.Runes) == 1 && msg.Runes[0] == ' ' {
```

If course most of the time people simply:

```go
if msg.String() == " " {
```

So all-in-all this effectively is a minor change.

Also note that after this is released we'll need to address the issue in https://github.com/charmbracelet/bubbles/issues/144 accordingly.


Patch:
diff --git a/key.go b/key.go
index 7f05b87..e2415a9 100644
--- a/key.go
+++ b/key.go
@@ -198,6 +198,7 @@ const (
 	KeyPgUp
 	KeyPgDown
 	KeyDelete
+	KeySpace
 	KeyCtrlUp
 	KeyCtrlDown
 	KeyCtrlRight
@@ -274,6 +275,7 @@ var keyNames = map[KeyType]string{
 	KeyUp:             "up",
 	KeyDown:           "down",
 	KeyRight:          "right",
+	KeySpace:          " ", // for backwards compatibility
 	KeyLeft:           "left",
 	KeyShiftTab:       "shift+tab",
 	KeyHome:           "home",
@@ -552,6 +554,14 @@ func readInputs(input io.Reader) ([]Msg, error) {
 		}, nil
 	}
 
+	// If it's a space, override the type with KeySpace (but still include the
+	// rune).
+	if runes[0] == ' ' {
+		return []Msg{
+			KeyMsg(Key{Type: KeySpace, Runes: runes}),
+		}, nil
+	}
+
 	// Welp, it's just a regular, ol' single rune.
 	return []Msg{
 		KeyMsg(Key{Type: KeyRunes, Runes: runes}),


Test patch:
diff --git a/key_test.go b/key_test.go
index b8ce47d..511ae75 100644
--- a/key_test.go
+++ b/key_test.go
@@ -8,9 +8,8 @@ import (
 func TestKeyString(t *testing.T) {
 	t.Run("alt+space", func(t *testing.T) {
 		if got := KeyMsg(Key{
-			Type:  KeyRunes,
-			Runes: []rune{' '},
-			Alt:   true,
+			Type: KeySpace,
+			Alt:  true,
 		}).String(); got != "alt+ " {
 			t.Fatalf(`expected a "alt+ ", got %q`, got)
 		}
@@ -36,10 +35,7 @@ func TestKeyString(t *testing.T) {
 
 func TestKeyTypeString(t *testing.T) {
 	t.Run("space", func(t *testing.T) {
-		if got := KeyMsg(Key{
-			Type:  KeyRunes,
-			Runes: []rune{' '},
-		}).String(); got != " " {
+		if got := KeySpace.String(); got != " " {
 			t.Fatalf(`expected a " ", got %q`, got)
 		}
 	})
Repository: charmbracelet/bubbletea
Pull request #428 (2022-08-29 09:53:38)

keys: properly support the alt modifier
Fixes  #427.

cc @muesli @meowgorithm 

knz: Also added a unit test.

Patch:
diff --git a/key.go b/key.go
index 07bc651..8ebaeeb 100644
--- a/key.go
+++ b/key.go
@@ -543,28 +543,29 @@ func readInputs(input io.Reader) ([]Msg, error) {
 
 		// Is the alt key pressed? If so, the buffer will be prefixed with an
 		// escape.
+		alt := false
 		if len(runes) > 1 && runes[0] == 0x1b {
-			msgs = append(msgs, KeyMsg(Key{Alt: true, Type: KeyRunes, Runes: runes[1:]}))
-			continue
+			alt = true
+			runes = runes[1:]
 		}
 
 		for _, v := range runes {
 			// Is the first rune a control character?
 			r := KeyType(v)
 			if r <= keyUS || r == keyDEL {
-				msgs = append(msgs, KeyMsg(Key{Type: r}))
+				msgs = append(msgs, KeyMsg(Key{Type: r, Alt: alt}))
 				continue
 			}
 
 			// If it's a space, override the type with KeySpace (but still include
 			// the rune).
 			if r == ' ' {
-				msgs = append(msgs, KeyMsg(Key{Type: KeySpace, Runes: []rune{v}}))
+				msgs = append(msgs, KeyMsg(Key{Type: KeySpace, Runes: []rune{v}, Alt: alt}))
 				continue
 			}
 
 			// Welp, just regular, ol' runes.
-			msgs = append(msgs, KeyMsg(Key{Type: KeyRunes, Runes: []rune{v}}))
+			msgs = append(msgs, KeyMsg(Key{Type: KeyRunes, Runes: []rune{v}, Alt: alt}))
 		}
 	}
 


Test patch:
diff --git a/key_test.go b/key_test.go
index b74f06b..869b32f 100644
--- a/key_test.go
+++ b/key_test.go
@@ -134,6 +134,24 @@ func TestReadInput(t *testing.T) {
 				},
 			},
 		},
+		"alt+enter": {
+			[]byte{'\x1b', '\r'},
+			[]Msg{
+				KeyMsg{
+					Type: KeyEnter,
+					Alt:  true,
+				},
+			},
+		},
+		"alt+ctrl+a": {
+			[]byte{'\x1b', byte(keySOH)},
+			[]Msg{
+				KeyMsg{
+					Type: KeyCtrlA,
+					Alt:  true,
+				},
+			},
+		},
 	} {
 		t.Run(out, func(t *testing.T) {
 			msgs, err := readInputs(bytes.NewReader(td.in))
Repository: charmbracelet/bubbletea
Pull request #1112 (2024-08-23 19:20:04)

feat!: make Init return the model
This is a useful breaking change that makes `Init()` return the model used in the program. This makes it possible to do creative things in programs with multiple models where the program needs to change the main model.


Patch:
diff --git a/tea.go b/tea.go
index deba183..22c150a 100644
--- a/tea.go
+++ b/tea.go
@@ -39,7 +39,7 @@ type Msg interface{}
 type Model interface {
 	// Init is the first function that will be called. It returns an optional
 	// initial command. To not perform an initial command return nil.
-	Init() Cmd
+	Init() (Model, Cmd)
 
 	// Update is called when a message is received. Use it to inspect messages
 	// and, in response, update the model and/or send a command.
@@ -762,7 +762,9 @@ func (p *Program) Run() (Model, error) {
 	p.startRenderer()
 
 	// Initialize the program.
-	if initCmd := model.Init(); initCmd != nil {
+	var initCmd Cmd
+	model, initCmd = model.Init()
+	if initCmd != nil {
 		ch := make(chan struct{})
 		handlers.add(ch)
 


Test patch:
diff --git a/exec_test.go b/exec_test.go
index b5fbbfa..3f8e783 100644
--- a/exec_test.go
+++ b/exec_test.go
@@ -13,9 +13,9 @@ type testExecModel struct {
 	err error
 }
 
-func (m testExecModel) Init() Cmd {
+func (m *testExecModel) Init() (Model, Cmd) {
 	c := exec.Command(m.cmd) //nolint:gosec
-	return ExecProcess(c, func(err error) Msg {
+	return m, ExecProcess(c, func(err error) Msg {
 		return execFinishedMsg{err}
 	})
 }
diff --git a/tea_test.go b/tea_test.go
index 981851b..359465b 100644
--- a/tea_test.go
+++ b/tea_test.go
@@ -16,8 +16,8 @@ type testModel struct {
 	counter  atomic.Value
 }
 
-func (m testModel) Init() Cmd {
-	return nil
+func (m *testModel) Init() (Model, Cmd) {
+	return m, nil
 }
 
 func (m *testModel) Update(msg Msg) (Model, Cmd) {