ranges.go

 1package lipgloss
 2
 3import (
 4	"strings"
 5
 6	"github.com/charmbracelet/x/ansi"
 7)
 8
 9// StyleRanges applying styling to ranges in a string. Existing styles will be
10// taken into account. Ranges should not overlap.
11func StyleRanges(s string, ranges ...Range) string {
12	if len(ranges) == 0 {
13		return s
14	}
15
16	var buf strings.Builder
17	lastIdx := 0
18	stripped := ansi.Strip(s)
19
20	// Use Truncate and TruncateLeft to style match.MatchedIndexes without
21	// losing the original option style:
22	for _, rng := range ranges {
23		// Add the text before this match
24		if rng.Start > lastIdx {
25			buf.WriteString(ansi.Cut(s, lastIdx, rng.Start))
26		}
27		// Add the matched range with its highlight
28		buf.WriteString(rng.Style.Render(ansi.Cut(stripped, rng.Start, rng.End)))
29		lastIdx = rng.End
30	}
31
32	// Add any remaining text after the last match
33	buf.WriteString(ansi.TruncateLeft(s, lastIdx, ""))
34
35	return buf.String()
36}
37
38// NewRange returns a range and style that can be used with [StyleRanges].
39func NewRange(start, end int, style Style) Range {
40	return Range{start, end, style}
41}
42
43// Range is a range of text and associated styling to be used with
44// [StyleRanges].
45type Range struct {
46	Start, End int
47	Style      Style
48}