Fix bug in ViewsFromTo where from might clip first value

This commit is contained in:
bloeys
2022-07-24 02:38:12 +04:00
parent 641e3eda98
commit a531d5904b
4 changed files with 34 additions and 17 deletions

View File

@ -17,7 +17,7 @@ import (
) )
const ( const (
DefaultGlyphsPerBatch = 16384 DefaultGlyphsPerBatch = 4 * 1024
floatsPerGlyph = 13 floatsPerGlyph = 13
invalidRune = unicode.ReplacementChar invalidRune = unicode.ReplacementChar

26
main.go
View File

@ -294,18 +294,19 @@ func (p *program) MainUpdate() {
p.cursorCharIndex = p.cmdBufLen p.cursorCharIndex = p.cmdBufLen
} }
// var a, b uint64
if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 { if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 {
var newPosNewLines int64 var newPosNewLines int64
if mouseWheelYNorm < 0 { if mouseWheelYNorm < 0 {
newPosNewLines, _ = find_n_lines_index_iterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm-1, p.CellCountX) newPosNewLines, _ = findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm-1, p.CellCountX)
} else { } else {
newPosNewLines, _ = find_n_lines_index_iterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm, p.CellCountX) newPosNewLines, _ = findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm, p.CellCountX)
} }
a := p.textBuf.AbsIndex(uint64(p.scrollPos)) // a = p.textBuf.AbsIndex(uint64(p.scrollPos))
b := p.textBuf.AbsIndex(uint64(newPosNewLines)) // b = p.textBuf.AbsIndex(uint64(newPosNewLines))
println("was at:", a, "; Now at:", b) // fmt.Printf("was at absIndex %d (char=%d); Now at absIndex %d (char=%d)\n", a, p.textBuf.Get(a), b, p.textBuf.Get(b))
// assert.T(p.textBuf.Get(uint64(newPosNewLines)) != '\n', fmt.Sprintf("Original AbsIndex %d; New line at AbsIndex %d\n", a, b)) // assert.T(p.textBuf.Get(uint64(newPosNewLines)) != '\n', fmt.Sprintf("Original AbsIndex %d; New line at AbsIndex %d\n", a, b))
p.scrollPos = clamp(newPosNewLines, 0, p.textBuf.Len) p.scrollPos = clamp(newPosNewLines, 0, p.textBuf.Len)
} }
@ -322,14 +323,14 @@ func (p *program) MainUpdate() {
// Draw textBuf // Draw textBuf
from := p.scrollPos from := p.scrollPos
to, _ := find_n_lines_index_iterator(p.textBuf.Iterator(), p.scrollPos, p.CellCountY-2, p.CellCountX) to, _ := findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.CellCountY-2, p.CellCountX)
assert.T(to >= 0, "'to' was less than zero")
// to is the first character after the nth line. Passing this index to ViewsFromTo will show 1 more char than we want, // to is the first character after the nth line. Passing this index to ViewsFromTo will show 1 more char than we want,
// so we decrement if needed // so we decrement if needed
if to > 0 { if to > 0 {
to-- to--
} }
assert.T(to >= 0, "'to' was less than zero")
v1, v2 := p.textBuf.ViewsFromTo(uint64(from), uint64(to)) v1, v2 := p.textBuf.ViewsFromTo(uint64(from), uint64(to))
p.lastCmdCharPos.Data = p.DrawTextAnsiCodes(v1, *gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0)).Data p.lastCmdCharPos.Data = p.DrawTextAnsiCodes(v1, *gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0)).Data
@ -599,7 +600,7 @@ func (p *program) HandleReturn() {
}() }()
defer p.ClearActiveCmd() defer p.ClearActiveCmd()
buf := make([]byte, 1024) buf := make([]byte, 4*1024)
for p.activeCmd != nil { for p.activeCmd != nil {
readBytes, err := p.activeCmd.Stdout.Read(buf) readBytes, err := p.activeCmd.Stdout.Read(buf)
@ -617,6 +618,7 @@ func (p *program) HandleReturn() {
continue continue
} }
// @Todo We need to parse ansi codes as data is coming in to update the drawing settings (e.g. color)
p.WriteToTextBuf(buf[:readBytes]) p.WriteToTextBuf(buf[:readBytes])
// println("Read:", string(buf[:readBytes])) // println("Read:", string(buf[:readBytes]))
} }
@ -862,14 +864,14 @@ func FindNthOrLastIndex[T comparable](arr []T, x T, startIndex, n int64) (lastIn
return lastIndex return lastIndex
} }
// find_n_lines_index starts at startIndex and moves n lines forward/backward, depending on whether 'n' is negative or positive, // findNLinesIndexIterator starts at startIndex and moves n lines forward/backward, depending on whether 'n' is negative or positive,
// then returns the index of the nth line and the size of char in bytes that preceeds the line. // then returns the index of the nth line and the size of char in bytes that preceeds the line.
// //
// A line is counted when either a '\n' is seen or by seeing enough chars that a wrap is required. // A line is counted when either a '\n' is seen or by seeing enough chars that a wrap is required.
// //
// Note: When moving backwards from the start of the line, the first char will be a new line (e.g. \n), so the first counted line is not a full line // Note: When moving backwards from the start of the line, the first char will be a new line (e.g. \n), so the first counted line is not a full line
// but only a single rune. So in most cases to get '-n' lines backwards you should request '-n-1' lines. // but only a single rune. So in most cases to get '-n' lines backwards you should request '-n-1' lines.
func find_n_lines_index_iterator(it ring.Iterator[byte], startIndex, n, charsPerLine int64) (newIndex, newSize int64) { func findNLinesIndexIterator(it ring.Iterator[byte], startIndex, n, charsPerLine int64) (newIndex, newSize int64) {
// If nothing changes (e.g. already at end of iterator) then we will stay at the same place // If nothing changes (e.g. already at end of iterator) then we will stay at the same place
@ -938,6 +940,10 @@ func find_n_lines_index_iterator(it ring.Iterator[byte], startIndex, n, charsPer
// If this is true we covered one line // If this is true we covered one line
if charsSeenThisLine == charsPerLine || r == '\n' { if charsSeenThisLine == charsPerLine || r == '\n' {
if r == '\n' {
fmt.Printf("Found \\n at index %d\n", it.Curr)
}
charsSeenThisLine = 0 charsSeenThisLine = 0
newSize = int64(size) newSize = int64(size)
newIndex = startIndex - bytesSeen + newSize newIndex = startIndex - bytesSeen + newSize

View File

@ -154,7 +154,7 @@ func (b *Buffer[T]) ViewsFromTo(fromIndex, toIndex uint64) (v1, v2 []T) {
return return
} }
fromIndex -= v1Len - 1 fromIndex -= v1Len
toIndex -= v1Len toIndex -= v1Len
if toIndex >= v2Len { if toIndex >= v2Len {
toIndex = v2Len toIndex = v2Len
@ -187,7 +187,9 @@ type Iterator[T any] struct {
V1 []T V1 []T
V2 []T V2 []T
// Curr is the index of the element that will be returned on Next() // Curr is the index of the element that will be returned on Next(),
// which means it is an index into V1 or V2 and so is relative to Buffer.Start value at the time
// of creating this iterator instance
Curr int64 Curr int64
InV1 bool InV1 bool
} }

View File

@ -1,6 +1,7 @@
package ring_test package ring_test
import ( import (
"runtime"
"testing" "testing"
"github.com/bloeys/nterm/ring" "github.com/bloeys/nterm/ring"
@ -135,7 +136,8 @@ func TestRing(t *testing.T) {
v11, v22 = b2.ViewsFromTo(3, 40) v11, v22 = b2.ViewsFromTo(3, 40)
Check(t, 0, len(v11)) Check(t, 0, len(v11))
Check(t, 0, len(v22)) Check(t, 1, len(v22))
CheckArr(t, []int{6}, v22)
v11, v22 = b2.ViewsFromTo(1, 2) v11, v22 = b2.ViewsFromTo(1, 2)
Check(t, 1, len(v11)) Check(t, 1, len(v11))
@ -159,6 +161,11 @@ func TestRing(t *testing.T) {
Check(t, 2, len(v22)) Check(t, 2, len(v22))
CheckArr(t, []int{3, 4}, v11) CheckArr(t, []int{3, 4}, v11)
CheckArr(t, []int{5, 6}, v22) CheckArr(t, []int{5, 6}, v22)
v11, v22 = b2.ViewsFromTo(2, 3)
Check(t, 0, len(v11))
Check(t, 2, len(v22))
CheckArr(t, []int{5, 6}, v22)
} }
func TestIterator(t *testing.T) { func TestIterator(t *testing.T) {
@ -291,21 +298,23 @@ func TestIterator(t *testing.T) {
func Check[T comparable](t *testing.T, expected, got T) { func Check[T comparable](t *testing.T, expected, got T) {
if got != expected { if got != expected {
t.Fatalf("Expected %v but got %v\n", expected, got) _, _, line, _ := runtime.Caller(1)
t.Fatalf("Expected %v but got %v by test at line %d\n", expected, got, line)
} }
} }
func CheckArr[T comparable](t *testing.T, expected, got []T) { func CheckArr[T comparable](t *testing.T, expected, got []T) {
_, _, line, _ := runtime.Caller(1)
if len(expected) != len(got) { if len(expected) != len(got) {
t.Fatalf("Expected %v but got %v\n", expected, got) t.Fatalf("Expected %v but got %v by test at line %d\n", expected, got, line)
return return
} }
for i := 0; i < len(expected); i++ { for i := 0; i < len(expected); i++ {
if expected[i] != got[i] { if expected[i] != got[i] {
t.Fatalf("Expected %v but got %v\n", expected, got) t.Fatalf("Expected %v but got %v by test at line %d\n", expected, got, line)
return return
} }
} }