src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/ui/text_builder.go (about)

     1  package ui
     2  
     3  import "strings"
     4  
     5  // Methods of [TextBuilder] are fully exercised by other functions Concat, so
     6  // there are no dedicated tests for it.
     7  
     8  // TextBuilder can be used to efficiently build a [Text]. The zero value is
     9  // ready to use. Do not copy a non-zero TextBuilder.
    10  type TextBuilder struct {
    11  	segs  []*Segment
    12  	style Style
    13  	text  strings.Builder
    14  }
    15  
    16  // WriteText appends t to the TextBuilder.
    17  func (tb *TextBuilder) WriteText(t Text) {
    18  	if len(t) == 0 {
    19  		return
    20  	}
    21  	if tb.style == t[0].Style {
    22  		// Merge the first segment of t with the pending segment.
    23  		tb.text.WriteString(t[0].Text)
    24  		t = t[1:]
    25  		if len(t) == 0 {
    26  			return
    27  		}
    28  	}
    29  	// At this point, the first segment of t has a different style than the
    30  	// pending segment (assuming that t is normal). Add the pending segment if
    31  	// it's non-empty.
    32  	if tb.text.Len() > 0 {
    33  		tb.segs = append(tb.segs, &Segment{tb.style, tb.text.String()})
    34  		tb.text.Reset()
    35  	}
    36  	// Add all segments from t except the last one.
    37  	tb.segs = append(tb.segs, t[:len(t)-1]...)
    38  
    39  	// Use the last segment of t as the pending segment.
    40  	tb.style = t[len(t)-1].Style
    41  	tb.text.WriteString(t[len(t)-1].Text)
    42  }
    43  
    44  // Text returns the [Text] that has been built.
    45  func (tb *TextBuilder) Text() Text {
    46  	if tb.Empty() {
    47  		return nil
    48  	}
    49  	t := append(Text(nil), tb.segs...)
    50  	return append(t, &Segment{tb.style, tb.text.String()})
    51  }
    52  
    53  // Empty returns nothing has been written to the TextBuilder yet.
    54  func (tb *TextBuilder) Empty() bool {
    55  	return len(tb.segs) == 0 && tb.text.Len() == 0
    56  }
    57  
    58  // Reset resets the TextBuilder to be empty.
    59  func (tb *TextBuilder) Reset() {
    60  	tb.segs = nil
    61  	tb.style = Style{}
    62  	tb.text.Reset()
    63  }