func (la *LineArray) JoinLines(a, b int) {
	la.insert(Loc{len(la.lines[a].data), a}, la.lines[b].data)
	la.DeleteLine(b)
}
JoinLines joins the two lines a and b
package editor
import (
	"bufio"
	"io"
	"unicode/utf8"
	"github.com/askovpen/gossiped/pkg/highlight"
)
func runeToByteIndex(n int, txt []byte) int {
	if n == 0 {
		return 0
	}
	count := 0
	i := 0
	for len(txt) > 0 {
		_, size := utf8.DecodeRune(txt)
		txt = txt[size:]
		count += size
		i++
		if i == n {
			break
		}
	}
	return count
}
type Line struct {
	data []byte
	state       highlight.State
	match       highlight.LineMatch
	rehighlight bool
}
type LineArray struct {
	lines []Line
}
func Append(slice []Line, data ...Line) []Line {
	l := len(slice)
	if l+len(data) > cap(slice) {  
		newSlice := make([]Line, (l+len(data))+10000)
		copy(newSlice, slice)
		slice = newSlice
	}
	slice = slice[0 : l+len(data)]
	for i, c := range data {
		slice[l+i] = c
	}
	return slice
}
func NewLineArray(size int64, reader io.Reader) *LineArray {
	la := new(LineArray)
	la.lines = make([]Line, 0, 1000)
	br := bufio.NewReader(reader)
	var loaded int
	n := 0
	for {
		data, err := br.ReadBytes('\n')
		if len(data) > 1 && data[len(data)-2] == '\r' {
			data = append(data[:len(data)-2], '\n')
			if fileformat == 0 {
				fileformat = 2
			}
		} else if len(data) > 0 {
			if fileformat == 0 {
				fileformat = 1
			}
		}
		if n >= 1000 && loaded >= 0 {
			totalLinesNum := int(float64(size) * (float64(n) / float64(loaded)))
			newSlice := make([]Line, len(la.lines), totalLinesNum+10000)
			copy(newSlice, la.lines)
			la.lines = newSlice
			loaded = -1
		}
		if loaded >= 0 {
			loaded += len(data)
		}
		if err != nil {
			if err == io.EOF {
				la.lines = Append(la.lines, Line{data, nil, nil, false})
			}
			break
		} else {
			la.lines = Append(la.lines, Line{data[:len(data)-1], nil, nil, false})
		}
		n++
	}
	return la
}
func (la *LineArray) String() string {
	str := ""
	for i, l := range la.lines {
		str += string(l.data)
		if i != len(la.lines)-1 {
			str += "\n"
		}
	}
	return str
}
func (la *LineArray) SaveString(useCrlf bool) string {
	str := ""
	for i, l := range la.lines {
		str += string(l.data)
		if i != len(la.lines)-1 {
			if useCrlf {
				str += "\r"
			}
			str += "\n"
		}
	}
	return str
}
func (la *LineArray) NewlineBelow(y int) {
	la.lines = append(la.lines, Line{[]byte{' '}, nil, nil, false})
	copy(la.lines[y+2:], la.lines[y+1:])
	la.lines[y+1] = Line{[]byte{}, la.lines[y].state, nil, false}
}
func (la *LineArray) insert(pos Loc, value []byte) {
	x, y := runeToByteIndex(pos.X, la.lines[pos.Y].data), pos.Y
	for i := 0; i < len(value); i++ {
		if value[i] == '\n' {
			la.Split(Loc{x, y})
			x = 0
			y++
			continue
		}
		la.insertByte(Loc{x, y}, value[i])
		x++
	}
}
func (la *LineArray) insertByte(pos Loc, value byte) {
	la.lines[pos.Y].data = append(la.lines[pos.Y].data, 0)
	copy(la.lines[pos.Y].data[pos.X+1:], la.lines[pos.Y].data[pos.X:])
	la.lines[pos.Y].data[pos.X] = value
}