Highlighter: fix bug causing out of bounds access when endLine > len of internal lines

This commit is contained in:
Luke I. Wilson 2021-04-01 16:19:14 -05:00
parent 239793aa2c
commit a4d5f3ccf4

View File

@ -67,13 +67,21 @@ func NewHighlighter(buffer Buffer, lang *Language, colorscheme *Colorscheme) *Hi
} }
} }
func (h *Highlighter) expandToBufferLines() {
if lines := h.Buffer.Lines(); len(h.lineMatches) < lines {
h.lineMatches = append(h.lineMatches, make([][]Match, lines-len(h.lineMatches))...) // Extend from Slice Tricks
}
}
// UpdateLines forces the highlighting matches for lines between startLine to // UpdateLines forces the highlighting matches for lines between startLine to
// endLine, inclusively, to be updated. It is more efficient to mark lines as // endLine, inclusively, to be updated. It is more efficient to mark lines as
// invalidated when changes occur and call UpdateInvalidatedLines(...). // invalidated when changes occur and call UpdateInvalidatedLines(...).
func (h *Highlighter) UpdateLines(startLine, endLine int) { func (h *Highlighter) UpdateLines(startLine, endLine int) {
if lines := h.Buffer.Lines(); len(h.lineMatches) < lines { h.expandToBufferLines()
h.lineMatches = append(h.lineMatches, make([][]Match, lines)...) // Extend h.updateLines(startLine, endLine)
} }
func (h *Highlighter) updateLines(startLine, endLine int) {
for i := startLine; i <= endLine && i < len(h.lineMatches); i++ { for i := startLine; i <= endLine && i < len(h.lineMatches); i++ {
if h.lineMatches[i] != nil { if h.lineMatches[i] != nil {
h.lineMatches[i] = h.lineMatches[i][:0] // Shrink slice to zero (hopefully save allocs) h.lineMatches[i] = h.lineMatches[i][:0] // Shrink slice to zero (hopefully save allocs)
@ -118,6 +126,8 @@ func (h *Highlighter) UpdateLines(startLine, endLine int) {
// UpdateInvalidatedLines only updates the highlighting for lines that are invalidated // UpdateInvalidatedLines only updates the highlighting for lines that are invalidated
// between lines startLine and endLine, inclusively. // between lines startLine and endLine, inclusively.
func (h *Highlighter) UpdateInvalidatedLines(startLine, endLine int) { func (h *Highlighter) UpdateInvalidatedLines(startLine, endLine int) {
h.expandToBufferLines()
// Move startLine to first line with invalidated changes // Move startLine to first line with invalidated changes
for startLine <= endLine && startLine < len(h.lineMatches)-1 { for startLine <= endLine && startLine < len(h.lineMatches)-1 {
if h.lineMatches[startLine] == nil { if h.lineMatches[startLine] == nil {
@ -126,6 +136,11 @@ func (h *Highlighter) UpdateInvalidatedLines(startLine, endLine int) {
startLine++ startLine++
} }
// Keep endLine clamped
if endLine >= len(h.lineMatches) {
endLine = len(h.lineMatches)-1
}
// Move endLine back to first line at or before endLine with invalidated changes // Move endLine back to first line at or before endLine with invalidated changes
for endLine >= startLine && endLine > 0 { for endLine >= startLine && endLine > 0 {
if h.lineMatches[endLine] == nil { if h.lineMatches[endLine] == nil {
@ -138,10 +153,11 @@ func (h *Highlighter) UpdateInvalidatedLines(startLine, endLine int) {
return // Do nothing; no invalidated lines return // Do nothing; no invalidated lines
} }
h.UpdateLines(startLine, endLine) h.updateLines(startLine, endLine)
} }
func (h *Highlighter) HasInvalidatedLines(startLine, endLine int) bool { func (h *Highlighter) HasInvalidatedLines(startLine, endLine int) bool {
h.expandToBufferLines()
for i := startLine; i <= endLine && i < len(h.lineMatches); i++ { for i := startLine; i <= endLine && i < len(h.lineMatches); i++ {
if h.lineMatches[i] == nil { if h.lineMatches[i] == nil {
return true return true
@ -159,6 +175,7 @@ func (h *Highlighter) validateLines(startLine, endLine int) {
} }
func (h *Highlighter) InvalidateLines(startLine, endLine int) { func (h *Highlighter) InvalidateLines(startLine, endLine int) {
h.expandToBufferLines()
for i := startLine; i <= endLine && i < len(h.lineMatches); i++ { for i := startLine; i <= endLine && i < len(h.lineMatches); i++ {
h.lineMatches[i] = nil h.lineMatches[i] = nil
} }