@@ -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
2634type 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