Skip to content

Commit

Permalink
highlighter: Reintroduction of statesOnly to fix bottom up changes
Browse files Browse the repository at this point in the history
This regression was introduced by accident in the moment the highlighting
interfaces have been combined. The MarkModified() method of the buffer
wasn't able to highlight bottom up changes lines in the backward direction.
  • Loading branch information
JoeKar committed Feb 1, 2024
1 parent 7f6733a commit e9effe8
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 29 deletions.
6 changes: 4 additions & 2 deletions internal/buffer/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,11 @@ func (b *SharedBuffer) MarkModified(start, end int) {
end = util.Clamp(end, 0, len(b.lines)-1)

if b.Settings["syntax"].(bool) && b.SyntaxDef != nil {
l := start
for i := start; i <= end; i++ {
b.Highlighter.Highlight(b, start, end)
l = util.Max(b.Highlighter.Highlight(b, i, end, true), l)
}
b.Highlighter.Highlight(b, start, l, false)
}

for i := start; i <= end; i++ {
Expand Down Expand Up @@ -817,7 +819,7 @@ func (b *Buffer) UpdateRules() {
b.Highlighter = highlight.NewHighlighter(b.SyntaxDef)
if b.Settings["syntax"].(bool) {
go func() {
b.Highlighter.Highlight(b, 0, b.End().Y)
b.Highlighter.Highlight(b, 0, b.End().Y, false)
screen.Redraw()
}()
}
Expand Down
80 changes: 53 additions & 27 deletions pkg/highlight/highlighter.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ func findAllIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte) [][]int
return matches
}

func (h *Highlighter) highlightRange(fullHighlights []Group, start int, end int, group Group) {
func (h *Highlighter) highlightRange(fullHighlights []Group, start int, end int, group Group, statesOnly bool) {
if statesOnly {
return
}

if start <= end && end <= len(fullHighlights) {
for i := start; i < end; i++ {
fullHighlights[i] = group
Expand All @@ -100,10 +104,10 @@ func (h *Highlighter) highlightRange(fullHighlights []Group, start int, end int,
}
}

func (h *Highlighter) highlightPatterns(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region) {
func (h *Highlighter) highlightPatterns(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region, statesOnly bool) {
lineLen := util.CharacterCount(line)
// log.Println("highlightPatterns: lineNum:", lineNum, "start:", start, "line:", string(line))
if lineLen == 0 {
if lineLen == 0 || statesOnly {
return
}

Expand All @@ -118,20 +122,20 @@ func (h *Highlighter) highlightPatterns(fullHighlights []Group, start int, lineN
if curRegion == nil || curRegion.group == curRegion.limitGroup || p.group == curRegion.limitGroup {
matches := findAllIndex(p.regex, nil, line)
for _, m := range matches {
h.highlightRange(fullHighlights, start+m[0], start+m[1], p.group)
h.highlightRange(fullHighlights, start+m[0], start+m[1], p.group, statesOnly)
}
}
}
}

func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region, regions []*region, nestedRegion bool) {
func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNum int, line []byte, curRegion *region, regions []*region, nestedRegion bool, statesOnly bool) {
lineLen := util.CharacterCount(line)
// log.Println("highlightRegions: lineNum:", lineNum, "start:", start, "line:", string(line))
if lineLen == 0 {
return
}

h.highlightPatterns(fullHighlights, start, lineNum, line, curRegion)
h.highlightPatterns(fullHighlights, start, lineNum, line, curRegion, statesOnly)

lastStart := 0
regionStart := 0
Expand Down Expand Up @@ -176,8 +180,8 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
// log.Println("start < end")
regionStart = startMatches[startIdx][0]
regionEnd = endMatches[endIdx][1]
h.highlightRange(fullHighlights, start+startMatches[startIdx][0], start+endMatches[endIdx][1], r.limitGroup)
h.highlightRegions(fullHighlights, start+startMatches[startIdx][1], lineNum, util.SliceStartEnd(line, startMatches[startIdx][1], endMatches[endIdx][0]), r, r.rules.regions, true)
h.highlightRange(fullHighlights, start+startMatches[startIdx][0], start+endMatches[endIdx][1], r.limitGroup, statesOnly)
h.highlightRegions(fullHighlights, start+startMatches[startIdx][1], lineNum, util.SliceStartEnd(line, startMatches[startIdx][1], endMatches[endIdx][0]), r, r.rules.regions, true, statesOnly)
if samePattern {
startIdx += 1
}
Expand All @@ -196,9 +200,9 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
}
// start and end at the current line, but switched
// log.Println("end < start")
h.highlightRange(fullHighlights, start, start+endMatches[endIdx][1], r.limitGroup)
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatches[endIdx][0]), r, r.rules.regions, true)
h.highlightPatterns(fullHighlights, start+endMatches[endIdx][1], lineNum, util.SliceStartEnd(line, endMatches[endIdx][1], startMatches[startIdx][0]), nil)
h.highlightRange(fullHighlights, start, start+endMatches[endIdx][1], r.limitGroup, statesOnly)
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatches[endIdx][0]), r, r.rules.regions, true, statesOnly)
h.highlightPatterns(fullHighlights, start+endMatches[endIdx][1], lineNum, util.SliceStartEnd(line, endMatches[endIdx][1], startMatches[startIdx][0]), nil, statesOnly)
if curRegion != nil {
h.lastRegion = curRegion.parent
} else {
Expand All @@ -212,8 +216,8 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
// log.Println("start ...")
regionStart = startMatches[startIdx][0]
regionEnd = 0
h.highlightRange(fullHighlights, start+startMatches[startIdx][0], lineLen, r.limitGroup)
h.highlightRegions(fullHighlights, start+startMatches[startIdx][1], lineNum, util.SliceEnd(line, startMatches[startIdx][1]), r, r.rules.regions, true)
h.highlightRange(fullHighlights, start+startMatches[startIdx][0], lineLen, r.limitGroup, statesOnly)
h.highlightRegions(fullHighlights, start+startMatches[startIdx][1], lineNum, util.SliceEnd(line, startMatches[startIdx][1]), r, r.rules.regions, true, statesOnly)
if lastStart <= startMatches[startIdx][0] {
lastStart = startMatches[startIdx][0]
h.lastRegion = r
Expand All @@ -226,8 +230,8 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
for _, endMatch := range endMatches {
// end at the current, but start at the previous line
// log.Println("... end")
h.highlightRange(fullHighlights, start, start+endMatch[1], r.limitGroup)
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true)
h.highlightRange(fullHighlights, start, start+endMatch[1], r.limitGroup, statesOnly)
h.highlightRegions(fullHighlights, start, lineNum, util.SliceStart(line, endMatch[0]), r, r.rules.regions, true, statesOnly)
if curRegion != nil {
h.lastRegion = curRegion.parent
} else {
Expand All @@ -238,25 +242,27 @@ func (h *Highlighter) highlightRegions(fullHighlights []Group, start int, lineNu
}
} else if len(startMatches) == 0 && len(endMatches) == 0 {
// no start and end found in this region
h.highlightRange(fullHighlights, start, lineLen, curRegion.group)
h.highlightRange(fullHighlights, start, lineLen, curRegion.group, statesOnly)
}
}
}
}

func (h *Highlighter) highlight(highlights LineMatch, start int, lineNum int, line []byte, curRegion *region) LineMatch {
func (h *Highlighter) highlight(highlights LineMatch, start int, lineNum int, line []byte, curRegion *region, statesOnly bool) LineMatch {
lineLen := util.CharacterCount(line)
// log.Println("highlight: lineNum:", lineNum, "start:", start, "line:", string(line))
if lineLen == 0 {
return highlights
}

fullHighlights := make([]Group, lineLen)
h.highlightRegions(fullHighlights, start, lineNum, line, curRegion, h.Def.rules.regions, false)
h.highlightRegions(fullHighlights, start, lineNum, line, curRegion, h.Def.rules.regions, false, statesOnly)

for i, h := range fullHighlights {
if i == 0 || h != fullHighlights[i-1] {
highlights[i] = h
if !statesOnly {
for i, h := range fullHighlights {
if i == 0 || h != fullHighlights[i-1] {
highlights[i] = h
}
}
}

Expand All @@ -274,20 +280,28 @@ func (h *Highlighter) HighlightString(input string) []LineMatch {
for i := 0; i < len(lines); i++ {
line := []byte(lines[i])
highlights := make(LineMatch)
lineMatches = append(lineMatches, h.highlight(highlights, 0, i, line, nil))
lineMatches = append(lineMatches, h.highlight(highlights, 0, i, line, nil, false))
}

return lineMatches
}

// Highlight sets the state and matches for each line from startline to endline
// It sets all other matches in the buffer to nil to conserve memory
func (h *Highlighter) Highlight(input LineStates, startline, endline int) {
// In the moment it is called with statesOnly set it will scan down from
// `startline` and set the appropriate end of line state for each line
// until it comes across a line whose state does not change
// returns the number of the final line
func (h *Highlighter) Highlight(input LineStates, startline, endline int, statesOnly bool) int {
h.lastRegion = nil
if startline > 0 {
h.lastRegion = input.State(startline - 1)
}

if statesOnly {
endline = input.LinesNum() - 1
}

for i := startline; i <= endline; i++ {
if i >= input.LinesNum() {
break
Expand All @@ -297,11 +311,23 @@ func (h *Highlighter) Highlight(input LineStates, startline, endline int) {
highlights := make(LineMatch)

var match LineMatch
match = h.highlight(highlights, 0, i, line, h.lastRegion)
match = h.highlight(highlights, 0, i, line, h.lastRegion, statesOnly)

input.SetState(i, h.lastRegion)
input.SetMatch(i, match)
curState := h.lastRegion
lastState := input.State(i)

input.SetState(i, curState)

if !statesOnly {
input.SetMatch(i, match)
} else {
if curState == lastState {
return i
}
}
}

return input.LinesNum() - 1
}

// ReHighlightLine will rehighlight the state and match for a single line
Expand All @@ -315,7 +341,7 @@ func (h *Highlighter) ReHighlightLine(input LineStates, lineN int) {
}

var match LineMatch
match = h.highlight(highlights, 0, lineN, line, h.lastRegion)
match = h.highlight(highlights, 0, lineN, line, h.lastRegion, false)

input.SetState(lineN, h.lastRegion)
input.SetMatch(lineN, match)
Expand Down

0 comments on commit e9effe8

Please sign in to comment.