diff --git a/go.mod b/go.mod index 135d87c..fddd82e 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/charmbracelet/bubbles go 1.18 require ( + github.com/MakeNowJust/heredoc v1.0.0 + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/atotto/clipboard v0.1.4 github.com/charmbracelet/bubbletea v0.25.0 github.com/charmbracelet/harmonica v0.2.0 diff --git a/go.sum b/go.sum index 927bf6d..10807da 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= diff --git a/textarea/textarea_test.go b/textarea/textarea_test.go index 461fc50..f021b82 100644 --- a/textarea/textarea_test.go +++ b/textarea/textarea_test.go @@ -3,7 +3,10 @@ package textarea import ( "strings" "testing" + "unicode" + "github.com/MakeNowJust/heredoc" + "github.com/acarl005/stripansi" tea "github.com/charmbracelet/bubbletea" ) @@ -416,15 +419,210 @@ func TestVerticalNavigationShouldRememberPositionWhileTraversing(t *testing.T) { } } -func TestRendersEndOfLineBuffer(t *testing.T) { - textarea := newTextArea() - textarea.ShowLineNumbers = true - textarea.SetWidth(20) +func TestView(t *testing.T) { + tests := []struct { + name string + modelFunc func(Model) Model + expected string + }{ + { + name: "placeholder", + expected: heredoc.Doc(` + > 1 Hello, World! + > ~ + > ~ + > ~ + > ~ + > ~ + `), + }, + { + name: "single line", + modelFunc: func(m Model) Model { + m.SetValue("the first line") - view := textarea.View() - if !strings.Contains(view, "~") { - t.Log(view) - t.Fatal("Expected to see a tilde at the end of the line") + return m + }, + expected: heredoc.Doc(` + > 1 the first line + > ~ + > ~ + > ~ + > ~ + > ~ + `), + }, + { + name: "multiple lines", + modelFunc: func(m Model) Model { + m.SetValue("the first line\nthe second line\nthe third line") + + return m + }, + expected: heredoc.Doc(` + > 1 the first line + > 2 the second line + > 3 the third line + > ~ + > ~ + > ~ + `), + }, + { + name: "single line without line numbers", + modelFunc: func(m Model) Model { + m.SetValue("the first line") + m.ShowLineNumbers = false + + return m + }, + expected: heredoc.Doc(` + > the first line + > + > + > + > + > + `), + }, + { + name: "multipline lines without line numbers", + modelFunc: func(m Model) Model { + m.SetValue("the first line\nthe second line\nthe third line") + m.ShowLineNumbers = false + + return m + }, + expected: heredoc.Doc(` + > the first line + > the second line + > the third line + > + > + > + `), + }, + { + name: "single line and custom end of buffer character", + modelFunc: func(m Model) Model { + m.SetValue("the first line") + m.EndOfBufferCharacter = '*' + + return m + }, + expected: heredoc.Doc(` + > 1 the first line + > * + > * + > * + > * + > * + `), + }, + { + name: "multiple lines and custom end of buffer character", + modelFunc: func(m Model) Model { + m.SetValue("the first line\nthe second line\nthe third line") + m.EndOfBufferCharacter = '*' + + return m + }, + expected: heredoc.Doc(` + > 1 the first line + > 2 the second line + > 3 the third line + > * + > * + > * + `), + }, + { + name: "single line without line numbers and custom end of buffer character", + modelFunc: func(m Model) Model { + m.SetValue("the first line") + m.ShowLineNumbers = false + m.EndOfBufferCharacter = '*' + + return m + }, + expected: heredoc.Doc(` + > the first line + > + > + > + > + > + `), + }, + { + name: "multiple lines without line numbers and custom end of buffer character", + modelFunc: func(m Model) Model { + m.SetValue("the first line\nthe second line\nthe third line") + m.ShowLineNumbers = false + m.EndOfBufferCharacter = '*' + + return m + }, + expected: heredoc.Doc(` + > the first line + > the second line + > the third line + > + > + > + `), + }, + { + name: "single line and custom prompt", + modelFunc: func(m Model) Model { + m.SetValue("the first line") + m.Prompt = "* " + + return m + }, + expected: heredoc.Doc(` + * 1 the first line + * ~ + * ~ + * ~ + * ~ + * ~ + `), + }, + { + name: "multiple lines and custom prompt", + modelFunc: func(m Model) Model { + m.SetValue("the first line\nthe second line\nthe third line") + m.Prompt = "* " + + return m + }, + expected: heredoc.Doc(` + * 1 the first line + * 2 the second line + * 3 the third line + * ~ + * ~ + * ~ + `), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + textarea := newTextArea() + + if tt.modelFunc != nil { + textarea = tt.modelFunc(textarea) + } + + view := stripString(textarea.View()) + expected := stripString(tt.expected) + + if view != expected { + t.Fatalf("Expected:\n%v\nGot:\n%v\n", expected, view) + } + }) } } @@ -444,3 +642,18 @@ func newTextArea() Model { func keyPress(key rune) tea.Msg { return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{key}, Alt: false} } + +func stripString(str string) string { + s := stripansi.Strip(str) + ss := strings.Split(s, "\n") + + var lines []string + for _, l := range ss { + trim := strings.TrimRightFunc(l, unicode.IsSpace) + if trim != "" { + lines = append(lines, trim) + } + } + + return strings.Join(lines, "\n") +}