Merge pull request #84 from felixangell/piecetable

move from rope to piece table
This commit is contained in:
Felix Angell 2018-05-16 21:39:54 +01:00 committed by GitHub
commit ee055fdc67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 90 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
tests/ tests/
phi-editor phi-editor
phi phi

View File

@ -13,9 +13,9 @@ import (
"unicode" "unicode"
"github.com/felixangell/fuzzysearch/fuzzy" "github.com/felixangell/fuzzysearch/fuzzy"
"github.com/felixangell/go-rope"
"github.com/felixangell/phi/cfg" "github.com/felixangell/phi/cfg"
"github.com/felixangell/phi/lex" "github.com/felixangell/phi/lex"
"github.com/felixangell/piecetable"
"github.com/felixangell/strife" "github.com/felixangell/strife"
"github.com/sqweek/dialog" "github.com/sqweek/dialog"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
@ -128,11 +128,11 @@ type Buffer struct {
BaseComponent BaseComponent
index int index int
parent *View parent *View
contents []*rope.Rope
curs *Cursor curs *Cursor
cfg *cfg.TomlConfig cfg *cfg.TomlConfig
buffOpts BufferConfig buffOpts BufferConfig
cam *camera cam *camera
table *piecetable.PieceTable
filePath string filePath string
languageInfo *cfg.LanguageSyntaxConfig languageInfo *cfg.LanguageSyntaxConfig
ex, ey int ex, ey int
@ -146,13 +146,12 @@ func NewBuffer(conf *cfg.TomlConfig, buffOpts BufferConfig, parent *View, index
config = cfg.NewDefaultConfig() config = cfg.NewDefaultConfig()
} }
buffContents := []*rope.Rope{}
buff := &Buffer{ buff := &Buffer{
index: index, index: index,
parent: parent, parent: parent,
contents: buffContents,
curs: &Cursor{}, curs: &Cursor{},
cfg: config, cfg: config,
table: piecetable.MakePieceTable(""),
buffOpts: buffOpts, buffOpts: buffOpts,
filePath: "", filePath: "",
cam: &camera{0, 0, 0, 0}, cam: &camera{0, 0, 0, 0},
@ -176,7 +175,7 @@ func (s *selection) renderAt(ctx *strife.Renderer, xOff int, yOff int) {
yd := (s.ey - s.sy) + 1 yd := (s.ey - s.sy) + 1
for y := 0; y < yd; y++ { for y := 0; y < yd; y++ {
lineLen := s.parent.contents[s.ey+y].Len() - s.sx lineLen := s.parent.table.Lines[s.ey+y].Len() - s.sx
if y == yd-1 { if y == yd-1 {
lineLen = xd lineLen = xd
} }
@ -211,12 +210,7 @@ func (b *Buffer) reload() {
panic(err) panic(err)
} }
b.contents = []*rope.Rope{} b.table = piecetable.MakePieceTable(string(contents))
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
b.appendLine(line)
}
// TODO perhaps when we reload the current line might not exist or something // TODO perhaps when we reload the current line might not exist or something
// try and set the cursor to what it was before but maybe make sure its not out // try and set the cursor to what it was before but maybe make sure its not out
@ -256,10 +250,7 @@ func (b *Buffer) OpenFile(filePath string) {
// add the file to the watcher. // add the file to the watcher.
b.parent.registerFile(filePath, b) b.parent.registerFile(filePath, b)
lines := strings.Split(string(contents), "\n") b.table = piecetable.MakePieceTable(string(contents))
for _, line := range lines {
b.appendLine(line)
}
// because appendLine sets modified to true // because appendLine sets modified to true
// we should reset this to false since weve // we should reset this to false since weve
@ -270,22 +261,22 @@ func (b *Buffer) OpenFile(filePath string) {
func (b *Buffer) setLine(idx int, val string) { func (b *Buffer) setLine(idx int, val string) {
b.modified = true b.modified = true
b.contents[idx] = rope.New(val) b.table.Lines[idx] = piecetable.NewLine(val, b.table)
if b.curs.y == idx { if b.curs.y == idx {
b.moveToEndOfLine() b.moveToEndOfLine()
} }
} }
func (b *Buffer) appendRopeAt(val *rope.Rope, idx int) { func (b *Buffer) appendLineAt(val *piecetable.Line, idx int) {
b.modified = true b.modified = true
b.contents = append(b.contents, new(rope.Rope)) b.table.Lines = append(b.table.Lines, val)
copy(b.contents[idx+1:], b.contents[idx:]) copy(b.table.Lines[idx+1:], b.table.Lines[idx:])
b.contents[idx] = val b.table.Lines[idx] = val
} }
func (b *Buffer) appendLineAt(val string, idx int) { func (b *Buffer) appendStringAt(val string, idx int) {
b.appendRopeAt(rope.New(val), idx) b.appendLineAt(piecetable.NewLine(val, b.table), idx)
} }
// appendLine adds a string to the end of // appendLine adds a string to the end of
@ -293,7 +284,7 @@ func (b *Buffer) appendLineAt(val string, idx int) {
func (b *Buffer) appendLine(val string) { func (b *Buffer) appendLine(val string) {
b.modified = true b.modified = true
b.contents = append(b.contents, rope.New(val)) b.table.Lines = append(b.table.Lines, piecetable.NewLine(val, b.table))
// because we've added a new line // because we've added a new line
// we have to set the x to the start // we have to set the x to the start
b.curs.x = 0 b.curs.x = 0
@ -306,9 +297,9 @@ func (b *Buffer) insertString(idx int, val string) {
lines := strings.Split(val, "\n") lines := strings.Split(val, "\n")
for _, l := range lines { for _, l := range lines {
b.contents = append(b.contents, new(rope.Rope)) b.table.Lines = append(b.table.Lines, piecetable.NewLine("", b.table))
copy(b.contents[b.curs.y+idx+1:], b.contents[b.curs.y+idx:]) copy(b.table.Lines[b.curs.y+idx+1:], b.table.Lines[b.curs.y+idx:])
b.contents[b.curs.y+idx] = rope.New(l) b.table.Lines[b.curs.y+idx] = piecetable.NewLine(l, b.table)
b.moveDown() b.moveDown()
} }
@ -318,9 +309,9 @@ func (b *Buffer) insertRune(r rune) {
b.modified = true b.modified = true
log.Println("Inserting rune ", r, " into current line at ", b.curs.x, ":", b.curs.y) log.Println("Inserting rune ", r, " into current line at ", b.curs.x, ":", b.curs.y)
log.Println("Line before insert> ", b.contents[b.curs.y]) log.Println("Line before insert> ", b.table.Lines[b.curs.y].String())
b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r)) b.table.Insert(string(r), b.curs.y, b.curs.x)
b.moveRight() b.moveRight()
} }
@ -379,16 +370,16 @@ func (b *Buffer) deleteLine() {
// HACK FIXME // HACK FIXME
b.modified = true b.modified = true
if len(b.contents) > 1 { if len(b.table.Lines) > 1 {
b.contents = remove(b.contents, b.curs.y) b.table.Lines = remove(b.table.Lines, b.curs.y)
} else { } else {
// we are on the first line // we are on the first line
// and there is nothing else to delete // and there is nothing else to delete
// so we just clear the line // so we just clear the line
b.contents[b.curs.y] = new(rope.Rope) b.table.Lines[b.curs.y] = piecetable.NewLine("", b.table)
} }
if b.curs.y >= len(b.contents) { if b.curs.y >= len(b.table.Lines) {
if b.curs.y > 0 { if b.curs.y > 0 {
b.moveUp() b.moveUp()
} }
@ -479,9 +470,9 @@ func (b *Buffer) processTextInput(r rune) bool {
// brackets. // brackets.
if b.cfg.Editor.Match_Braces { if b.cfg.Editor.Match_Braces {
if r == ')' || r == '}' || r == ']' { if r == ')' || r == '}' || r == ']' {
currLine := b.contents[b.curs.y] currLine := b.table.Lines[b.curs.y]
if b.curs.x < currLine.Len() { if b.curs.x < currLine.Len() {
curr := currLine.Index(b.curs.x + 1) curr := b.table.Index(b.curs.y, b.curs.x+1)
if curr == r { if curr == r {
b.moveRight() b.moveRight()
return true return true
@ -495,7 +486,7 @@ func (b *Buffer) processTextInput(r rune) bool {
// HACK FIXME // HACK FIXME
b.modified = true b.modified = true
b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(r)) b.table.Insert(string(r), b.curs.y, b.curs.x)
b.moveRight() b.moveRight()
// we don't need to match braces // we don't need to match braces
@ -520,13 +511,13 @@ func (b *Buffer) processTextInput(r rune) bool {
fallthrough fallthrough
case '[': case '[':
matchingPair += offset matchingPair += offset
b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(rune(matchingPair))) b.table.Insert(string(rune(matchingPair)), b.curs.y, b.curs.x)
} }
return true return true
} }
func remove(slice []*rope.Rope, s int) []*rope.Rope { func remove(slice []*piecetable.Line, s int) []*piecetable.Line {
return append(slice[:s], slice[s+1:]...) return append(slice[:s], slice[s+1:]...)
} }
@ -540,27 +531,31 @@ func (b *Buffer) deletePrev() {
if b.curs.x > 0 { if b.curs.x > 0 {
offs := -1 offs := -1
if !b.cfg.Editor.Tabs_Are_Spaces { if !b.cfg.Editor.Tabs_Are_Spaces {
if b.contents[b.curs.y].Index(b.curs.x) == '\t' { if b.table.Index(b.curs.y, b.curs.x) == '\t' {
offs = int(-b.cfg.Editor.Tab_Size) offs = int(-b.cfg.Editor.Tab_Size)
} }
} else if b.cfg.Editor.Hungry_Backspace && b.curs.x >= int(b.cfg.Editor.Tab_Size) { } else if b.cfg.Editor.Hungry_Backspace && b.curs.x >= int(b.cfg.Editor.Tab_Size) {
// cut out the last {TAB_SIZE} amount of characters // cut out the last {TAB_SIZE} amount of characters
// and check em // and check em
tabSize := int(b.cfg.Editor.Tab_Size) tabSize := int(b.cfg.Editor.Tab_Size)
lastTabSizeChars := b.contents[b.curs.y].Substr(b.curs.x+1-tabSize, tabSize).String()
if strings.Compare(lastTabSizeChars, b.makeTab()) == 0 { // render the line...
currLine := b.table.Lines[b.curs.y].String()
before := currLine[b.curs.x-tabSize:]
if strings.HasPrefix(before, b.makeTab()) {
// delete {TAB_SIZE} amount of characters // delete {TAB_SIZE} amount of characters
// from the cursors x pos // from the cursors x pos
for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ { for i := 0; i < int(b.cfg.Editor.Tab_Size); i++ {
b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1) b.table.Delete(b.curs.y, b.curs.x)
b.curs.move(-1, 0) b.curs.move(-1, 0)
} }
return return
} }
} }
b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1) b.table.Delete(b.curs.y, b.curs.x)
if len(b.autoComplete.lastRunes) > 0 { if len(b.autoComplete.lastRunes) > 0 {
// pop the last word off in the auto complete // pop the last word off in the auto complete
@ -574,9 +569,12 @@ func (b *Buffer) deletePrev() {
// wrapping back the line? // wrapping back the line?
// start of line, wrap to previous // start of line, wrap to previous
prevLineLen := b.contents[b.curs.y-1].Len() prevLineLen := b.table.Lines[b.curs.y-1].Len()
b.contents[b.curs.y-1] = b.contents[b.curs.y-1].Concat(b.contents[b.curs.y])
b.contents = append(b.contents[:b.curs.y], b.contents[b.curs.y+1:]...) val := b.table.Lines[b.curs.y].String()
b.table.Insert(val, b.curs.y-1, b.table.Lines[b.curs.y-1].Len())
b.table.Lines = append(b.table.Lines[:b.curs.y], b.table.Lines[b.curs.y+1:]...)
b.curs.move(prevLineLen, -1) b.curs.move(prevLineLen, -1)
} }
} }
@ -596,7 +594,7 @@ func (b *Buffer) deleteBeforeCursor() {
func (b *Buffer) moveLeft() { func (b *Buffer) moveLeft() {
if b.curs.x == 0 && b.curs.y > 0 { if b.curs.x == 0 && b.curs.y > 0 {
b.curs.move(b.contents[b.curs.y-1].Len(), -1) b.curs.move(b.table.Lines[b.curs.y-1].Len(), -1)
} else if b.curs.x > 0 { } else if b.curs.x > 0 {
b.curs.move(-1, 0) b.curs.move(-1, 0)
@ -604,14 +602,14 @@ func (b *Buffer) moveLeft() {
} }
func (b *Buffer) moveRight() { func (b *Buffer) moveRight() {
currLineLength := b.contents[b.curs.y].Len() currLineLength := b.table.Lines[b.curs.y].Len()
if b.curs.x >= currLineLength && b.curs.y < len(b.contents)-1 { if b.curs.x >= currLineLength && b.curs.y < len(b.table.Lines)-1 {
// we're at the end of the line and we have // we're at the end of the line and we have
// some lines after, let's wrap around // some lines after, let's wrap around
b.curs.move(-currLineLength, 0) b.curs.move(-currLineLength, 0)
b.moveDown() b.moveDown()
} else if b.curs.x < b.contents[b.curs.y].Len() { } else if b.curs.x < b.table.Lines[b.curs.y].Len() {
// we have characters to the right, let's move along // we have characters to the right, let's move along
b.curs.move(1, 0) b.curs.move(1, 0)
} }
@ -624,7 +622,7 @@ func (b *Buffer) moveToStartOfLine() {
} }
func (b *Buffer) moveToEndOfLine() { func (b *Buffer) moveToEndOfLine() {
lineLen := b.contents[b.curs.y].Len() lineLen := b.table.Lines[b.curs.y].Len()
if b.curs.x > lineLen { if b.curs.x > lineLen {
distToMove := b.curs.x - lineLen distToMove := b.curs.x - lineLen
@ -654,7 +652,7 @@ func (b *Buffer) gotoLine(num int64) {
func (b *Buffer) moveUp() { func (b *Buffer) moveUp() {
if b.curs.y > 0 { if b.curs.y > 0 {
offs := 0 offs := 0
prevLineLen := b.contents[b.curs.y-1].Len() prevLineLen := b.table.Lines[b.curs.y-1].Len()
if b.curs.x > prevLineLen { if b.curs.x > prevLineLen {
offs = prevLineLen - b.curs.x offs = prevLineLen - b.curs.x
} }
@ -671,9 +669,9 @@ func (b *Buffer) moveUp() {
} }
func (b *Buffer) moveDown() { func (b *Buffer) moveDown() {
if b.curs.y < len(b.contents)-1 { if b.curs.y < len(b.table.Lines)-1 {
offs := 0 offs := 0
nextLineLen := b.contents[b.curs.y+1].Len() nextLineLen := b.table.Lines[b.curs.y+1].Len()
if b.curs.x > nextLineLen { if b.curs.x > nextLineLen {
offs = nextLineLen - b.curs.x offs = nextLineLen - b.curs.x
} }
@ -692,21 +690,21 @@ func (b *Buffer) moveDown() {
func (b *Buffer) swapLineUp() bool { func (b *Buffer) swapLineUp() bool {
if b.curs.y > 0 { if b.curs.y > 0 {
currLine := b.contents[b.curs.y] currLine := b.table.Lines[b.curs.y]
prevLine := b.contents[b.curs.y-1] prevLine := b.table.Lines[b.curs.y-1]
b.contents[b.curs.y-1] = currLine b.table.Lines[b.curs.y-1] = currLine
b.contents[b.curs.y] = prevLine b.table.Lines[b.curs.y] = prevLine
b.moveUp() b.moveUp()
} }
return true return true
} }
func (b *Buffer) swapLineDown() bool { func (b *Buffer) swapLineDown() bool {
if b.curs.y < len(b.contents) { if b.curs.y < len(b.table.Lines) {
currLine := b.contents[b.curs.y] currLine := b.table.Lines[b.curs.y]
nextLine := b.contents[b.curs.y+1] nextLine := b.table.Lines[b.curs.y+1]
b.contents[b.curs.y+1] = currLine b.table.Lines[b.curs.y+1] = currLine
b.contents[b.curs.y] = nextLine b.table.Lines[b.curs.y] = nextLine
b.moveDown() b.moveDown()
} }
return true return true
@ -720,7 +718,7 @@ func (b *Buffer) scrollUp(lineScrollAmount int) {
} }
func (b *Buffer) scrollDown(lineScrollAmount int) { func (b *Buffer) scrollDown(lineScrollAmount int) {
if b.cam.y < len(b.contents) { if b.cam.y < len(b.table.Lines) {
b.cam.dy += lineScrollAmount b.cam.dy += lineScrollAmount
} }
} }
@ -802,19 +800,19 @@ func (b *Buffer) processActionKey(key int) bool {
// we're at the start of a line, so we want to // we're at the start of a line, so we want to
// shift the line down and insert an empty line // shift the line down and insert an empty line
// above it! // above it!
b.contents = append(b.contents, new(rope.Rope)) // grow b.table.Lines = append(b.table.Lines, piecetable.NewLine("", b.table)) // grow
copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:]) // shift copy(b.table.Lines[b.curs.y+1:], b.table.Lines[b.curs.y:]) // shift
b.contents[b.curs.y] = new(rope.Rope) // set b.table.Lines[b.curs.y] = piecetable.NewLine("", b.table) // set
b.moveDown() b.moveDown()
return true return true
} }
initialX := b.curs.x initialX := b.curs.x
prevLineLen := b.contents[b.curs.y].Len() prevLineLen := b.table.Lines[b.curs.y].Len()
// END OF LINE: // END OF LINE:
if initialX == prevLineLen { if initialX == prevLineLen {
b.appendLineAt("", b.curs.y+1) b.appendStringAt("", b.curs.y+1)
b.moveDown() b.moveDown()
b.moveToStartOfLine() b.moveToStartOfLine()
return true return true
@ -822,9 +820,15 @@ func (b *Buffer) processActionKey(key int) bool {
// we're not at the end of the line, but we're not at // we're not at the end of the line, but we're not at
// the start, i.e. we're SPLITTING the line // the start, i.e. we're SPLITTING the line
left, right := b.contents[b.curs.y].Split(initialX) left := b.table.Lines[b.curs.y].String()
b.contents[b.curs.y] = left rightPart := left[initialX:]
b.appendRopeAt(right, b.curs.y+1)
for i := 0; i < len(rightPart); i++ {
// TODO POP in piecetable?
b.table.Delete(b.curs.y, len(left)-i)
}
b.appendStringAt(rightPart, b.curs.y+1)
b.moveDown() b.moveDown()
b.moveToStartOfLine() b.moveToStartOfLine()
@ -839,7 +843,7 @@ func (b *Buffer) processActionKey(key int) bool {
} }
case sdl.K_RIGHT: case sdl.K_RIGHT:
currLineLength := b.contents[b.curs.y].Len() currLineLength := b.table.Lines[b.curs.y].Len()
if SUPER_DOWN { if SUPER_DOWN {
for b.curs.x < currLineLength { for b.curs.x < currLineLength {
@ -852,12 +856,12 @@ func (b *Buffer) processActionKey(key int) bool {
// this will move to the next blank or underscore // this will move to the next blank or underscore
// character // character
if ALT_DOWN { if ALT_DOWN {
line := b.contents[b.curs.y] line := b.table.Lines[b.curs.y]
i := b.curs.x + 1 // ? i := b.curs.x + 1 // ?
for i < len(line.String())-1 { for i < len(line.String())-1 {
curr := line.Index(i) curr := b.table.Index(b.curs.y, i)
switch curr { switch curr {
case ' ': case ' ':
@ -888,11 +892,9 @@ func (b *Buffer) processActionKey(key int) bool {
// the start of the line! // the start of the line!
b.curs.gotoStart() b.curs.gotoStart()
} else if ALT_DOWN { } else if ALT_DOWN {
currLine := b.contents[b.curs.y]
i := b.curs.x i := b.curs.x
for i > 0 { for i > 0 {
currChar := currLine.Index(i) currChar := b.table.Index(b.curs.y, i)
switch currChar { switch currChar {
case ' ': case ' ':
@ -953,17 +955,17 @@ func (b *Buffer) processActionKey(key int) bool {
if b.cfg.Editor.Tabs_Are_Spaces { if b.cfg.Editor.Tabs_Are_Spaces {
// make an empty rune array of TAB_SIZE, cast to string // make an empty rune array of TAB_SIZE, cast to string
// and insert it. // and insert it.
b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, b.makeTab()) b.table.Insert(b.makeTab(), b.curs.y, b.curs.x)
b.curs.move(int(b.cfg.Editor.Tab_Size), 0) b.curs.move(int(b.cfg.Editor.Tab_Size), 0)
} else { } else {
b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string('\t')) b.table.Insert(string('\t'), b.curs.y, b.curs.x)
// the actual position is + 1, but we make it // the actual position is + 1, but we make it
// move by TAB_SIZE characters on the view. // move by TAB_SIZE characters on the view.
b.curs.moveRender(1, 0, int(b.cfg.Editor.Tab_Size), 0) b.curs.moveRender(1, 0, int(b.cfg.Editor.Tab_Size), 0)
} }
case sdl.K_END: case sdl.K_END:
currLine := b.contents[b.curs.y] currLine := b.table.Lines[b.curs.y]
if b.curs.x < currLine.Len() { if b.curs.x < currLine.Len() {
distToMove := currLine.Len() - b.curs.x distToMove := currLine.Len() - b.curs.x
b.curs.move(distToMove, 0) b.curs.move(distToMove, 0)
@ -1241,11 +1243,11 @@ func (b *Buffer) renderAt(ctx *strife.Renderer, rx int, ry int) {
start := b.cam.y start := b.cam.y
upper := b.cam.y + visibleLines upper := b.cam.y + visibleLines
if start > len(b.contents) { if start > len(b.table.Lines) {
start = len(b.contents) start = len(b.table.Lines)
} }
if upper > len(b.contents) { if upper > len(b.table.Lines) {
upper = len(b.contents) upper = len(b.table.Lines)
} }
// render the selection if any // render the selection if any
@ -1253,10 +1255,10 @@ func (b *Buffer) renderAt(ctx *strife.Renderer, rx int, ry int) {
lastSelection.renderAt(ctx, b.x+b.ex, b.y+b.ey) lastSelection.renderAt(ctx, b.x+b.ex, b.y+b.ey)
} }
numLines := len(b.contents) numLines := len(b.table.Lines)
var y_col int var y_col int
for lineNum, rope := range b.contents[start:upper] { for lineNum, rope := range b.table.Lines[start:upper] {
currLine := []rune(rope.String()) currLine := []rune(rope.String())
// slice the visible characters only. // slice the visible characters only.

View File

@ -132,7 +132,7 @@ func NewCommandPalette(conf cfg.TomlConfig, view *View) *CommandPalette {
} }
func (b *CommandPalette) processCommand() { func (b *CommandPalette) processCommand() {
input := b.buff.contents[0].String() input := b.buff.table.Lines[0].String()
input = strings.TrimSpace(input) input = strings.TrimSpace(input)
tokenizedLine := strings.Split(input, " ") tokenizedLine := strings.Split(input, " ")
@ -162,7 +162,7 @@ func (b *CommandPalette) processCommand() {
} }
func (b *CommandPalette) calculateCommandSuggestions() { func (b *CommandPalette) calculateCommandSuggestions() {
input := b.buff.contents[0].String() input := b.buff.table.Lines[0].String()
input = strings.TrimSpace(input) input = strings.TrimSpace(input)
tokenizedLine := strings.Split(input, " ") tokenizedLine := strings.Split(input, " ")
@ -209,7 +209,7 @@ func (b *CommandPalette) calculateCommandSuggestions() {
} }
func (b *CommandPalette) calculateSuggestions() { func (b *CommandPalette) calculateSuggestions() {
input := b.buff.contents[0].String() input := b.buff.table.Lines[0].String()
input = strings.TrimSpace(input) input = strings.TrimSpace(input)
if len(input) == 0 { if len(input) == 0 {

View File

@ -59,7 +59,7 @@ func Save(v *View, commands []string) bool {
} }
var buffer bytes.Buffer var buffer bytes.Buffer
for idx, line := range b.contents { for idx, line := range b.table.Lines {
if idx > 0 { if idx > 0 {
// TODO: this avoids a trailing newline // TODO: this avoids a trailing newline
// if we handle it like this? but if we have // if we handle it like this? but if we have