mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 14:38:19 +00:00
Fix paragraph viewing bugs+indexing helpers for ring buffer
This commit is contained in:
153
main.go
153
main.go
@ -49,11 +49,12 @@ type Cmd struct {
|
|||||||
Stderr io.ReadCloser
|
Stderr io.ReadCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
type Line struct {
|
// Para represents a paragraph, a line of text between two new lines
|
||||||
|
type Para struct {
|
||||||
StartIndex, EndIndex uint64
|
StartIndex, EndIndex uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Line) Size() uint64 {
|
func (l *Para) Size() uint64 {
|
||||||
size := l.EndIndex - l.StartIndex
|
size := l.EndIndex - l.StartIndex
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
@ -72,10 +73,8 @@ type program struct {
|
|||||||
gridMesh *meshes.Mesh
|
gridMesh *meshes.Mesh
|
||||||
gridMat *materials.Material
|
gridMat *materials.Material
|
||||||
|
|
||||||
CurrLine Line
|
CurrPara Para
|
||||||
// CurrLineValid bool
|
Paras *ring.Buffer[Para]
|
||||||
|
|
||||||
Lines *ring.Buffer[Line]
|
|
||||||
|
|
||||||
textBuf *ring.Buffer[byte]
|
textBuf *ring.Buffer[byte]
|
||||||
textBufMutex sync.Mutex
|
textBufMutex sync.Mutex
|
||||||
@ -143,7 +142,7 @@ func main() {
|
|||||||
imguiInfo: nmageimgui.NewImGUI(),
|
imguiInfo: nmageimgui.NewImGUI(),
|
||||||
FontSize: 40,
|
FontSize: 40,
|
||||||
|
|
||||||
Lines: ring.NewBuffer[Line](defaultTextBufSize),
|
Paras: ring.NewBuffer[Para](defaultTextBufSize),
|
||||||
|
|
||||||
textBuf: ring.NewBuffer[byte](defaultTextBufSize),
|
textBuf: ring.NewBuffer[byte](defaultTextBufSize),
|
||||||
|
|
||||||
@ -263,34 +262,6 @@ func (p *program) Update() {
|
|||||||
p.MainUpdate()
|
p.MainUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) WriteToTextBuf(text []byte) {
|
|
||||||
// This is locked because running cmds are potentially writing to it same time we are
|
|
||||||
p.textBufMutex.Lock()
|
|
||||||
p.ParseLines(text)
|
|
||||||
p.textBuf.Write(text...)
|
|
||||||
p.textBufMutex.Unlock()
|
|
||||||
|
|
||||||
// @Todo we need better handling here
|
|
||||||
p.scrollPos = clamp(p.Lines.Len-p.CellCountY+3, 0, p.Lines.Len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *program) WriteToCmdBuf(text []rune) {
|
|
||||||
|
|
||||||
delta := int64(len(text))
|
|
||||||
newHeadPos := p.cmdBufLen + delta
|
|
||||||
if newHeadPos <= defaultCmdBufSize {
|
|
||||||
|
|
||||||
copy(p.cmdBuf[p.cursorCharIndex+delta:], p.cmdBuf[p.cursorCharIndex:])
|
|
||||||
copy(p.cmdBuf[p.cursorCharIndex:], text)
|
|
||||||
|
|
||||||
p.cursorCharIndex += delta
|
|
||||||
p.cmdBufLen = newHeadPos
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.T(false, "Circular buffer not implemented for cmd buf")
|
|
||||||
}
|
|
||||||
|
|
||||||
var sepLinePos = gglm.NewVec3(0, 0, 0)
|
var sepLinePos = gglm.NewVec3(0, 0, 0)
|
||||||
|
|
||||||
func (p *program) MainUpdate() {
|
func (p *program) MainUpdate() {
|
||||||
@ -322,7 +293,7 @@ func (p *program) MainUpdate() {
|
|||||||
p.scrollPos++
|
p.scrollPos++
|
||||||
}
|
}
|
||||||
|
|
||||||
p.scrollPos = clamp(p.scrollPos, 0, p.Lines.Len)
|
p.scrollPos = clamp(p.scrollPos, 0, p.Paras.Len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete inputs
|
// Delete inputs
|
||||||
@ -339,12 +310,17 @@ func (p *program) MainUpdate() {
|
|||||||
sepLinePos.SetY(2 * p.GlyphRend.Atlas.LineHeight)
|
sepLinePos.SetY(2 * p.GlyphRend.Atlas.LineHeight)
|
||||||
|
|
||||||
// Draw textBuf
|
// Draw textBuf
|
||||||
linesIt := p.Lines.Iterator()
|
parasIt := p.Paras.Iterator()
|
||||||
linesIt.GotoIndex(p.scrollPos)
|
parasIt.GotoIndex(p.scrollPos)
|
||||||
p.lastCmdCharPos.Data = gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0).Data
|
p.lastCmdCharPos.Data = gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0).Data
|
||||||
for v, done := linesIt.Next(); !done && p.lastCmdCharPos.Y() >= sepLinePos.Y(); v, done = linesIt.Next() {
|
for v, done := parasIt.Next(); !done && p.lastCmdCharPos.Y() >= sepLinePos.Y(); v, done = parasIt.Next() {
|
||||||
|
|
||||||
v1, v2 := p.textBuf.ViewsFromTo(v.StartIndex%uint64(p.textBuf.Cap), v.EndIndex%uint64(p.textBuf.Cap))
|
if !p.IsParaValid(&v) {
|
||||||
|
p.scrollPos++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, v2 := p.textBuf.ViewsFromToWriteCount(v.StartIndex, v.EndIndex)
|
||||||
if len(v1) > 0 && v1[0] == '\n' {
|
if len(v1) > 0 && v1[0] == '\n' {
|
||||||
v1 = v1[1:]
|
v1 = v1[1:]
|
||||||
}
|
}
|
||||||
@ -359,32 +335,8 @@ func (p *program) MainUpdate() {
|
|||||||
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(p.cmdBuf[:p.cmdBufLen], *p.lastCmdCharPos).Data
|
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(p.cmdBuf[:p.cmdBufLen], *p.lastCmdCharPos).Data
|
||||||
}
|
}
|
||||||
|
|
||||||
func bytesToRunes(b []byte) []rune {
|
|
||||||
|
|
||||||
runeCount := utf8.RuneCount(b)
|
|
||||||
if runeCount == 0 {
|
|
||||||
return []rune{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @PERF We should use a pre-allocated buffer here
|
|
||||||
out := make([]rune, 0, runeCount)
|
|
||||||
for {
|
|
||||||
|
|
||||||
r, size := utf8.DecodeRune(b)
|
|
||||||
if r == utf8.RuneError {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
out = append(out, r)
|
|
||||||
b = b[size:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *program) DrawTextAnsiCodes(bs []byte, pos gglm.Vec3) gglm.Vec3 {
|
func (p *program) DrawTextAnsiCodes(bs []byte, pos gglm.Vec3) gglm.Vec3 {
|
||||||
|
|
||||||
startPos := pos.Clone()
|
|
||||||
currColor := p.Settings.DefaultColor
|
currColor := p.Settings.DefaultColor
|
||||||
|
|
||||||
draw := func(rs []rune) {
|
draw := func(rs []rune) {
|
||||||
@ -397,7 +349,7 @@ func (p *program) DrawTextAnsiCodes(bs []byte, pos gglm.Vec3) gglm.Vec3 {
|
|||||||
// @PERF We could probably use bytes.IndexByte here
|
// @PERF We could probably use bytes.IndexByte here
|
||||||
if r == '\n' {
|
if r == '\n' {
|
||||||
pos.Data = p.GlyphRend.DrawTextOpenGLAbsRectWithStartPos(rs[startIndex:i], &pos, gglm.NewVec3(0, 0, 0), gglm.NewVec2(float32(p.GlyphRend.ScreenWidth), 2*p.GlyphRend.Atlas.LineHeight), &currColor).Data
|
pos.Data = p.GlyphRend.DrawTextOpenGLAbsRectWithStartPos(rs[startIndex:i], &pos, gglm.NewVec3(0, 0, 0), gglm.NewVec2(float32(p.GlyphRend.ScreenWidth), 2*p.GlyphRend.Atlas.LineHeight), &currColor).Data
|
||||||
pos.SetX(startPos.X())
|
pos.SetX(0)
|
||||||
pos.AddY(-p.GlyphRend.Atlas.LineHeight)
|
pos.AddY(-p.GlyphRend.Atlas.LineHeight)
|
||||||
startIndex = i + 1
|
startIndex = i + 1
|
||||||
continue
|
continue
|
||||||
@ -666,7 +618,7 @@ func (p *program) HandleReturn() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) ParseLines(bs []byte) {
|
func (p *program) ParseParas(bs []byte) {
|
||||||
|
|
||||||
checkedBytes := uint64(0)
|
checkedBytes := uint64(0)
|
||||||
for len(bs) > 0 {
|
for len(bs) > 0 {
|
||||||
@ -679,19 +631,19 @@ func (p *program) ParseLines(bs []byte) {
|
|||||||
bs = bs[index+1:]
|
bs = bs[index+1:]
|
||||||
|
|
||||||
checkedBytes += uint64(index + 1)
|
checkedBytes += uint64(index + 1)
|
||||||
p.CurrLine.EndIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
p.CurrPara.EndIndex = p.textBuf.WrittenElements + checkedBytes
|
||||||
p.WriteLine(&p.CurrLine)
|
p.WritePara(&p.CurrPara)
|
||||||
p.CurrLine.StartIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
p.CurrPara.StartIndex = p.textBuf.WrittenElements + checkedBytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) WriteLine(l *Line) {
|
func (p *program) WritePara(para *Para) {
|
||||||
assert.T(l.StartIndex <= l.EndIndex, "Invalid line: %+v\n", l)
|
assert.T(para.StartIndex <= para.EndIndex, "Invalid line: %+v\n", para)
|
||||||
p.Lines.Write(*l)
|
p.Paras.Write(*para)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) IsLineValid(l *Line) bool {
|
func (p *program) IsParaValid(l *Para) bool {
|
||||||
isValid := p.textBuf.WrittenElements-l.StartIndex <= uint64(p.textBuf.Cap)
|
isValid := p.textBuf.WrittenElements-l.StartIndex < uint64(p.textBuf.Cap)
|
||||||
return isValid
|
return isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,6 +797,36 @@ func (p *program) HandleWindowResize() {
|
|||||||
p.CellCount = p.CellCountX * p.CellCountY
|
p.CellCount = p.CellCountX * p.CellCountY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *program) WriteToTextBuf(text []byte) {
|
||||||
|
// This is locked because running cmds are potentially writing to it same time we are
|
||||||
|
p.textBufMutex.Lock()
|
||||||
|
|
||||||
|
p.ParseParas(text)
|
||||||
|
p.textBuf.Write(text...)
|
||||||
|
|
||||||
|
p.textBufMutex.Unlock()
|
||||||
|
|
||||||
|
// @Todo we need better handling here
|
||||||
|
p.scrollPos = clamp(p.Paras.Len-p.CellCountY+3, 0, p.Paras.Len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *program) WriteToCmdBuf(text []rune) {
|
||||||
|
|
||||||
|
delta := int64(len(text))
|
||||||
|
newHeadPos := p.cmdBufLen + delta
|
||||||
|
if newHeadPos <= defaultCmdBufSize {
|
||||||
|
|
||||||
|
copy(p.cmdBuf[p.cursorCharIndex+delta:], p.cmdBuf[p.cursorCharIndex:])
|
||||||
|
copy(p.cmdBuf[p.cursorCharIndex:], text)
|
||||||
|
|
||||||
|
p.cursorCharIndex += delta
|
||||||
|
p.cmdBufLen = newHeadPos
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.T(false, "Circular buffer not implemented for cmd buf")
|
||||||
|
}
|
||||||
|
|
||||||
func FloorF32(x float32) float32 {
|
func FloorF32(x float32) float32 {
|
||||||
return float32(math.Floor(float64(x)))
|
return float32(math.Floor(float64(x)))
|
||||||
}
|
}
|
||||||
@ -870,6 +852,29 @@ func clamp[T constraints.Ordered](x, min, max T) T {
|
|||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bytesToRunes(b []byte) []rune {
|
||||||
|
|
||||||
|
runeCount := utf8.RuneCount(b)
|
||||||
|
if runeCount == 0 {
|
||||||
|
return []rune{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PERF We should use a pre-allocated buffer here
|
||||||
|
out := make([]rune, 0, runeCount)
|
||||||
|
for {
|
||||||
|
|
||||||
|
r, size := utf8.DecodeRune(b)
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, r)
|
||||||
|
b = b[size:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func FindNthOrLastIndex[T comparable](arr []T, x T, startIndex, n int64) (lastIndex int64) {
|
func FindNthOrLastIndex[T comparable](arr []T, x T, startIndex, n int64) (lastIndex int64) {
|
||||||
|
|
||||||
lastIndex = -1
|
lastIndex = -1
|
||||||
|
|||||||
51
ring/ring.go
51
ring/ring.go
@ -1,6 +1,7 @@
|
|||||||
package ring
|
package ring
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/bloeys/nterm/assert"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -73,10 +74,46 @@ func (b *Buffer[T]) Get(index uint64) (val T) {
|
|||||||
return b.Data[(b.Start+int64(index))%b.Cap]
|
return b.Data[(b.Start+int64(index))%b.Cap]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Buffer[T]) AbsIndex(relIndex uint64) uint64 {
|
// AbsIndexFromRel takes an index relative to Buffer.Start and returns an absolute index into Buffer.Data
|
||||||
|
func (b *Buffer[T]) AbsIndexFromRel(relIndex uint64) uint64 {
|
||||||
return uint64((b.Start + int64(relIndex)) % b.Cap)
|
return uint64((b.Start + int64(relIndex)) % b.Cap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelIndexFromAbs takes an index into Buffer.Data and returns an index relative to Buffer.Start
|
||||||
|
func (b *Buffer[T]) RelIndexFromAbs(absIndex uint64) uint64 {
|
||||||
|
assert.T(absIndex < uint64(b.Cap), "absIndex must be between 0 and Buffer.Cap-1")
|
||||||
|
return uint64((int64(absIndex) - b.Start + b.Cap) % b.Cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbsIndexFromWriteCount takes the total number of elements written and returns the index of the
|
||||||
|
// last written element after 'writeCount' writes.
|
||||||
|
//
|
||||||
|
// For example, if writeCount=1 then the index of last written element (the returned value) is zero.
|
||||||
|
// For a buffer of cap=4, after 5 writes the last updated index is absIndex=0
|
||||||
|
//
|
||||||
|
// writeCount=0 is undefined because no elements have been written to yet. In this case zero is returned.
|
||||||
|
func (b *Buffer[T]) AbsIndexFromWriteCount(writeCount uint64) uint64 {
|
||||||
|
if writeCount == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return (writeCount - 1) % uint64(b.Cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelIndexFromWriteCount takes the total number of elements written and returns the index of the
|
||||||
|
// last written element after 'writeCount' writes relative to the current Buffer.Start value.
|
||||||
|
//
|
||||||
|
// For example, if writeCount=1 then the index of last written element (the returned value) is zero.
|
||||||
|
// For a buffer of cap=4, after 5 writes the last updated index is absIndex=0
|
||||||
|
//
|
||||||
|
// writeCount=0 is undefined because no elements have been written to yet. In this case zero is returned.
|
||||||
|
func (b *Buffer[T]) RelIndexFromWriteCount(writeCount uint64) uint64 {
|
||||||
|
if writeCount == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return b.RelIndexFromAbs(b.AbsIndexFromWriteCount(writeCount))
|
||||||
|
}
|
||||||
|
|
||||||
// Views returns two slices that have 'Len' elements in total between them.
|
// Views returns two slices that have 'Len' elements in total between them.
|
||||||
// The first slice is from Start till min(Start+Len, Cap). If Start+Len<=Cap then the first slice contains all the data and the second is empty.
|
// The first slice is from Start till min(Start+Len, Cap). If Start+Len<=Cap then the first slice contains all the data and the second is empty.
|
||||||
// If Start+Len>Cap then the first slice contains the data from Start till Cap, and the second slice contains data from 0 till Start+Len-Cap (basically the remaining elements to reach Len in total)
|
// If Start+Len>Cap then the first slice contains the data from Start till Cap, and the second slice contains data from 0 till Start+Len-Cap (basically the remaining elements to reach Len in total)
|
||||||
@ -91,11 +128,19 @@ func (b *Buffer[T]) Views() (v1, v2 []T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v1 = b.Data[b.Start:]
|
v1 = b.Data[b.Start:]
|
||||||
v2 = b.Data[:b.Start+b.Len-b.Cap]
|
v2 = b.Data[:(b.Start+b.Len)%b.Cap]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Buffer[T]) ViewsFromTo(fromIndex, toIndex uint64) (v1, v2 []T) {
|
func (b *Buffer[T]) ViewsFromToWriteCount(fromIndex, toIndex uint64) (v1, v2 []T) {
|
||||||
|
fromIndex = b.RelIndexFromWriteCount(fromIndex)
|
||||||
|
toIndex = b.RelIndexFromWriteCount(toIndex)
|
||||||
|
return b.ViewsFromToRelIndex(fromIndex, toIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ViewsFromToRelIndex takes indices relative to Buffer.Start and returns views adjusted to contain
|
||||||
|
// elements between these two indices (inclusive)
|
||||||
|
func (b *Buffer[T]) ViewsFromToRelIndex(fromIndex, toIndex uint64) (v1, v2 []T) {
|
||||||
|
|
||||||
toIndex++ // We convert the index into a length (e.g. from=0, to=0 is from=0, len=1)
|
toIndex++ // We convert the index into a length (e.g. from=0, to=0 is from=0, len=1)
|
||||||
if toIndex <= fromIndex || fromIndex >= uint64(b.Len) {
|
if toIndex <= fromIndex || fromIndex >= uint64(b.Len) {
|
||||||
|
|||||||
@ -71,77 +71,77 @@ func TestRing(t *testing.T) {
|
|||||||
// ViewsFromTo
|
// ViewsFromTo
|
||||||
b2 = ring.NewBuffer[int](4)
|
b2 = ring.NewBuffer[int](4)
|
||||||
|
|
||||||
v11, v22 := b2.ViewsFromTo(0, 0)
|
v11, v22 := b2.ViewsFromToRelIndex(0, 0)
|
||||||
Check(t, 0, len(v11))
|
Check(t, 0, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
|
|
||||||
b2.Write(1, 2, 3, 4)
|
b2.Write(1, 2, 3, 4)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(5, 0)
|
v11, v22 = b2.ViewsFromToRelIndex(5, 0)
|
||||||
Check(t, 0, len(v11))
|
Check(t, 0, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 0)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 0)
|
||||||
Check(t, 1, len(v11))
|
Check(t, 1, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{1}, v11)
|
CheckArr(t, []int{1}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 1)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 1)
|
||||||
Check(t, 2, len(v11))
|
Check(t, 2, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{1, 2}, v11)
|
CheckArr(t, []int{1, 2}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 3)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 3)
|
||||||
Check(t, 4, len(v11))
|
Check(t, 4, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 4)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 4)
|
||||||
Check(t, 4, len(v11))
|
Check(t, 4, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 40)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 40)
|
||||||
Check(t, 4, len(v11))
|
Check(t, 4, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
CheckArr(t, []int{1, 2, 3, 4}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(3, 40)
|
v11, v22 = b2.ViewsFromToRelIndex(3, 40)
|
||||||
Check(t, 1, len(v11))
|
Check(t, 1, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{4}, v11)
|
CheckArr(t, []int{4}, v11)
|
||||||
|
|
||||||
b2.Write(5, 6)
|
b2.Write(5, 6)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(3, 40)
|
v11, v22 = b2.ViewsFromToRelIndex(3, 40)
|
||||||
Check(t, 0, len(v11))
|
Check(t, 0, len(v11))
|
||||||
Check(t, 1, len(v22))
|
Check(t, 1, len(v22))
|
||||||
CheckArr(t, []int{6}, v22)
|
CheckArr(t, []int{6}, v22)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(1, 2)
|
v11, v22 = b2.ViewsFromToRelIndex(1, 2)
|
||||||
Check(t, 1, len(v11))
|
Check(t, 1, len(v11))
|
||||||
Check(t, 1, len(v22))
|
Check(t, 1, len(v22))
|
||||||
CheckArr(t, []int{4}, v11)
|
CheckArr(t, []int{4}, v11)
|
||||||
CheckArr(t, []int{5}, v22)
|
CheckArr(t, []int{5}, v22)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 1)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 1)
|
||||||
Check(t, 2, len(v11))
|
Check(t, 2, len(v11))
|
||||||
Check(t, 0, len(v22))
|
Check(t, 0, len(v22))
|
||||||
CheckArr(t, []int{3, 4}, v11)
|
CheckArr(t, []int{3, 4}, v11)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 2)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 2)
|
||||||
Check(t, 2, len(v11))
|
Check(t, 2, len(v11))
|
||||||
Check(t, 1, len(v22))
|
Check(t, 1, len(v22))
|
||||||
CheckArr(t, []int{3, 4}, v11)
|
CheckArr(t, []int{3, 4}, v11)
|
||||||
CheckArr(t, []int{5}, v22)
|
CheckArr(t, []int{5}, v22)
|
||||||
|
|
||||||
v11, v22 = b2.ViewsFromTo(0, 3)
|
v11, v22 = b2.ViewsFromToRelIndex(0, 3)
|
||||||
Check(t, 2, len(v11))
|
Check(t, 2, len(v11))
|
||||||
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)
|
v11, v22 = b2.ViewsFromToRelIndex(2, 3)
|
||||||
Check(t, 0, len(v11))
|
Check(t, 0, len(v11))
|
||||||
Check(t, 2, len(v22))
|
Check(t, 2, len(v22))
|
||||||
CheckArr(t, []int{5, 6}, v22)
|
CheckArr(t, []int{5, 6}, v22)
|
||||||
|
|||||||
Reference in New Issue
Block a user