diff --git a/go.mod b/go.mod index e316a0a..42d6dd9 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.23.7 require ( github.com/MakeNowJust/heredoc v1.0.0 github.com/atotto/clipboard v0.1.4 + github.com/aymanbagabas/go-udiff v0.2.0 github.com/charmbracelet/bubbletea v1.3.4 github.com/charmbracelet/harmonica v0.2.0 github.com/charmbracelet/lipgloss v1.1.0 @@ -22,7 +23,6 @@ require ( require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect diff --git a/textarea/textarea.go b/textarea/textarea.go index 620201c..d82ae97 100644 --- a/textarea/textarea.go +++ b/textarea/textarea.go @@ -1271,11 +1271,13 @@ func (m Model) placeholderView() string { case i == 0: // first character of first line as cursor with character m.Cursor.TextStyle = m.style.computedPlaceholder() - m.Cursor.SetChar(string(plines[0][0])) + + ch, rest, _, _ := uniseg.FirstGraphemeClusterInString(plines[0], 0) + m.Cursor.SetChar(ch) s.WriteString(lineStyle.Render(m.Cursor.View())) // the rest of the first line - s.WriteString(lineStyle.Render(style.Render(plines[0][1:] + strings.Repeat(" ", max(0, m.width-uniseg.StringWidth(plines[0])))))) + s.WriteString(lineStyle.Render(style.Render(rest))) // remaining lines case len(plines) > i: // current line placeholder text diff --git a/textarea/textarea_test.go b/textarea/textarea_test.go index 9b272c5..ea3e3cc 100644 --- a/textarea/textarea_test.go +++ b/textarea/textarea_test.go @@ -6,6 +6,7 @@ import ( "unicode" "github.com/MakeNowJust/heredoc" + "github.com/aymanbagabas/go-udiff" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/x/ansi" @@ -1671,6 +1672,26 @@ func TestView(t *testing.T) { `), }, }, + { + name: "placeholder chinese character", + modelFunc: func(m Model) Model { + m.Placeholder = "输入消息..." + m.ShowLineNumbers = true + m.SetWidth(20) + return m + }, + want: want{ + view: heredoc.Doc(` + > 1 输入消息... + > + > + > + > + > + + `), + }, + }, } for _, tt := range tests { @@ -1689,6 +1710,7 @@ func TestView(t *testing.T) { wantView := stripString(tt.want.view) if view != wantView { + t.Log(udiff.Unified("expected", "got", wantView, view)) t.Fatalf("Want:\n%v\nGot:\n%v\n", wantView, view) }