diff --git a/ui/buffer/rope.go b/ui/buffer/rope.go index 1fbdafd..06c90d7 100644 --- a/ui/buffer/rope.go +++ b/ui/buffer/rope.go @@ -290,28 +290,33 @@ func (b *RopeBuffer) PosToLineCol(pos int) (int, int) { var line, col int var wasAtNewline bool - _rope := (*rope.Node)(b) - _rope.EachLeaf(func(n *rope.Node) bool { + if pos <= 0 { + return line, col + } + + (*rope.Node)(b).EachLeaf(func(n *rope.Node) bool { data := n.Value() var i int for i < len(data) { - if pos <= 0 { - return true - } - - if data[i] == '\n' { // End of line + if wasAtNewline { // Start of line + if data[i] != '\n' { // If the start of this line does not happen to be a delim... + wasAtNewline = false // Say we weren't previously at a delimiter + } + line, col = line+1, 0 + } else if data[i] == '\n' { // End of line wasAtNewline = true col++ - } else if wasAtNewline { // Start of line - wasAtNewline = false - line, col = line+1, 0 } else { - col++ // Normal byte + col++ } _, size := utf8.DecodeRune(data[i:]) i += size pos -= size + + if pos < 0 { + return true + } } return false }) diff --git a/ui/buffer/rope_test.go b/ui/buffer/rope_test.go index 0e64728..c1a72f4 100644 --- a/ui/buffer/rope_test.go +++ b/ui/buffer/rope_test.go @@ -2,6 +2,49 @@ package buffer import "testing" +func TestRopePosToLineCol(t *testing.T) { + var buf Buffer = NewRopeBuffer([]byte("line0\nline1\n\nline3\n")) + //line0 + //line1 + // + //line3 + // + + startLine, startCol := buf.PosToLineCol(0) + if startLine != 0 { + t.Errorf("Expected startLine == 0, got %v", startLine) + t.Fail() + } + + if startCol != 0 { + t.Errorf("Expected startCol == 0, got %v", startCol) + t.Fail() + } + + endPos := buf.Len()-1 + endLine, endCol := buf.PosToLineCol(endPos) + t.Logf("endPos = %v", endPos) + if endLine != 3 { + t.Errorf("Expected endLine == 3, got %v", endLine) + } + + if endCol != 5 { + t.Errorf("Expected endCol == 5, got %v", endCol) + } + + line1Pos := 11 // Byte index of the delim separating line1 and line 2 + line1Line, line1Col := buf.PosToLineCol(line1Pos) + if line1Line != 1 { + t.Errorf("Expected line1Line == 1, got %v", line1Line) + t.Fail() + } + + if line1Col != 5 { + t.Errorf("Expected line1Col == 5, got %v", line1Col) + t.Fail() + } +} + func TestRopeInserting(t *testing.T) { var buf Buffer = NewRopeBuffer([]byte("some")) buf.Insert(0, 4, []byte(" text\n")) // Insert " text" after "some"