mirror of https://github.com/lapce/lapce.git
183 lines
3.7 KiB
Go
183 lines
3.7 KiB
Go
package plugin
|
|
|
|
import (
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
// Line is
|
|
type Line struct {
|
|
Text string
|
|
length int
|
|
}
|
|
|
|
// LineCache is
|
|
type LineCache struct {
|
|
NbLines int
|
|
ViewID string
|
|
Lines []*Line
|
|
Raw []byte
|
|
}
|
|
|
|
// View is
|
|
type View struct {
|
|
Rev uint64
|
|
Row int
|
|
Col int
|
|
Offset int
|
|
ID string
|
|
Path string
|
|
Syntax string
|
|
LineCache *LineCache
|
|
}
|
|
|
|
// SetRaw sets
|
|
func (v *View) SetRaw(raw []byte) {
|
|
l := v.LineCache
|
|
l.Raw = raw
|
|
lines := []*Line{}
|
|
lineRunes := []rune{}
|
|
for _, c := range []rune(*(*string)(unsafe.Pointer(&raw))) {
|
|
lineRunes = append(lineRunes, c)
|
|
if c == '\n' {
|
|
line := &Line{
|
|
Text: string(lineRunes),
|
|
}
|
|
line.length = len(line.Text)
|
|
lines = append(lines, line)
|
|
lineRunes = []rune{}
|
|
}
|
|
}
|
|
if len(lineRunes) > 0 {
|
|
line := &Line{
|
|
Text: string(lineRunes),
|
|
}
|
|
line.length = len(line.Text)
|
|
lines = append(lines, line)
|
|
}
|
|
l.Lines = lines
|
|
}
|
|
|
|
// ApplyUpdate applies update
|
|
func (v *View) ApplyUpdate(update *Update) (int, int, int, int, string, string, bool) {
|
|
l := v.LineCache
|
|
v.Rev = update.Rev
|
|
i := 0
|
|
startCopy := update.Delta.Els[i].Copy
|
|
startOffset := 0
|
|
if startCopy != nil {
|
|
i++
|
|
startOffset = startCopy[1]
|
|
}
|
|
startRow, startCol := v.GetPos(startOffset)
|
|
text := ""
|
|
deletedText := ""
|
|
if i < len(update.Delta.Els) {
|
|
text = update.Delta.Els[i].Insert
|
|
if text != "" {
|
|
i++
|
|
}
|
|
}
|
|
endOffset := len(l.Raw)
|
|
if i < len(update.Delta.Els) {
|
|
endCopyEl := update.Delta.Els[i]
|
|
endOffset = endCopyEl.Copy[0]
|
|
}
|
|
endRow, endCol := v.GetPos(endOffset)
|
|
if startOffset == endOffset && text == "" {
|
|
return startRow, startCol, endRow, endCol, text, deletedText, false
|
|
}
|
|
|
|
deletedText = string(l.Raw[startOffset:endOffset])
|
|
diff := endOffset - startOffset
|
|
if diff < len(text) {
|
|
for i := 0; i < len(text)-diff; i++ {
|
|
l.Raw = append(l.Raw, 0)
|
|
}
|
|
}
|
|
copy(l.Raw[startOffset+len(text):], l.Raw[endOffset:])
|
|
copy(l.Raw[startOffset:startOffset+len(text)], []byte(text))
|
|
if diff > len(text) {
|
|
l.Raw = l.Raw[:len(l.Raw)-(diff-len(text))]
|
|
}
|
|
|
|
oldN := endRow - startRow
|
|
|
|
newLines := strings.Split(text, "\n")
|
|
for i := range newLines {
|
|
if i < len(newLines)-1 {
|
|
newLines[i] += "\n"
|
|
}
|
|
}
|
|
newN := len(newLines) - 1
|
|
if newN > oldN {
|
|
for i := 0; i < newN-oldN; i++ {
|
|
l.Lines = append(l.Lines, nil)
|
|
}
|
|
copy(l.Lines[startRow+newN:], l.Lines[endRow:])
|
|
}
|
|
|
|
for i := 0; i <= newN; i++ {
|
|
newText := newLines[i]
|
|
idx := startRow + i
|
|
if newN == 0 {
|
|
startLine := l.Lines[startRow]
|
|
endLine := l.Lines[endRow]
|
|
l.Lines[idx] = &Line{
|
|
Text: string(startLine.Text[:startCol]) + newText + string(endLine.Text[endCol:]),
|
|
}
|
|
} else if i == 0 {
|
|
line := l.Lines[startRow]
|
|
l.Lines[idx] = &Line{
|
|
Text: string(line.Text[:startCol]) + newText,
|
|
}
|
|
} else if i == newN {
|
|
line := l.Lines[startRow+newN]
|
|
l.Lines[idx] = &Line{
|
|
Text: newText + string(line.Text[endCol:]),
|
|
}
|
|
} else {
|
|
l.Lines[idx] = &Line{
|
|
Text: newText,
|
|
}
|
|
}
|
|
l.Lines[idx].length = len(l.Lines[idx].Text)
|
|
}
|
|
|
|
if newN < oldN {
|
|
copy(l.Lines[startRow+newN+1:], l.Lines[endRow+1:])
|
|
l.Lines = l.Lines[:len(l.Lines)-(oldN-newN)]
|
|
}
|
|
v.Offset = startOffset + len(text)
|
|
v.Row, v.Col = v.GetPos(v.Offset)
|
|
return startRow, startCol, endRow, endCol, text, deletedText, true
|
|
}
|
|
|
|
// GetPos gets pos
|
|
func (v *View) GetPos(offset int) (int, int) {
|
|
row := 0
|
|
idx := 0
|
|
var line *Line
|
|
for row, line = range v.LineCache.Lines {
|
|
if idx+line.length > offset {
|
|
return row, offset - idx
|
|
}
|
|
idx += line.length
|
|
}
|
|
return row, line.length
|
|
}
|
|
|
|
// GetOffset is
|
|
func (v *View) GetOffset(row, col int) int {
|
|
offset := 0
|
|
lines := v.LineCache.Lines
|
|
for i := 0; i <= row; i++ {
|
|
if i == row {
|
|
offset += col
|
|
return offset
|
|
}
|
|
offset += lines[i].length
|
|
}
|
|
return offset
|
|
}
|