src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/ui/style_regions.go (about) 1 package ui 2 3 import ( 4 "sort" 5 6 "src.elv.sh/pkg/diag" 7 ) 8 9 // StylingRegion represents a region to apply styling. 10 type StylingRegion struct { 11 diag.Ranging 12 Styling Styling 13 Priority int 14 } 15 16 // StyleRegions applies styling to the specified regions in s. 17 // 18 // The regions are sorted by start position. If multiple Regions share the same 19 // starting position, the one with the highest priority is kept; the other 20 // regions are removed. If a Region starts before the end of the previous 21 // Region, it is also removed. 22 func StyleRegions(s string, regions []StylingRegion) Text { 23 regions = fixRegions(regions) 24 25 var text Text 26 lastTo := 0 27 for _, r := range regions { 28 if r.From > lastTo { 29 // Add text between regions or before the first region. 30 text = append(text, &Segment{Text: s[lastTo:r.From]}) 31 } 32 text = append(text, 33 StyleSegment(&Segment{Text: s[r.From:r.To]}, r.Styling)) 34 lastTo = r.To 35 } 36 if len(s) > lastTo { 37 // Add text after the last region. 38 text = append(text, &Segment{Text: s[lastTo:]}) 39 } 40 return text 41 } 42 43 func fixRegions(regions []StylingRegion) []StylingRegion { 44 regions = append([]StylingRegion(nil), regions...) 45 // Sort regions by their start positions. Regions with the same start 46 // position are sorted by decreasing priority. 47 sort.Slice(regions, func(i, j int) bool { 48 a, b := regions[i], regions[j] 49 return a.From < b.From || (a.From == b.From && a.Priority > b.Priority) 50 }) 51 // Remove overlapping regions, preferring the ones that appear earlier. 52 var newRegions []StylingRegion 53 lastTo := 0 54 for _, r := range regions { 55 if r.From < lastTo { 56 // Overlaps with the last one 57 continue 58 } 59 newRegions = append(newRegions, r) 60 lastTo = r.To 61 } 62 return newRegions 63 }