package editor import ( "strings" ) type row struct { chars []rune render []rune } func newRow(s string) *row { var chars []rune var render []rune for _, ch := range s { chars = append(chars, ch) render = append(render, ch) } return &row{chars, render} } func (r *row) size() int { return len(r.chars) } func (r *row) rSize() int { return len(r.render) } func (r *row) insertRune(ch rune, at int) { // If insertion index is invalid, just // append the rune to the end of the array if at < 0 || at >= r.size() { 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] end := r.chars[at:r.size()] // Splice it back together newSlice = append(newSlice, start...) newSlice = append(newSlice, ch) newSlice = append(newSlice, end...) r.chars = newSlice r.update() } func (r *row) deleteRune(at int) { if at < 0 || at >= r.size() { return } var newSlice []rune // Split the character array at the insertion point start := r.chars[0:at] end := r.chars[at+1 : r.size()] // Skip the index in question // Splice it back together newSlice = append(newSlice, start...) newSlice = append(newSlice, end...) r.chars = newSlice r.update() } func (r *row) update() { r.render = r.render[:0] replacement := strings.Repeat(" ", KiloTabStop) str := strings.ReplaceAll(string(r.chars), "\t", replacement) for _, ch := range str { r.render = append(r.render, ch) } } func (r *row) toString() string { return string(r.chars) } func (r *row) cursorXToRenderX(cursorX int) int { renderX := 0 i := 0 for ; i < cursorX; i++ { if r.chars[i] == '\t' { renderX += (KiloTabStop - 1) - (renderX % KiloTabStop) } renderX += 1 } return renderX }