File: style_regions.go

package info (click to toggle)
elvish 0.21.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,372 kB
  • sloc: javascript: 236; sh: 130; python: 104; makefile: 88; xml: 9
file content (63 lines) | stat: -rw-r--r-- 1,715 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package ui

import (
	"sort"

	"src.elv.sh/pkg/diag"
)

// StylingRegion represents a region to apply styling.
type StylingRegion struct {
	diag.Ranging
	Styling  Styling
	Priority int
}

// StyleRegions applies styling to the specified regions in s.
//
// The regions are sorted by start position. If multiple Regions share the same
// starting position, the one with the highest priority is kept; the other
// regions are removed. If a Region starts before the end of the previous
// Region, it is also removed.
func StyleRegions(s string, regions []StylingRegion) Text {
	regions = fixRegions(regions)

	var text Text
	lastTo := 0
	for _, r := range regions {
		if r.From > lastTo {
			// Add text between regions or before the first region.
			text = append(text, &Segment{Text: s[lastTo:r.From]})
		}
		text = append(text,
			StyleSegment(&Segment{Text: s[r.From:r.To]}, r.Styling))
		lastTo = r.To
	}
	if len(s) > lastTo {
		// Add text after the last region.
		text = append(text, &Segment{Text: s[lastTo:]})
	}
	return text
}

func fixRegions(regions []StylingRegion) []StylingRegion {
	regions = append([]StylingRegion(nil), regions...)
	// Sort regions by their start positions. Regions with the same start
	// position are sorted by decreasing priority.
	sort.Slice(regions, func(i, j int) bool {
		a, b := regions[i], regions[j]
		return a.From < b.From || (a.From == b.From && a.Priority > b.Priority)
	})
	// Remove overlapping regions, preferring the ones that appear earlier.
	var newRegions []StylingRegion
	lastTo := 0
	for _, r := range regions {
		if r.From < lastTo {
			// Overlaps with the last one
			continue
		}
		newRegions = append(newRegions, r)
		lastTo = r.To
	}
	return newRegions
}