1
0
Fork 0
gilo/editor/document/row.go

174 lines
3.0 KiB
Go
Raw Normal View History

2021-04-02 15:36:43 -04:00
package document
2021-03-30 16:05:33 -04:00
2021-04-01 16:17:13 -04:00
import (
"strings"
2021-04-07 13:10:40 -04:00
"timshome.page/gilo/editor/highlight"
2021-04-13 14:43:31 -04:00
"timshome.page/gilo/internal/gilo"
"timshome.page/gilo/key"
"unicode"
2021-04-01 16:17:13 -04:00
)
2021-04-02 14:52:44 -04:00
type Row struct {
chars []rune
render []rune
Hl []int
2021-03-30 16:05:33 -04:00
}
2021-04-02 14:52:44 -04:00
func newRow(s string) *Row {
2021-03-30 18:00:06 -04:00
var chars []rune
var render []rune
2021-03-30 18:00:06 -04:00
for _, ch := range s {
chars = append(chars, ch)
render = append(render, ch)
2021-03-30 18:00:06 -04:00
}
return &Row{chars, render, []int{}}
2021-03-30 16:05:33 -04:00
}
2021-04-02 14:52:44 -04:00
func (r *Row) Size() int {
2021-03-30 16:05:33 -04:00
return len(r.chars)
}
2021-04-02 14:52:44 -04:00
func (r *Row) RenderSize() int {
return len(r.render)
}
2021-04-13 14:43:31 -04:00
func (r *Row) Render(at *gilo.Point) string {
2021-04-02 15:36:43 -04:00
return string(r.render[at.X:])
}
2021-04-06 10:59:24 -04:00
func (r *Row) Search(query string) int {
return strings.Index(string(r.render), query)
}
2021-04-02 14:52:44 -04:00
func (r *Row) insertRune(ch rune, at int) {
2021-04-01 16:17:13 -04:00
// If insertion index is invalid, just
// append the rune to the end of the array
2021-04-02 14:52:44 -04:00
if at < 0 || at >= r.Size() {
2021-04-01 16:17:13 -04:00
r.chars = append(r.chars, ch)
r.update()
return
}
var newSlice []rune
// Split the character array at the insertion point
start := r.chars[0:at]
2021-04-02 14:52:44 -04:00
end := r.chars[at:r.Size()]
2021-04-01 16:17:13 -04:00
// Splice it back together
newSlice = append(newSlice, start...)
newSlice = append(newSlice, ch)
newSlice = append(newSlice, end...)
r.chars = newSlice
r.update()
}
func (r *Row) appendString(str string) {
for _, ch := range str {
r.chars = append(r.chars, ch)
}
r.update()
}
2021-04-02 14:52:44 -04:00
func (r *Row) deleteRune(at int) {
if at < 0 || at >= r.Size() {
2021-04-02 10:48:51 -04:00
return
}
var newSlice []rune
// Split the character array at the insertion point
start := r.chars[0:at]
2021-04-02 14:52:44 -04:00
end := r.chars[at+1 : r.Size()] // Skip the index in question
2021-04-02 10:48:51 -04:00
// Splice it back together
newSlice = append(newSlice, start...)
newSlice = append(newSlice, end...)
r.chars = newSlice
r.update()
}
2021-04-02 14:52:44 -04:00
func (r *Row) update() {
r.render = r.render[:0]
2021-04-13 14:43:31 -04:00
replacement := strings.Repeat(" ", gilo.TabSize)
str := strings.ReplaceAll(string(r.chars), "\t", replacement)
for _, ch := range str {
r.render = append(r.render, ch)
}
r.updateSyntax()
}
func (r *Row) updateSyntax() {
i := 0
2021-04-13 14:43:31 -04:00
prevSep := true
r.Hl = make([]int, r.RenderSize())
for i < r.RenderSize() {
ch := r.render[i]
2021-04-13 14:43:31 -04:00
prevHl := highlight.Normal
if i > 0 {
2021-04-16 11:46:16 -04:00
prevHl = r.Hl[i-1]
2021-04-13 14:43:31 -04:00
}
if (unicode.IsDigit(ch) && (prevSep || prevHl == highlight.Number)) ||
(ch == '.' && prevHl == highlight.Number) {
r.Hl[i] = highlight.Number
2021-04-13 14:43:31 -04:00
i += 1
prevSep = false
continue
} else {
r.Hl[i] = highlight.Normal
}
2021-04-13 14:43:31 -04:00
prevSep = key.IsSeparator(ch)
i++
}
}
2021-03-30 16:05:33 -04:00
2021-04-02 14:52:44 -04:00
func (r *Row) toString() string {
2021-04-01 16:17:13 -04:00
return string(r.chars)
}
2021-04-02 15:36:43 -04:00
func (r *Row) CursorXToRenderX(cursorX int) (renderX int) {
renderX = 0
2021-03-31 14:56:46 -04:00
2021-04-07 12:02:08 -04:00
for i := 0; i < cursorX; i++ {
2021-03-31 14:56:46 -04:00
if r.chars[i] == '\t' {
2021-04-13 14:43:31 -04:00
renderX += (gilo.TabSize - 1) - (renderX % gilo.TabSize)
2021-03-31 14:56:46 -04:00
}
renderX += 1
}
return renderX
2021-04-01 16:17:13 -04:00
}
2021-04-06 10:59:24 -04:00
func (r *Row) RenderXtoCursorX(renderX int) (cursorX int) {
currentRenderX := 0
cursorX = 0
for cursorX = 0; cursorX < r.Size(); cursorX++ {
if r.chars[cursorX] == '\t' {
2021-04-13 14:43:31 -04:00
currentRenderX += (gilo.TabSize - 1) - (currentRenderX % gilo.TabSize)
2021-04-06 10:59:24 -04:00
} else {
currentRenderX += 1
}
if currentRenderX > renderX {
return cursorX
}
}
return cursorX
2021-04-07 12:32:57 -04:00
}