4 "github.com/mattn/go-runewidth"
5 "github.com/zyedidia/tcell"
8 func min(a, b int) int {
15 func visualToCharPos(visualIndex int, lineN int, str string, buf *Buffer, tabsize int) (int, int, *tcell.Style) {
19 var style *tcell.Style
22 for i, c := range str {
23 // width := StringWidth(str[:i], tabsize)
25 if group, ok := buf.Match(lineN)[charPos]; ok {
26 s := GetColor(group.String())
30 if width >= visualIndex {
31 return charPos, visualIndex - lastWidth, style
41 rw = tabsize - (lineIdx % tabsize)
44 rw = runewidth.RuneWidth(c)
56 // The actual character that is drawn
57 // This is only different from char if it's for example hidden character
63 type CellView struct {
67 func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
72 matchingBrace := Loc{-1, -1}
73 // bracePairs is defined in buffer.go
74 if buf.Settings["matchbrace"].(bool) {
75 for _, bp := range bracePairs {
76 r := buf.Cursor.RuneUnder(buf.Cursor.X)
77 if r == bp[0] || r == bp[1] {
78 matchingBrace = buf.FindMatchingBrace(bp, buf.Cursor.Loc)
83 tabsize := int(buf.Settings["tabsize"].(float64))
84 softwrap := buf.Settings["softwrap"].(bool)
85 indentrunes := []rune(buf.Settings["indentchar"].(string))
86 // if empty indentchar settings, use space
87 if indentrunes == nil || len(indentrunes) == 0 {
88 indentrunes = []rune{' '}
90 indentchar := indentrunes[0]
93 if buf.Settings["syntax"].(bool) && buf.syntaxDef != nil {
94 if start > 0 && buf.lines[start-1].rehighlight {
95 buf.highlighter.ReHighlightLine(buf, start-1)
96 buf.lines[start-1].rehighlight = false
99 buf.highlighter.ReHighlightStates(buf, start)
101 buf.highlighter.HighlightMatches(buf, top, top+height)
104 c.lines = make([][]*Char, 0)
110 for viewLine < height {
111 if lineN >= len(buf.lines) {
115 lineStr := buf.Line(lineN)
116 line := []rune(lineStr)
118 colN, startOffset, startStyle := visualToCharPos(left, lineN, lineStr, buf, tabsize)
122 viewCol := -startOffset
123 if startStyle != nil {
124 curStyle = *startStyle
127 // We'll either draw the length of the line, or the width of the screen
128 // whichever is smaller
129 lineLength := min(StringWidth(lineStr, tabsize), width)
130 c.lines = append(c.lines, make([]*Char, lineLength))
133 // We only need to wrap if the length of the line is greater than the width of the terminal screen
134 if softwrap && StringWidth(lineStr, tabsize) > width {
136 // We're going to draw the entire line now
137 lineLength = StringWidth(lineStr, tabsize)
140 for viewCol < lineLength {
141 if colN >= len(line) {
144 if group, ok := buf.Match(lineN)[colN]; ok {
145 curStyle = GetColor(group.String())
152 if colN == matchingBrace.X && lineN == matchingBrace.Y && !buf.Cursor.HasSelection() {
153 st = curStyle.Reverse(true)
155 if viewCol < len(c.lines[viewLine]) {
156 c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, st, 1}
160 charWidth := tabsize - (viewCol+left)%tabsize
162 c.lines[viewLine][viewCol].drawChar = indentchar
163 c.lines[viewLine][viewCol].width = charWidth
165 indentStyle := curStyle
166 ch := buf.Settings["indentchar"].(string)
167 if group, ok := colorscheme["indent-char"]; ok && !IsStrWhitespace(ch) && ch != "" {
171 c.lines[viewLine][viewCol].style = indentStyle
174 for i := 1; i < charWidth; i++ {
176 if viewCol >= 0 && viewCol < lineLength && viewCol < len(c.lines[viewLine]) {
177 c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, ' ', curStyle, 1}
181 } else if runewidth.RuneWidth(char) > 1 {
182 charWidth := runewidth.RuneWidth(char)
184 c.lines[viewLine][viewCol].width = charWidth
186 for i := 1; i < charWidth; i++ {
188 if viewCol >= 0 && viewCol < lineLength && viewCol < len(c.lines[viewLine]) {
189 c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, ' ', curStyle, 1}
198 if wrap && viewCol >= width {
201 // If we go too far soft wrapping we have to cut off
202 if viewLine >= height {
206 nextLine := line[colN:]
207 lineLength := min(StringWidth(string(nextLine), tabsize), width)
208 c.lines = append(c.lines, make([]*Char, lineLength))
214 if group, ok := buf.Match(lineN)[len(line)]; ok {
215 curStyle = GetColor(group.String())
223 for i := top; i < top+height; i++ {
224 if i >= buf.NumLines {