From ff039df5d06e1ddc724d276aa1257357da334eb7 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Fri, 25 Mar 2016 19:18:29 -0400 Subject: [PATCH] Working by-line syntax highlighting --- src/highlighter.go | 79 ++++++++++++++++++++++++++++++---------------- src/view.go | 21 ++++++------ 2 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/highlighter.go b/src/highlighter.go index 5fb6dcbb..32ed0943 100644 --- a/src/highlighter.go +++ b/src/highlighter.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "path/filepath" "regexp" + "strconv" "strings" ) @@ -208,17 +209,24 @@ func GetRules(buf *Buffer) ([]SyntaxRule, string) { // SyntaxMatches is an alias to a map from character numbers to styles, // so map[3] represents the style of the third character -type SyntaxMatches map[int]tcell.Style +type SyntaxMatches [][]tcell.Style // Match takes a buffer and returns the syntax matches a map specifying how it should be syntax highlighted -func Match(rules []SyntaxRule, buf *Buffer, v *View) SyntaxMatches { - m := make(SyntaxMatches) +func Match(v *View) SyntaxMatches { + buf := v.buf + rules := v.buf.rules - lineStart := v.updateLines[0] - lineEnd := v.updateLines[1] + 1 - if lineStart < 0 { - // Don't need to update syntax highlighting - return m + viewStart := v.topline + viewEnd := v.topline + v.height + if viewEnd > len(buf.lines) { + viewEnd = len(buf.lines) + } + + lines := buf.lines[viewStart:viewEnd] + matches := make(SyntaxMatches, len(lines)) + + for i, line := range lines { + matches[i] = make([]tcell.Style, len(line)) } totalStart := v.topline - synLinesUp @@ -230,35 +238,35 @@ func Match(rules []SyntaxRule, buf *Buffer, v *View) SyntaxMatches { totalEnd = len(buf.lines) } - if lineEnd > len(buf.lines) { - lineEnd = len(buf.lines) - } - - lines := buf.lines[lineStart:lineEnd] str := strings.Join(buf.lines[totalStart:totalEnd], "\n") startNum := v.cursor.loc + v.cursor.Distance(0, totalStart) toplineNum := v.cursor.loc + v.cursor.Distance(0, v.topline) + for _, rule := range rules { - if rule.startend && rule.regex.MatchString(str) { - indicies := rule.regex.FindAllStringIndex(str, -1) - for _, value := range indicies { - value[0] += startNum - value[1] += startNum - for i := value[0]; i < value[1]; i++ { - if i >= toplineNum { - m[i] = rule.style + if rule.startend { + if rule.regex.MatchString(str) { + indicies := rule.regex.FindAllStringIndex(str, -1) + for _, value := range indicies { + value[0] += startNum + value[1] += startNum + for i := value[0]; i < value[1]; i++ { + colNum, lineNum := GetPos(i, buf) + v.m.Message(strconv.Itoa(lineNum) + ", " + strconv.Itoa(colNum)) + if i >= toplineNum { + if lineNum != -1 && colNum != -1 { + matches[lineNum][colNum] = rule.style + } + } } } } } else { - for _, line := range lines { + for lineN, line := range lines { if rule.regex.MatchString(line) { - indicies := rule.regex.FindAllStringIndex(str, -1) + indicies := rule.regex.FindAllStringIndex(line, -1) for _, value := range indicies { - value[0] += toplineNum - value[1] += toplineNum for i := value[0]; i < value[1]; i++ { - m[i] = rule.style + matches[lineN][i] = rule.style } } } @@ -266,5 +274,22 @@ func Match(rules []SyntaxRule, buf *Buffer, v *View) SyntaxMatches { } } - return m + return matches +} + +// GetPos returns an x, y position given a character location in the buffer +func GetPos(loc int, buf *Buffer) (int, int) { + charNum := 0 + x, y := 0, 0 + + for i, line := range buf.lines { + if charNum+Count(line) > loc { + y = i + x = loc - charNum + return x, y + } + charNum += Count(line) + 1 + } + + return -1, -1 } diff --git a/src/view.go b/src/view.go index 10704595..936814b6 100644 --- a/src/view.go +++ b/src/view.go @@ -91,7 +91,7 @@ func NewViewWidthHeight(buf *Buffer, m *Messenger, w, h int) *View { // Update the syntax highlighting for the entire buffer at the start v.UpdateLines(v.topline, v.topline+v.height) - // v.matches = Match(v.buf.rules, v.buf, v) + v.matches = Match(v) // Set mouseReleased to true because we assume the mouse is not being pressed when // the editor is opened @@ -407,12 +407,16 @@ func (v *View) HandleEvent(event tcell.Event) { v.UpdateLines(v.topline, v.topline+v.height) case tcell.KeyPgUp: v.PageUp() + relocate = false case tcell.KeyPgDn: v.PageDown() + relocate = false case tcell.KeyCtrlU: v.HalfPageUp() + relocate = false case tcell.KeyCtrlD: v.HalfPageDown() + relocate = false case tcell.KeyRune: // Insert a character if v.cursor.HasSelection() { @@ -479,12 +483,12 @@ func (v *View) HandleEvent(event tcell.Event) { v.Relocate() } - // v.matches = Match(v.buf.rules, v.buf, v) + v.matches = Match(v) } // DisplayView renders the view to the screen func (v *View) DisplayView() { - matches := make(SyntaxMatches) + matches := make(SyntaxMatches, len(v.matches)) // The character number of the character in the top left of the screen charNum := v.cursor.loc + v.cursor.Distance(0, v.topline) @@ -528,17 +532,10 @@ func (v *View) DisplayView() { // Write the line tabchars := 0 - for _, ch := range line { + for colN, ch := range line { var lineStyle tcell.Style // Does the current character need to be syntax highlighted? - if st, ok := v.matches[charNum]; ok { - highlightStyle = st - } else if st, ok := v.lastMatches[charNum]; ok { - highlightStyle = st - } else { - highlightStyle = tcell.StyleDefault - } - matches[charNum] = highlightStyle + highlightStyle = v.matches[lineN][colN] if v.cursor.HasSelection() && (charNum >= v.cursor.selectionStart && charNum <= v.cursor.selectionEnd ||