]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/cellview.go
Update readme
[micro.git] / cmd / micro / cellview.go
index 5d03ade37bc3b2cae166761179509a0ec992005a..b0cb6523c3602312b9ba8470d7cae65e83e12ed6 100644 (file)
@@ -1,8 +1,6 @@
 package main
 
 import (
-       "time"
-
        "github.com/mattn/go-runewidth"
        "github.com/zyedidia/tcell"
 )
@@ -14,28 +12,52 @@ func min(a, b int) int {
        return b
 }
 
-func VisualToCharPos(visualIndex int, str string, tabsize int) int {
-       visualPos := 0
+func visualToCharPos(visualIndex int, lineN int, str string, buf *Buffer, tabsize int) (int, int, *tcell.Style) {
        charPos := 0
-       for _, c := range str {
-               width := StringWidth(string(c), tabsize)
+       var lineIdx int
+       var lastWidth int
+       var style *tcell.Style
+       var width int
+       var rw int
+       for i, c := range str {
+               // width := StringWidth(str[:i], tabsize)
+
+               if group, ok := buf.Match(lineN)[charPos]; ok {
+                       s := GetColor(group.String())
+                       style = &s
+               }
 
-               if visualPos+width > visualIndex {
-                       return charPos
+               if width >= visualIndex {
+                       return charPos, visualIndex - lastWidth, style
                }
 
-               visualPos += width
-               charPos++
+               if i != 0 {
+                       charPos++
+                       lineIdx += rw
+               }
+               lastWidth = width
+               rw = 0
+               if c == '\t' {
+                       rw = tabsize - (lineIdx % tabsize)
+                       width += rw
+               } else {
+                       rw = runewidth.RuneWidth(c)
+                       width += rw
+               }
        }
 
-       return 0
+       return -1, -1, style
 }
 
 type Char struct {
        visualLoc Loc
        realLoc   Loc
        char      rune
-       style     tcell.Style
+       // The actual character that is drawn
+       // This is only different from char if it's for example hidden character
+       drawChar rune
+       style    tcell.Style
+       width    int
 }
 
 type CellView struct {
@@ -43,18 +65,50 @@ type CellView struct {
 }
 
 func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
+       if width <= 0 {
+               return
+       }
+
+       matchingBrace := Loc{-1, -1}
+       // bracePairs is defined in buffer.go
+       if buf.Settings["matchbrace"].(bool) {
+               for _, bp := range bracePairs {
+                       curX := buf.Cursor.X
+                       curLoc := buf.Cursor.Loc
+                       if buf.Settings["matchbraceleft"].(bool) {
+                               if curX > 0 {
+                                       curX--
+                                       curLoc = curLoc.Move(-1, buf)
+                               }
+                       }
+
+                       r := buf.Cursor.RuneUnder(curX)
+                       if r == bp[0] || r == bp[1] {
+                               matchingBrace = buf.FindMatchingBrace(bp, curLoc)
+                       }
+               }
+       }
+
        tabsize := int(buf.Settings["tabsize"].(float64))
        softwrap := buf.Settings["softwrap"].(bool)
-       indentchar := []rune(buf.Settings["indentchar"].(string))[0]
+       indentrunes := []rune(buf.Settings["indentchar"].(string))
+       // if empty indentchar settings, use space
+       if indentrunes == nil || len(indentrunes) == 0 {
+               indentrunes = []rune{' '}
+       }
+       indentchar := indentrunes[0]
 
        start := buf.Cursor.Y
-       startTime := time.Now()
-       matches := buf.highlighter.ReHighlight(buf, start)
-       elapsed := time.Since(startTime)
-       for i, m := range matches {
-               buf.matches[start+i] = m
+       if buf.Settings["syntax"].(bool) && buf.syntaxDef != nil {
+               if start > 0 && buf.lines[start-1].rehighlight {
+                       buf.highlighter.ReHighlightLine(buf, start-1)
+                       buf.lines[start-1].rehighlight = false
+               }
+
+               buf.highlighter.ReHighlightStates(buf, start)
+
+               buf.highlighter.HighlightMatches(buf, top, top+height)
        }
-       messenger.Message("Rehighlighted ", len(matches), " lines in ", elapsed)
 
        c.lines = make([][]*Char, 0)
 
@@ -70,8 +124,14 @@ func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
                lineStr := buf.Line(lineN)
                line := []rune(lineStr)
 
-               colN := VisualToCharPos(left, lineStr, tabsize)
-               viewCol := 0
+               colN, startOffset, startStyle := visualToCharPos(left, lineN, lineStr, buf, tabsize)
+               if colN < 0 {
+                       colN = len(line)
+               }
+               viewCol := -startOffset
+               if startStyle != nil {
+                       curStyle = *startStyle
+               }
 
                // We'll either draw the length of the line, or the width of the screen
                // whichever is smaller
@@ -90,21 +150,56 @@ func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
                        if colN >= len(line) {
                                break
                        }
-                       if group, ok := buf.matches[lineN][colN]; ok {
-                               curStyle = GetColor(group)
+                       if group, ok := buf.Match(lineN)[colN]; ok {
+                               curStyle = GetColor(group.String())
                        }
 
                        char := line[colN]
 
+                       if viewCol >= 0 {
+                               st := curStyle
+                               if colN == matchingBrace.X && lineN == matchingBrace.Y && !buf.Cursor.HasSelection() {
+                                       st = curStyle.Reverse(true)
+                               }
+                               if viewCol < len(c.lines[viewLine]) {
+                                       c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, st, 1}
+                               }
+                       }
                        if char == '\t' {
-                               c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, indentchar, curStyle}
-                               // TODO: this always adds 4 spaces but it should really add just the remainder to the next tab location
-                               viewCol += tabsize
+                               charWidth := tabsize - (viewCol+left)%tabsize
+                               if viewCol >= 0 {
+                                       c.lines[viewLine][viewCol].drawChar = indentchar
+                                       c.lines[viewLine][viewCol].width = charWidth
+
+                                       indentStyle := curStyle
+                                       ch := buf.Settings["indentchar"].(string)
+                                       if group, ok := colorscheme["indent-char"]; ok && !IsStrWhitespace(ch) && ch != "" {
+                                               indentStyle = group
+                                       }
+
+                                       c.lines[viewLine][viewCol].style = indentStyle
+                               }
+
+                               for i := 1; i < charWidth; i++ {
+                                       viewCol++
+                                       if viewCol >= 0 && viewCol < lineLength && viewCol < len(c.lines[viewLine]) {
+                                               c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, ' ', curStyle, 1}
+                                       }
+                               }
+                               viewCol++
                        } else if runewidth.RuneWidth(char) > 1 {
-                               c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, curStyle}
-                               viewCol += runewidth.RuneWidth(char)
+                               charWidth := runewidth.RuneWidth(char)
+                               if viewCol >= 0 {
+                                       c.lines[viewLine][viewCol].width = charWidth
+                               }
+                               for i := 1; i < charWidth; i++ {
+                                       viewCol++
+                                       if viewCol >= 0 && viewCol < lineLength && viewCol < len(c.lines[viewLine]) {
+                                               c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, ' ', curStyle, 1}
+                                       }
+                               }
+                               viewCol++
                        } else {
-                               c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, curStyle}
                                viewCol++
                        }
                        colN++
@@ -125,12 +220,19 @@ func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
                        }
 
                }
-               if group, ok := buf.matches[lineN][len(line)]; ok {
-                       curStyle = GetColor(group)
+               if group, ok := buf.Match(lineN)[len(line)]; ok {
+                       curStyle = GetColor(group.String())
                }
 
                // newline
                viewLine++
                lineN++
        }
+
+       for i := top; i < top+height; i++ {
+               if i >= buf.NumLines {
+                       break
+               }
+               buf.SetMatch(i, nil)
+       }
 }