@@ -40,6 +40,24 @@ type (
4040 pasteErrMsg struct { error }
4141)
4242
43+ // WrapMode describes how to line-wrap text.
44+ type WrapMode int
45+
46+ // Available wrap modes.
47+ const (
48+ WordWrap WrapMode = iota
49+ RuneWrap
50+ )
51+
52+ // String returns the wrap mode in a human-readable format. This method is
53+ // provisional and for informational purposes only.
54+ func (w WrapMode ) String () string {
55+ return [... ]string {
56+ "word" ,
57+ "rune" ,
58+ }[w ]
59+ }
60+
4361// KeyMap is the key bindings for different actions within the textarea.
4462type KeyMap struct {
4563 CharacterBackward key.Binding
@@ -174,13 +192,14 @@ func (s Style) computedText() lipgloss.Style {
174192// line is the input to the text wrapping function. This is stored in a struct
175193// so that it can be hashed and memoized.
176194type line struct {
177- runes []rune
178- width int
195+ runes []rune
196+ width int
197+ wrapMode WrapMode
179198}
180199
181200// Hash returns a hash of the line.
182201func (w line ) Hash () string {
183- v := fmt .Sprintf ("%s:%d" , string (w .runes ), w .width )
202+ v := fmt .Sprintf ("%s:%d:%d " , string (w .runes ), w .width , w . wrapMode )
184203 return fmt .Sprintf ("%x" , sha256 .Sum256 ([]byte (v )))
185204}
186205
@@ -238,6 +257,9 @@ type Model struct {
238257 // there's no limit.
239258 MaxWidth int
240259
260+ // wrapMode determines line-wrapping behavior.
261+ wrapMode WrapMode
262+
241263 // If promptFunc is set, it replaces Prompt as a generator for
242264 // prompt strings at the beginning of each line.
243265 promptFunc func (line int ) string
@@ -300,6 +322,7 @@ func New() Model {
300322 ShowLineNumbers : true ,
301323 Cursor : cur ,
302324 KeyMap : DefaultKeyMap ,
325+ wrapMode : WordWrap ,
303326
304327 value : make ([][]rune , minHeight , maxLines ),
305328 focus : false ,
@@ -954,6 +977,14 @@ func (m *Model) SetHeight(h int) {
954977 }
955978}
956979
980+ // SetWrapMode sets the model's wrap mode.
981+ func (m * Model ) SetWrapMode (mode WrapMode ) {
982+ if mode < WordWrap || mode > RuneWrap {
983+ return
984+ }
985+ m .wrapMode = mode
986+ }
987+
957988// Update is the Bubble Tea update loop.
958989func (m Model ) Update (msg tea.Msg ) (Model , tea.Cmd ) {
959990 if ! m .focus {
@@ -1304,11 +1335,11 @@ func Blink() tea.Msg {
13041335}
13051336
13061337func (m Model ) memoizedWrap (runes []rune , width int ) [][]rune {
1307- input := line {runes : runes , width : width }
1338+ input := line {runes : runes , width : width , wrapMode : m . wrapMode }
13081339 if v , ok := m .cache .Get (input ); ok {
13091340 return v
13101341 }
1311- v := wrap (runes , width )
1342+ v := wrap (runes , width , m . wrapMode )
13121343 m .cache .Set (input , v )
13131344 return v
13141345}
@@ -1395,7 +1426,23 @@ func Paste() tea.Msg {
13951426 return pasteMsg (str )
13961427}
13971428
1398- func wrap (runes []rune , width int ) [][]rune {
1429+ func wrap (runes []rune , width int , mode WrapMode ) [][]rune {
1430+ if mode == RuneWrap {
1431+ wrapped := ansi .Hardwrap (string (runes ), width , true )
1432+ wrappedSplit := strings .Split (wrapped , "\n " )
1433+
1434+ lines := [][]rune {}
1435+ for i , s := range wrappedSplit {
1436+ if i == len (wrappedSplit )- 1 {
1437+ s += " "
1438+ }
1439+
1440+ lines = append (lines , []rune (s ))
1441+ }
1442+
1443+ return lines
1444+ }
1445+
13991446 var (
14001447 lines = [][]rune {{}}
14011448 word = []rune {}
0 commit comments