@@ -71,135 +71,180 @@ func findIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte) []int {
7171 return []int {util .RunePos (str , match [0 ]), util .RunePos (str , match [1 ])}
7272}
7373
74- func findAllIndex (regex * regexp.Regexp , str []byte ) [][]int {
75- matches := regex .FindAllIndex (str , - 1 )
74+ func findAllIndex (regex * regexp.Regexp , skip * regexp.Regexp , str []byte ) [][]int {
75+ var strbytes []byte
76+ if skip != nil {
77+ strbytes = skip .ReplaceAllFunc (str , func (match []byte ) []byte {
78+ res := make ([]byte , util .CharacterCount (match ))
79+ return res
80+ })
81+ } else {
82+ strbytes = str
83+ }
84+
85+ matches := regex .FindAllIndex (strbytes , - 1 )
7686 for i , m := range matches {
7787 matches [i ][0 ] = util .RunePos (str , m [0 ])
7888 matches [i ][1 ] = util .RunePos (str , m [1 ])
7989 }
8090 return matches
8191}
8292
83- func (h * Highlighter ) highlightRegion (highlights LineMatch , start int , lineNum int , line []byte , curRegion * region ) LineMatch {
84- lineLen := util .CharacterCount (line )
85- if start == 0 {
86- if _ , ok := highlights [0 ]; ! ok {
87- highlights [0 ] = curRegion .group
93+ func (h * Highlighter ) highlightRange (fullHighlights []Group , start int , end int , group Group ) {
94+ if start <= end && end <= len (fullHighlights ) {
95+ for i := start ; i < end ; i ++ {
96+ fullHighlights [i ] = group
8897 }
8998 }
99+ }
90100
91- var nestedRegion * region
92- nestedLoc := []int {lineLen , 0 }
93- searchNesting := true
94- endLoc := findIndex (curRegion .end , curRegion .skip , line )
95- if endLoc != nil {
96- if start == endLoc [0 ] {
97- searchNesting = false
98- } else {
99- nestedLoc = endLoc
100- }
101+ func (h * Highlighter ) highlightPatterns (fullHighlights []Group , start int , lineNum int , line []byte , curRegion * region ) {
102+ lineLen := util .CharacterCount (line )
103+ if lineLen == 0 {
104+ return
101105 }
102- if searchNesting {
103- for _ , r := range curRegion .rules .regions {
104- loc := findIndex (r .start , r .skip , line )
105- if loc != nil {
106- if loc [0 ] < nestedLoc [0 ] {
107- nestedLoc = loc
108- nestedRegion = r
109- }
106+
107+ var patterns []* pattern
108+ if curRegion == nil {
109+ patterns = h .Def .rules .patterns
110+ } else {
111+ patterns = curRegion .rules .patterns
112+ }
113+
114+ for _ , p := range patterns {
115+ if curRegion == nil || curRegion .group == curRegion .limitGroup || p .group == curRegion .limitGroup {
116+ matches := findAllIndex (p .regex , nil , line )
117+ for _ , m := range matches {
118+ h .highlightRange (fullHighlights , start + m [0 ], start + m [1 ], p .group )
110119 }
111120 }
112121 }
113- if nestedRegion != nil && nestedLoc [0 ] != lineLen {
114- highlights [start + nestedLoc [0 ]] = nestedRegion .limitGroup
115- slice := util .SliceEnd (line , nestedLoc [1 ])
116- h .highlightEmptyRegion (highlights , start + nestedLoc [1 ], lineNum , slice )
117- h .highlightRegion (highlights , start + nestedLoc [1 ], lineNum , slice , nestedRegion )
118- return highlights
119- }
122+ }
120123
121- fullHighlights := make ([]Group , lineLen )
122- for i := 0 ; i < len (fullHighlights ); i ++ {
123- fullHighlights [i ] = curRegion .group
124+ func (h * Highlighter ) highlightRegions (fullHighlights []Group , start int , lineNum int , line []byte , curRegion * region , regions []* region , nestedRegion bool ) {
125+ lineLen := util .CharacterCount (line )
126+ if lineLen == 0 {
127+ return
124128 }
125129
126- if searchNesting {
127- for _ , p := range curRegion .rules .patterns {
128- if curRegion .group == curRegion .limitGroup || p .group == curRegion .limitGroup {
129- matches := findAllIndex (p .regex , line )
130- for _ , m := range matches {
131- if endLoc == nil || m [0 ] < endLoc [0 ] {
132- for i := m [0 ]; i < m [1 ]; i ++ {
133- fullHighlights [i ] = p .group
130+ h .highlightPatterns (fullHighlights , start , lineNum , line , curRegion )
131+
132+ lastStart := 0
133+ regionStart := 0
134+ regionEnd := 0
135+ for _ , r := range regions {
136+ if ! nestedRegion && curRegion != nil && (curRegion .group != r .group || curRegion .start != r .start ) {
137+ continue
138+ }
139+ startMatches := findAllIndex (r .start , r .skip , line )
140+ endMatches := findAllIndex (r .end , r .skip , line )
141+ samePattern := false
142+ startLoop:
143+ for startIdx := 0 ; startIdx < len (startMatches ); startIdx ++ {
144+ if startMatches [startIdx ][0 ] < lineLen {
145+ for endIdx := 0 ; endIdx < len (endMatches ); endIdx ++ {
146+ if startMatches [startIdx ][0 ] == endMatches [endIdx ][0 ] {
147+ // start and end are the same (pattern)
148+ samePattern = true
149+ if len (startMatches ) == len (endMatches ) {
150+ // special case in the moment both are the same
151+ if curRegion != nil && curRegion .group == r .group && curRegion .start == r .start {
152+ if len (startMatches ) > 1 {
153+ // end < start
154+ continue startLoop
155+ } else if len (startMatches ) > 0 {
156+ // ... end
157+ startIdx = len (startMatches )
158+ continue startLoop
159+ }
160+ } else {
161+ // start ... or start < end
162+ }
163+ }
164+ } else if startMatches [startIdx ][1 ] <= endMatches [endIdx ][0 ] {
165+ if regionStart < startMatches [startIdx ][0 ] && startMatches [startIdx ][0 ] < regionEnd {
166+ continue
167+ }
168+ // start and end at the current line
169+ regionStart = startMatches [startIdx ][0 ]
170+ regionEnd = endMatches [endIdx ][1 ]
171+ h .highlightRange (fullHighlights , start + startMatches [startIdx ][0 ], start + endMatches [endIdx ][1 ], r .limitGroup )
172+ h .highlightRegions (fullHighlights , start + startMatches [startIdx ][1 ], lineNum , util .SliceStartEnd (line , startMatches [startIdx ][1 ], endMatches [endIdx ][0 ]), r , r .rules .regions , true )
173+ if samePattern {
174+ startIdx += 1
175+ }
176+ if lastStart == 0 || lastStart < endMatches [endIdx ][1 ] {
177+ if curRegion != nil {
178+ h .lastRegion = curRegion .parent
179+ } else {
180+ h .lastRegion = nil
181+ }
182+ curRegion = h .lastRegion
183+ }
184+ continue startLoop
185+ } else if endMatches [endIdx ][1 ] <= startMatches [startIdx ][0 ] {
186+ if endMatches [endIdx ][0 ] < regionEnd || curRegion == nil {
187+ continue
134188 }
189+ // start and end at the current line, but switched
190+ h .highlightRange (fullHighlights , start , start + endMatches [endIdx ][1 ], r .limitGroup )
191+ h .highlightRegions (fullHighlights , start , lineNum , util .SliceStart (line , endMatches [endIdx ][0 ]), r , r .rules .regions , true )
192+ h .highlightPatterns (fullHighlights , start + endMatches [endIdx ][1 ], lineNum , util .SliceStartEnd (line , endMatches [endIdx ][1 ], startMatches [startIdx ][0 ]), nil )
193+ if curRegion != nil {
194+ h .lastRegion = curRegion .parent
195+ } else {
196+ h .lastRegion = nil
197+ }
198+ curRegion = h .lastRegion
199+ }
200+ }
201+ if regionEnd <= startMatches [startIdx ][0 ] {
202+ // start at the current, but end at the next line
203+ regionStart = startMatches [startIdx ][0 ]
204+ regionEnd = 0
205+ h .highlightRange (fullHighlights , start + startMatches [startIdx ][0 ], lineLen , r .limitGroup )
206+ h .highlightRegions (fullHighlights , start + startMatches [startIdx ][1 ], lineNum , util .SliceEnd (line , startMatches [startIdx ][1 ]), r , r .rules .regions , true )
207+ if lastStart <= startMatches [startIdx ][0 ] {
208+ lastStart = startMatches [startIdx ][0 ]
209+ h .lastRegion = r
135210 }
136211 }
137212 }
138213 }
139- }
140- for i , h := range fullHighlights {
141- if i == 0 || h != fullHighlights [i - 1 ] {
142- highlights [start + i ] = h
143- }
144- }
145-
146- loc := endLoc
147- if loc != nil {
148- highlights [start + loc [0 ]] = curRegion .limitGroup
149- if curRegion .parent == nil {
150- highlights [start + loc [1 ]] = 0
151- h .highlightEmptyRegion (highlights , start + loc [1 ], lineNum , util .SliceEnd (line , loc [1 ]))
152- return highlights
214+ if curRegion != nil && curRegion .group == r .group && curRegion .start == r .start {
215+ if (len (startMatches ) == 0 && len (endMatches ) > 0 ) || (samePattern && (len (startMatches ) == len (endMatches ))) {
216+ for _ , endMatch := range endMatches {
217+ // end at the current, but start at the previous line
218+ h .highlightRange (fullHighlights , start , start + endMatch [1 ], r .limitGroup )
219+ h .highlightRegions (fullHighlights , start , lineNum , util .SliceStart (line , endMatch [0 ]), r , r .rules .regions , true )
220+ if curRegion != nil {
221+ h .lastRegion = curRegion .parent
222+ } else {
223+ h .lastRegion = nil
224+ }
225+ curRegion = h .lastRegion
226+ break
227+ }
228+ } else if len (startMatches ) == 0 && len (endMatches ) == 0 {
229+ // no start and end found in this region
230+ h .highlightRange (fullHighlights , start , lineLen , curRegion .group )
231+ }
153232 }
154- highlights [start + loc [1 ]] = curRegion .parent .group
155- h .highlightRegion (highlights , start + loc [1 ], lineNum , util .SliceEnd (line , loc [1 ]), curRegion .parent )
156- return highlights
157233 }
158-
159- h .lastRegion = curRegion
160-
161- return highlights
162234}
163235
164- func (h * Highlighter ) highlightEmptyRegion (highlights LineMatch , start int , lineNum int , line []byte ) LineMatch {
236+ func (h * Highlighter ) highlight (highlights LineMatch , start int , lineNum int , line []byte , curRegion * region ) LineMatch {
165237 lineLen := util .CharacterCount (line )
166238 if lineLen == 0 {
167- h .lastRegion = nil
168239 return highlights
169240 }
170241
171- var firstRegion * region
172- firstLoc := []int {lineLen , 0 }
173- for _ , r := range h .Def .rules .regions {
174- loc := findIndex (r .start , r .skip , line )
175- if loc != nil {
176- if loc [0 ] < firstLoc [0 ] {
177- firstLoc = loc
178- firstRegion = r
179- }
180- }
181- }
182- if firstRegion != nil && firstLoc [0 ] != lineLen {
183- highlights [start + firstLoc [0 ]] = firstRegion .limitGroup
184- h .highlightEmptyRegion (highlights , start , lineNum , util .SliceStart (line , firstLoc [0 ]))
185- h .highlightRegion (highlights , start + firstLoc [1 ], lineNum , util .SliceEnd (line , firstLoc [1 ]), firstRegion )
186- return highlights
187- }
242+ fullHighlights := make ([]Group , lineLen )
243+ h .highlightRegions (fullHighlights , start , lineNum , line , curRegion , h .Def .rules .regions , false )
188244
189- fullHighlights := make ([]Group , len (line ))
190- for _ , p := range h .Def .rules .patterns {
191- matches := findAllIndex (p .regex , line )
192- for _ , m := range matches {
193- for i := m [0 ]; i < m [1 ]; i ++ {
194- fullHighlights [i ] = p .group
195- }
196- }
197- }
198245 for i , h := range fullHighlights {
199246 if i == 0 || h != fullHighlights [i - 1 ] {
200- // if _, ok := highlights[start+i]; !ok {
201- highlights [start + i ] = h
202- // }
247+ highlights [i ] = h
203248 }
204249 }
205250
@@ -217,12 +262,7 @@ func (h *Highlighter) HighlightString(input string) []LineMatch {
217262 for i := 0 ; i < len (lines ); i ++ {
218263 line := []byte (lines [i ])
219264 highlights := make (LineMatch )
220-
221- if i == 0 || h .lastRegion == nil {
222- lineMatches = append (lineMatches , h .highlightEmptyRegion (highlights , 0 , i , line ))
223- } else {
224- lineMatches = append (lineMatches , h .highlightRegion (highlights , 0 , i , line , h .lastRegion ))
225- }
265+ lineMatches = append (lineMatches , h .highlight (highlights , 0 , i , line , nil ))
226266 }
227267
228268 return lineMatches
@@ -245,11 +285,7 @@ func (h *Highlighter) Highlight(input LineStates, startline, endline int) {
245285 highlights := make (LineMatch )
246286
247287 var match LineMatch
248- if i == 0 || h .lastRegion == nil {
249- match = h .highlightEmptyRegion (highlights , 0 , i , line )
250- } else {
251- match = h .highlightRegion (highlights , 0 , i , line , h .lastRegion )
252- }
288+ match = h .highlight (highlights , 0 , i , line , h .lastRegion )
253289
254290 input .SetState (i , h .lastRegion )
255291 input .SetMatch (i , match )
@@ -267,11 +303,7 @@ func (h *Highlighter) ReHighlightLine(input LineStates, lineN int) {
267303 }
268304
269305 var match LineMatch
270- if lineN == 0 || h .lastRegion == nil {
271- match = h .highlightEmptyRegion (highlights , 0 , lineN , line )
272- } else {
273- match = h .highlightRegion (highlights , 0 , lineN , line , h .lastRegion )
274- }
306+ match = h .highlight (highlights , 0 , lineN , line , h .lastRegion )
275307
276308 input .SetState (lineN , h .lastRegion )
277309 input .SetMatch (lineN , match )
0 commit comments