mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-07 05:10:23 +09:00
143 lines
3.1 KiB
Go
143 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/mattn/go-runewidth"
|
|
"github.com/zyedidia/tcell"
|
|
)
|
|
|
|
func min(a, b int) int {
|
|
if a <= b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func VisualToCharPos(visualIndex int, str string, tabsize int) int {
|
|
visualPos := 0
|
|
charPos := 0
|
|
for _, c := range str {
|
|
width := StringWidth(string(c), tabsize)
|
|
|
|
if visualPos+width > visualIndex {
|
|
return charPos
|
|
}
|
|
|
|
visualPos += width
|
|
charPos++
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
type Char struct {
|
|
visualLoc Loc
|
|
realLoc Loc
|
|
char rune
|
|
// The actual character that is drawn
|
|
// This is only different from char if it's for example hidden character
|
|
drawChar rune
|
|
style tcell.Style
|
|
}
|
|
|
|
type CellView struct {
|
|
lines [][]*Char
|
|
}
|
|
|
|
func (c *CellView) Draw(buf *Buffer, top, height, left, width int) {
|
|
tabsize := int(buf.Settings["tabsize"].(float64))
|
|
softwrap := buf.Settings["softwrap"].(bool)
|
|
indentchar := []rune(buf.Settings["indentchar"].(string))[0]
|
|
|
|
start := buf.Cursor.Y
|
|
if buf.Settings["syntax"].(bool) {
|
|
startTime := time.Now()
|
|
if start > 0 && buf.lines[start-1].rehighlight {
|
|
buf.highlighter.ReHighlightLine(buf, start-1)
|
|
buf.lines[start-1].rehighlight = false
|
|
}
|
|
|
|
buf.highlighter.ReHighlight(buf, start)
|
|
elapsed := time.Since(startTime)
|
|
messenger.Message("Rehighlighted in ", elapsed)
|
|
}
|
|
|
|
c.lines = make([][]*Char, 0)
|
|
|
|
viewLine := 0
|
|
lineN := top
|
|
|
|
curStyle := defStyle
|
|
for viewLine < height {
|
|
if lineN >= len(buf.lines) {
|
|
break
|
|
}
|
|
|
|
lineStr := buf.Line(lineN)
|
|
line := []rune(lineStr)
|
|
|
|
colN := VisualToCharPos(left, lineStr, tabsize)
|
|
viewCol := 0
|
|
|
|
// We'll either draw the length of the line, or the width of the screen
|
|
// whichever is smaller
|
|
lineLength := min(StringWidth(lineStr, tabsize), width)
|
|
c.lines = append(c.lines, make([]*Char, lineLength))
|
|
|
|
wrap := false
|
|
// We only need to wrap if the length of the line is greater than the width of the terminal screen
|
|
if softwrap && StringWidth(lineStr, tabsize) > width {
|
|
wrap = true
|
|
// We're going to draw the entire line now
|
|
lineLength = StringWidth(lineStr, tabsize)
|
|
}
|
|
|
|
for viewCol < lineLength {
|
|
if colN >= len(line) {
|
|
break
|
|
}
|
|
if group, ok := buf.Match(lineN)[colN]; ok {
|
|
curStyle = GetColor(group)
|
|
}
|
|
|
|
char := line[colN]
|
|
|
|
if char == '\t' {
|
|
c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, indentchar, curStyle}
|
|
viewCol += tabsize - viewCol%tabsize
|
|
} else if runewidth.RuneWidth(char) > 1 {
|
|
c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, curStyle}
|
|
viewCol += runewidth.RuneWidth(char)
|
|
} else {
|
|
c.lines[viewLine][viewCol] = &Char{Loc{viewCol, viewLine}, Loc{colN, lineN}, char, char, curStyle}
|
|
viewCol++
|
|
}
|
|
colN++
|
|
|
|
if wrap && viewCol >= width {
|
|
viewLine++
|
|
|
|
// If we go too far soft wrapping we have to cut off
|
|
if viewLine >= height {
|
|
break
|
|
}
|
|
|
|
nextLine := line[colN:]
|
|
lineLength := min(StringWidth(string(nextLine), tabsize), width)
|
|
c.lines = append(c.lines, make([]*Char, lineLength))
|
|
|
|
viewCol = 0
|
|
}
|
|
|
|
}
|
|
if group, ok := buf.Match(lineN)[len(line)]; ok {
|
|
curStyle = GetColor(group)
|
|
}
|
|
|
|
// newline
|
|
viewLine++
|
|
lineN++
|
|
}
|
|
}
|