Skip to content

Commit 1c9dbbb

Browse files
committed
highlighter: Add capability to remove already captured groups
This is necessary in the moment sibling regions overlap each other.
1 parent 80d010c commit 1c9dbbb

1 file changed

Lines changed: 104 additions & 36 deletions

File tree

pkg/highlight/highlighter.go

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,21 @@ type LineStates interface {
2222
Unlock()
2323
}
2424

25+
// highlightStorage is used to store the found ranges
26+
type highlightStorage struct {
27+
start int
28+
end int
29+
group Group
30+
region *region
31+
}
32+
2533
// A Highlighter contains the information needed to highlight a string
2634
type Highlighter struct {
2735
lastRegion *region
2836
lastStart int
2937
lastEnd int
3038
Def *Def
39+
storage []highlightStorage
3140
}
3241

3342
// NewHighlighter returns a new highlighter from the given syntax definition
@@ -79,16 +88,64 @@ func findAllIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte) [][]int
7988
return matches
8089
}
8190

82-
func (h *Highlighter) highlightRange(fullHighlights []Group, start int, end int, group Group) {
83-
if start <= end && end <= len(fullHighlights) {
84-
for i := start; i < end; i++ {
85-
fullHighlights[i] = group
86-
// log.Println("fullHighlights[", i, "]:", group)
91+
func (h *Highlighter) removeRange(start int, end int, removeStart int) {
92+
removeEnd := removeStart
93+
for i := removeStart; i < len(h.storage); i++ {
94+
next := h.storage[i]
95+
if start < next.start && next.start < end {
96+
// log.Println("removed: start:", next.start, "end:", next.end, "group:", next.group)
97+
removeEnd++
8798
}
8899
}
100+
if removeStart < removeEnd {
101+
h.storage = append(h.storage[:removeStart], h.storage[removeEnd:]...)
102+
}
89103
}
90104

91-
func (h *Highlighter) highlightPatterns(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region) {
105+
func (h *Highlighter) storeRange(start int, end int, group Group, region *region) {
106+
// log.Println("storeRange: start:", start, "end:", end, "group:", group)
107+
for k, e := range h.storage {
108+
if e.region != nil && region != nil {
109+
if e.region.parent == region.parent {
110+
if region == e.region {
111+
if group == e.group && start == e.end {
112+
// same region, update ...
113+
h.storage[k].end = end
114+
// log.Println("exchanged to: start:", h.storage[k].start, "end:", h.storage[k].end, "group:", h.storage[k].group)
115+
return
116+
}
117+
} else {
118+
// sibling regions, search for overlaps ...
119+
if start < e.start && end > e.start {
120+
// overlap
121+
} else if (start < e.start && end >= e.end) || (start <= e.start && end > e.end) {
122+
// larger match
123+
} else if start >= e.start && end <= e.end {
124+
// smaller or same match
125+
return
126+
} else {
127+
continue
128+
}
129+
130+
// log.Println("exchanged from: start:", e.start, "end:", e.end, "group:", e.group)
131+
h.storage[k] = highlightStorage{start, end, group, region}
132+
133+
// check and remove follow-ups matching the same
134+
h.removeRange(start, end, k + 1)
135+
return
136+
}
137+
} else {
138+
if region.parent != e.region && start >= e.start && end <= e.end {
139+
return
140+
}
141+
}
142+
}
143+
}
144+
145+
h.storage = append(h.storage, highlightStorage{start, end, group, region})
146+
}
147+
148+
func (h *Highlighter) highlightPatterns(start int, lineNum int, line []byte, curRegion *region) {
92149
lineLen := util.CharacterCount(line)
93150
// log.Println("highlightPatterns: lineNum:", lineNum, "start:", start, "line:", string(line))
94151
if lineLen == 0 {
@@ -105,24 +162,25 @@ func (h *Highlighter) highlightPatterns(fullHighlights []Group, start int, lineN
105162
for _, p := range patterns {
106163
matches := findAllIndex(p.regex, nil, line)
107164
for _, m := range matches {
108-
h.highlightRange(fullHighlights, start+m[0], start+m[1], p.group)
165+
h.storeRange(start+m[0], start+m[1], p.group, nil)
109166
}
110167
}
111168
}
112169

113-
func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region, regions []*region, nestedRegion bool) {
170+
func (h *Highlighter) highlightRegions(start int, lineNum int, line []byte, curRegion *region, regions []*region, nestedRegion bool) {
114171
lineLen := util.CharacterCount(line)
115172
// log.Println("highlightRegions: lineNum:", lineNum, "start:", start, "line:", string(line))
116173
if lineLen == 0 {
117174
return
118175
}
119176

120177
if nestedRegion {
121-
h.highlightPatterns(fullHighlights, start, lineNum, line, curRegion)
178+
h.highlightPatterns(start, lineNum, line, curRegion)
122179
} else {
123-
h.highlightPatterns(fullHighlights, start, lineNum, line, nil)
180+
h.highlightPatterns(start, lineNum, line, nil)
124181
}
125182

183+
regionLoop:
126184
for _, r := range regions {
127185
// log.Println("r.start:", r.start.String(), "r.end", r.end.String())
128186
if !nestedRegion && curRegion != nil && curRegion != r {
@@ -164,15 +222,15 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
164222
// start and end at the current line
165223
// log.Println("start < end")
166224
update := false
167-
if h.lastStart == 0 || h.lastStart < start+endMatch[1] {
225+
if h.lastStart == -1 || h.lastStart < start+endMatch[1] {
168226
h.lastStart = start + startMatch[0]
169227
h.lastEnd = start + endMatch[1]
170228
update = true
171229
}
172-
h.highlightRange(fullHighlights, start+startMatch[0], start+startMatch[1], r.limitGroup)
173-
h.highlightRange(fullHighlights, start+startMatch[1], start+endMatch[0], r.group)
174-
h.highlightRange(fullHighlights, start+endMatch[0], start+endMatch[1], r.limitGroup)
175-
h.highlightRegions(fullHighlights, start+startMatch[1], lineNum, util.SliceStartEnd(line, startMatch[1], endMatch[0]), r, r.rules.regions, true)
230+
h.storeRange(start+startMatch[0], start+startMatch[1], r.limitGroup, r)
231+
h.storeRange(start+startMatch[1], start+endMatch[0], r.group, r)
232+
h.storeRange(start+endMatch[0], start+endMatch[1], r.limitGroup, r)
233+
h.highlightRegions(start+startMatch[1], lineNum, util.SliceStartEnd(line, startMatch[1], endMatch[0]), r, r.rules.regions, true)
176234
if samePattern {
177235
startIdx += 1
178236
}
@@ -193,10 +251,10 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
193251
// log.Println("end < start")
194252
h.lastStart = start
195253
h.lastEnd = start + endMatch[1]
196-
h.highlightRange(fullHighlights, start, start+endMatch[0], r.group)
197-
h.highlightRange(fullHighlights, start+endMatch[0], start+endMatch[1], r.limitGroup)
198-
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true)
199-
h.highlightPatterns(fullHighlights, start+endMatch[1], lineNum, util.SliceStartEnd(line, endMatch[1], startMatch[0]), nil)
254+
h.storeRange(start, start+endMatch[0], r.group, r)
255+
h.storeRange(start+endMatch[0], start+endMatch[1], r.limitGroup, r)
256+
h.highlightRegions(start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true)
257+
h.highlightPatterns(start+endMatch[1], lineNum, util.SliceStartEnd(line, endMatch[1], startMatch[0]), nil)
200258
if curRegion != nil {
201259
h.lastRegion = r.parent
202260
} else {
@@ -205,17 +263,18 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
205263
curRegion = h.lastRegion
206264
}
207265
}
208-
if nestedRegion || start+startMatch[0] <= h.lastStart || h.lastEnd <= start+startMatch[0] {
266+
if nestedRegion || start+startMatch[0] < h.lastStart || h.lastEnd < start+startMatch[0] {
209267
// start at the current, but end at the next line
210268
// log.Println("start ...")
211-
h.lastStart = start + startMatch[0]
212-
h.lastEnd = start + lineLen
213-
h.highlightRange(fullHighlights, start+startMatch[0], start+startMatch[1], r.limitGroup)
214-
h.highlightRange(fullHighlights, start+startMatch[1], start+lineLen, r.group)
215-
h.highlightRegions(fullHighlights, start+startMatch[1], lineNum, util.SliceEnd(line, startMatch[1]), r, r.rules.regions, true)
216-
if h.lastStart == 0 || h.lastStart <= start+startMatch[0] {
269+
if h.lastStart == -1 || start+startMatch[0] < h.lastStart || h.lastEnd < start+startMatch[0] {
270+
h.lastStart = start + startMatch[0]
271+
h.lastEnd = start + lineLen - 1
217272
h.lastRegion = r
218273
}
274+
h.storeRange(start+startMatch[0], start+startMatch[1], r.limitGroup, r)
275+
h.storeRange(start+startMatch[1], start+lineLen, r.group, r)
276+
h.highlightRegions(start+startMatch[1], lineNum, util.SliceEnd(line, startMatch[1]), r, r.rules.regions, true)
277+
continue regionLoop
219278
}
220279
}
221280
if curRegion == r {
@@ -225,21 +284,21 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
225284
// log.Println("... end")
226285
h.lastStart = start
227286
h.lastEnd = start + endMatch[1]
228-
h.highlightRange(fullHighlights, start, start+endMatch[0], r.group)
229-
h.highlightRange(fullHighlights, start+endMatch[0], start+endMatch[1], r.limitGroup)
230-
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true)
287+
h.storeRange(start, start+endMatch[0], r.group, r)
288+
h.storeRange(start+endMatch[0], start+endMatch[1], r.limitGroup, r)
289+
h.highlightRegions(start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true)
231290
if curRegion != nil {
232291
h.lastRegion = r.parent
233292
} else {
234293
h.lastRegion = nil
235294
}
236295
curRegion = h.lastRegion
237-
h.highlightRegions(fullHighlights, start+endMatch[1], lineNum, util.SliceEnd(line, endMatch[1]), curRegion, h.Def.rules.regions, false)
296+
h.highlightRegions(start+endMatch[1], lineNum, util.SliceEnd(line, endMatch[1]), curRegion, h.Def.rules.regions, false)
238297
break
239298
}
240299
} else if len(startMatches) == 0 && len(endMatches) == 0 {
241300
// no start and end found in this region
242-
h.highlightRange(fullHighlights, start, start+lineLen, curRegion.group)
301+
h.storeRange(start, start+lineLen, curRegion.group, r)
243302
}
244303
}
245304
}
@@ -248,12 +307,12 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
248307
// current region still open
249308
// log.Println("...")
250309
if curRegion.rules != nil {
251-
h.highlightRegions(fullHighlights, start, lineNum, line, curRegion, curRegion.rules.regions, true)
310+
h.highlightRegions(start, lineNum, line, curRegion, curRegion.rules.regions, true)
252311
}
253312
if curRegion == h.lastRegion && curRegion.parent != nil {
254313
var regions []*region
255314
regions = append(regions, curRegion)
256-
h.highlightRegions(fullHighlights, start, lineNum, line, curRegion, regions, true)
315+
h.highlightRegions(start, lineNum, line, curRegion, regions, true)
257316
}
258317
}
259318
}
@@ -265,11 +324,20 @@ func (h *Highlighter) highlight(highlights LineMatch, start int, lineNum int, li
265324
return highlights
266325
}
267326

268-
h.lastStart = 0
269-
h.lastEnd = 0
327+
h.lastStart = -1
328+
h.lastEnd = -1
329+
h.storage = h.storage[:0]
330+
331+
h.highlightRegions(start, lineNum, line, curRegion, h.Def.rules.regions, false)
270332

271333
fullHighlights := make([]Group, lineLen)
272-
h.highlightRegions(fullHighlights, start, lineNum, line, curRegion, h.Def.rules.regions, false)
334+
335+
for _, e := range h.storage {
336+
for i := e.start; i < e.end; i++ {
337+
fullHighlights[i] = e.group
338+
// log.Println("fullHighlights[", i, "]:", e.group)
339+
}
340+
}
273341

274342
for i, h := range fullHighlights {
275343
if i == 0 || h != fullHighlights[i-1] {

0 commit comments

Comments
 (0)