func TestCommonStart(t *testing.T) { line1 := buffer.MakeLine("hello world") line2 := buffer.MakeLine("hello bob") cs := line1.CommonStart(line2) if cs.ToString() != "hello " { t.Error("Common start is wrong", line1, line2, cs) } line3 := buffer.MakeLine("hello world") cs = line1.CommonStart(line3) if cs.ToString() != "hello world" { t.Error("Common start is wrong", line1, line3, cs) } }
func TestReplaceLines(t *testing.T) { buf := buffer.MakeBuffer([]string{"a", "b", "c", "d", "e"}) lines := []buffer.Line{ buffer.MakeLine("hello"), buffer.MakeLine("world"), } buf.ReplaceLines(lines, 1, 3) if buf.Length() != 4 { t.Error("ReplaceLines failed:", buf.ToString("\n")) } if buf.GetRow(3).ToString() != "e" { t.Error("ReplaceLines failed:", buf.ToString("\n")) } }
func TestSlice(t *testing.T) { line1 := buffer.MakeLine("012345678") var line2 buffer.Line line2 = line1.Slice(0, 4) if line2.ToString() != "0123" { t.Error("slice:", line1.ToString(), line2.ToString()) } line2 = line1.Slice(0, -1) if line2.ToString() != "012345678" { t.Error("slice:", line1.ToString(), line2.ToString()) } line2 = line1.Slice(4, 6) if line2.ToString() != "45" { t.Error("slice:", line1.ToString(), line2.ToString()) } line2 = line1.Slice(4, 20) if line2.ToString() != "45678" { t.Error("slice:", line1.ToString(), line2.ToString()) } }
func TestSearch(t *testing.T) { line := buffer.MakeLine("hello world") a, b := line.Search("llo", 0, -1) if a != 2 || b != 5 { t.Error("search:", line.ToString(), "llo", a, b) } a, b = line.Search("llo", 2, -1) if a != 2 || b != 5 { t.Error("search:", line.ToString(), "llo", a, b) } a, b = line.Search("llo", 0, 2) if a != -1 { t.Error("search:", line.ToString(), "llo", a, b) } a, b = line.Search("/.o/", 0, -1) if a != 3 || b != 5 { t.Error("search:", line.ToString(), "llo", a, b) } }
func TestTabs2spaces(t *testing.T) { line1 := buffer.MakeLine("\t\thello world") line2 := line1.Tabs2spaces() if line2.ToString() != " hello world" { t.Error("Tabs2spaces:", line2) } }
// InsertChar insters a character (rune) into the current cursor position. func (file *File) InsertChar(ch rune) { maxCol := 0 maxLineLen := 0 for _, cursor := range file.MultiCursor.Cursors() { if cursor.Col() > maxCol { maxCol = cursor.Col() } if file.buffer.RowLength(cursor.Row()) > maxLineLen { maxLineLen = file.buffer.RowLength(cursor.Row()) } } for idx, cursor := range file.MultiCursor.Cursors() { row, col := cursor.RowCol() if maxCol > 0 && col == 0 { continue } line := file.buffer.GetRow(row) if (ch == ' ' || ch == '\t') && col == 0 && line.Length() == 0 && maxLineLen > 0 { continue } insertStr := string(ch) if ch == '\t' && file.autoTab && file.tabString != "\t" { insertStr = file.tabString } newLine := buffer.MakeLine(line.Slice(0, col).ToString() + insertStr + line.Slice(col, -1).ToString()) file.buffer.SetRow(row, newLine) col += len(insertStr) file.MultiCursor.SetCursor(idx, row, col, col) } file.Snapshot() }
func TestBufferAppend(t *testing.T) { buf := buffer.MakeBuffer([]string{"", "hello"}) line := buffer.MakeLine("world") buf.Append(line) if buf.Length() != 3 { t.Error("Buffer Append failed", buf) } }
// Backspace removes the character before the cursor. func (file *File) Backspace() { for idx, cursor := range file.MultiCursor.Cursors() { row, col := cursor.RowCol() if col == 0 { if file.MultiCursor.Length() > 1 { continue } if row == 0 { return } row-- if row+1 >= file.buffer.Length() { return } col = file.buffer.RowLength(row) newLine := buffer.MakeLine(file.buffer.GetRow(row).ToString() + file.buffer.GetRow(row+1).ToString()) file.buffer.ReplaceLine(newLine, row) file.buffer.DeleteRow(row + 1) file.MultiCursor.SetCursor(idx, row, col, col) } else { line := file.buffer.GetRow(row) if col > line.Length() { continue } // Handle multi-char indents. nDel := 1 if file.autoTab && len(file.tabString) > 0 { if line.Slice(0, col).ToString() == strings.Repeat(" ", col) { n := len(file.tabString) if n*(col/n) == col { nDel = n } } } newLine := buffer.MakeLine(line.Slice(0, col-nDel).ToString() + line.Slice(col, -1).ToString()) file.buffer.SetRow(row, newLine) col -= nDel file.MultiCursor.SetCursor(idx, row, col, col) } } file.enforceRowBounds() file.enforceColBounds() file.Snapshot() }
func TestBufferEdits(t *testing.T) { buf := buffer.MakeBuffer([]string{"a", "b", "c"}) buf.InsertAfter(1, buffer.MakeLine("b2"), buffer.MakeLine("b3")) if buf.ToString("-") != "a-b-b2-b3-c" { t.Error("InsertAfter is broken", buf.ToString("-")) } buf.DeleteRow(0) if buf.ToString("-") != "b-b2-b3-c" { t.Error("InsertAfter is broken", buf.ToString("-")) } buf.ReplaceLine(buffer.MakeLine("z"), 0) if buf.ToString("-") != "z-b2-b3-c" { t.Error("InsertAfter is broken", buf.ToString("-")) } buf.DeleteRow(2) if buf.ToString("-") != "z-b2-c" { t.Error("InsertAfter is broken", buf.ToString("-")) } }
func TestDup(t *testing.T) { line1 := buffer.MakeLine("hello world") line2 := line1.Dup() if line1.ToString() != line2.ToString() { t.Error("Duped line content does not match.", line1, line2) } line1.SetChar(0, 'H') if line1.ToString() == line2.ToString() { t.Error("Duped line contains same memory.", line1, line2) } }
// Paste inserts the copy buffer into buffer at the current line. func (file *File) Paste(strs []string) { row := file.MultiCursor.GetRow(0) pasteLines := make([]buffer.Line, len(strs)) for idx, str := range strs { pasteLines[idx] = buffer.MakeLine(str) } file.buffer.InsertAfter(row-1, pasteLines...) file.CursorDown(len(pasteLines)) file.enforceRowBounds() file.enforceColBounds() file.Snapshot() }
func (file *File) doAutoIndent(idx int) { row := file.MultiCursor.GetRow(idx) if row == 0 { return } origLine := file.buffer.GetRow(row).Dup() // Whitespace-only indent. re, _ := regexp.Compile("^[ \t]+") prevLineStr := file.buffer.GetRow(row - 1).ToString() ws := re.FindString(prevLineStr) if len(ws) > 0 { newLineStr := ws + file.buffer.GetRow(row).ToString() file.buffer.SetRow(row, buffer.MakeLine(newLineStr)) col := file.MultiCursor.GetCol(idx) + len(ws) file.MultiCursor.SetCursor(idx, row, col, col) if file.buffer.GetRow(row-1).Length() == len(ws) { file.buffer.SetRow(row-1, buffer.MakeLine("")) } } if row < 2 { return } // Non-whitespace indent. indent := file.buffer.GetRow(row - 1).CommonStart(file.buffer.GetRow(row - 2)) if indent.Length() > len(ws) { file.ForceSnapshot() newLineStr := indent.ToString() + origLine.ToString() file.buffer.SetRow(row, buffer.MakeLine(newLineStr)) col := file.MultiCursor.GetCol(idx) + indent.Length() - len(ws) file.MultiCursor.SetCursor(idx, row, col, col) } }
// CursorAlign inserts spaces into each cursor position, in order to // align the cursors vertically. func (file *File) CursorAlign() { maxCol := file.MultiCursor.MaxCol() for idx, cursor := range file.MultiCursor.Cursors() { row, col := cursor.RowCol() nSpaces := maxCol - col spaces := strings.Repeat(" ", nSpaces) line := file.buffer.GetRow(row) newLine := buffer.MakeLine(line.Slice(0, col).ToString() + spaces + line.Slice(col, -1).ToString()) file.buffer.SetRow(row, newLine) col += len(spaces) file.MultiCursor.SetCursor(idx, row, col, col) } file.Snapshot() }
func TestBufferDeepDup(t *testing.T) { buf1 := buffer.MakeBuffer([]string{"hello", "world"}) buf2 := buf1.DeepDup() if buf1.GetRow(1).ToString() != buf2.GetRow(1).ToString() { t.Error("Duped buffers not equal:", buf1, buf2) } buf2.SetRow(1, buffer.MakeLine("wurld")) if buf1.GetRow(1).ToString() == buf2.GetRow(1).ToString() { t.Error("Duped buffers too identical:", buf1, buf2) } }
func TestRemoveTrailingWhitespace(t *testing.T) { tests := [][]string{ {" foo", " foo"}, {" foo ", " foo"}, {" foo\t", " foo"}, } for _, test := range tests { line1 := buffer.MakeLine(test[0]) line2 := line1.RemoveTrailingWhitespace() if line2.ToString() != test[1] { t.Errorf("remove trailing whitespace: --%s-- => --%s--", line1.ToString(), line2.ToString()) } } }