mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 14:38:19 +00:00
Starting using lines to render+rect glyph draw funcs
This commit is contained in:
@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
func T(check bool, msg string, args ...any) {
|
func T(check bool, msg string, args ...any) {
|
||||||
if consts.Mode_Debug && !check {
|
if consts.Mode_Debug && !check {
|
||||||
|
// Sprintf is done inside the assert because putting it as the argument to 'msg' blocks
|
||||||
|
// the function from getting fully optimized out on a release build (and slower in general)
|
||||||
panic("Assert failed: " + fmt.Sprintf(msg, args...))
|
panic("Assert failed: " + fmt.Sprintf(msg, args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
179
glyphs/glyphs.go
179
glyphs/glyphs.go
@ -74,15 +74,15 @@ func (gr *GlyphRend) DrawTextOpenGL01(text []rune, screenPos *gglm.Vec3, color *
|
|||||||
//DrawTextOpenGLAbsString prepares text that will be drawn on the next GlyphRend.Draw call.
|
//DrawTextOpenGLAbsString prepares text that will be drawn on the next GlyphRend.Draw call.
|
||||||
//screenPos is in the range ([0,ScreenWidth],[0,ScreenHeight]) where (0,0) is bottom left.
|
//screenPos is in the range ([0,ScreenWidth],[0,ScreenHeight]) where (0,0) is bottom left.
|
||||||
//Color is RGBA in the range [0,1].
|
//Color is RGBA in the range [0,1].
|
||||||
func (gr *GlyphRend) DrawTextOpenGLAbs(text []rune, screenPos *gglm.Vec3, color *gglm.Vec4) gglm.Vec3 {
|
func (gr *GlyphRend) DrawTextOpenGLAbs(text []rune, startPos *gglm.Vec3, color *gglm.Vec4) gglm.Vec3 {
|
||||||
|
|
||||||
runs := gr.TextRunsBuf[:]
|
runs := gr.TextRunsBuf[:]
|
||||||
gr.GetTextRuns(text, &runs)
|
gr.GetTextRuns(text, &runs)
|
||||||
if runs == nil {
|
if runs == nil {
|
||||||
return *screenPos
|
return *startPos
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := screenPos.Clone()
|
drawPos := startPos.Clone()
|
||||||
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
||||||
bufIndex := gr.GlyphCount * floatsPerGlyph
|
bufIndex := gr.GlyphCount * floatsPerGlyph
|
||||||
for runIndex := 0; runIndex < len(runs); runIndex++ {
|
for runIndex := 0; runIndex < len(runs); runIndex++ {
|
||||||
@ -94,26 +94,39 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text []rune, screenPos *gglm.Vec3, color
|
|||||||
if run.IsLtr {
|
if run.IsLtr {
|
||||||
|
|
||||||
for i := 0; i < len(run.Runes); i++ {
|
for i := 0; i < len(run.Runes); i++ {
|
||||||
gr.drawRune(run, i, prevRune, screenPos, pos, color, lineHeightF32, &bufIndex)
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(startPos.X(), drawPos.Y()-lineHeightF32, startPos.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
prevRune = run.Runes[i]
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
//Wrap
|
//Wrap
|
||||||
if pos.X()+gr.Atlas.SpaceAdvance >= screenWidthF32 {
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= screenWidthF32 {
|
||||||
screenPos.SetY(screenPos.Y() - lineHeightF32)
|
|
||||||
*pos = *screenPos.Clone()
|
drawPos.SetXYZ(startPos.X(), drawPos.Y()-lineHeightF32, startPos.Z())
|
||||||
|
// startPos.SetY(startPos.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *startPos.Clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for i := len(run.Runes) - 1; i >= 0; i-- {
|
for i := len(run.Runes) - 1; i >= 0; i-- {
|
||||||
gr.drawRune(run, i, prevRune, screenPos, pos, color, lineHeightF32, &bufIndex)
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(startPos.X(), drawPos.Y()-lineHeightF32, startPos.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
prevRune = run.Runes[i]
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
//Wrap
|
//Wrap
|
||||||
if pos.X()+gr.Atlas.SpaceAdvance >= screenWidthF32 {
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= screenWidthF32 {
|
||||||
screenPos.SetY(screenPos.Y() - lineHeightF32)
|
drawPos.SetXYZ(startPos.X(), drawPos.Y()-lineHeightF32, startPos.Z())
|
||||||
*pos = *screenPos.Clone()
|
// startPos.SetY(startPos.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *startPos.Clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,20 +137,146 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text []rune, screenPos *gglm.Vec3, color
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *pos
|
return *drawPos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gr *GlyphRend) DrawTextOpenGLAbsRect(text []rune, rectTopLeft *gglm.Vec3, rectBotRight *gglm.Vec2, color *gglm.Vec4) gglm.Vec3 {
|
||||||
|
|
||||||
|
runs := gr.TextRunsBuf[:]
|
||||||
|
gr.GetTextRuns(text, &runs)
|
||||||
|
if runs == nil {
|
||||||
|
return *rectTopLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPos := rectTopLeft.Clone()
|
||||||
|
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
||||||
|
bufIndex := gr.GlyphCount * floatsPerGlyph
|
||||||
|
for runIndex := 0; runIndex < len(runs); runIndex++ {
|
||||||
|
|
||||||
|
run := &runs[runIndex]
|
||||||
|
prevRune := invalidRune
|
||||||
|
|
||||||
|
if run.IsLtr {
|
||||||
|
|
||||||
|
for i := 0; i < len(run.Runes); i++ {
|
||||||
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
|
//Wrap
|
||||||
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= rectBotRight.X() {
|
||||||
|
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
// rectTopLeft.SetY(rectTopLeft.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *rectTopLeft.Clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for i := len(run.Runes) - 1; i >= 0; i-- {
|
||||||
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
|
//Wrap
|
||||||
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= rectBotRight.X() {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
// rectTopLeft.SetY(rectTopLeft.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *rectTopLeft.Clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if consts.Mode_Debug && PrintPositions {
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *drawPos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gr *GlyphRend) DrawTextOpenGLAbsRectWithStartPos(text []rune, startPos, rectTopLeft *gglm.Vec3, rectBotRight *gglm.Vec2, color *gglm.Vec4) gglm.Vec3 {
|
||||||
|
|
||||||
|
runs := gr.TextRunsBuf[:]
|
||||||
|
gr.GetTextRuns(text, &runs)
|
||||||
|
if runs == nil {
|
||||||
|
return *startPos
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPos := startPos.Clone()
|
||||||
|
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
||||||
|
bufIndex := gr.GlyphCount * floatsPerGlyph
|
||||||
|
for runIndex := 0; runIndex < len(runs); runIndex++ {
|
||||||
|
|
||||||
|
run := &runs[runIndex]
|
||||||
|
prevRune := invalidRune
|
||||||
|
|
||||||
|
if run.IsLtr {
|
||||||
|
|
||||||
|
for i := 0; i < len(run.Runes); i++ {
|
||||||
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
|
//Wrap
|
||||||
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= rectBotRight.X() {
|
||||||
|
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
// rectTopLeft.SetY(rectTopLeft.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *rectTopLeft.Clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for i := len(run.Runes) - 1; i >= 0; i-- {
|
||||||
|
|
||||||
|
if run.Runes[i] == '\n' {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.drawRune(run, i, prevRune, drawPos, color, lineHeightF32, &bufIndex)
|
||||||
|
prevRune = run.Runes[i]
|
||||||
|
|
||||||
|
//Wrap
|
||||||
|
if drawPos.X()+gr.Atlas.SpaceAdvance >= rectBotRight.X() {
|
||||||
|
drawPos.SetXYZ(rectTopLeft.X(), drawPos.Y()-lineHeightF32, rectTopLeft.Z())
|
||||||
|
// rectTopLeft.SetY(rectTopLeft.Y() - lineHeightF32)
|
||||||
|
// *drawPos = *rectTopLeft.Clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if consts.Mode_Debug && PrintPositions {
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *drawPos
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Debug
|
// @Debug
|
||||||
var PrintPositions bool
|
var PrintPositions bool
|
||||||
|
|
||||||
func (gr *GlyphRend) drawRune(run *TextRun, i int, prevRune rune, screenPos, pos *gglm.Vec3, color *gglm.Vec4, lineHeightF32 float32, bufIndex *uint32) {
|
func (gr *GlyphRend) drawRune(run *TextRun, i int, prevRune rune, pos *gglm.Vec3, color *gglm.Vec4, lineHeightF32 float32, bufIndex *uint32) {
|
||||||
|
|
||||||
r := run.Runes[i]
|
r := run.Runes[i]
|
||||||
if r == '\n' {
|
if r == ' ' {
|
||||||
screenPos.SetY(screenPos.Y() - lineHeightF32)
|
|
||||||
*pos = *screenPos.Clone()
|
|
||||||
return
|
|
||||||
} else if r == ' ' {
|
|
||||||
pos.AddX(gr.Atlas.SpaceAdvance)
|
pos.AddX(gr.Atlas.SpaceAdvance)
|
||||||
return
|
return
|
||||||
} else if r == '\t' {
|
} else if r == '\t' {
|
||||||
@ -398,9 +537,11 @@ func (gr *GlyphRend) Draw() {
|
|||||||
|
|
||||||
//We need to disable depth testing so that nearby characters don't occlude each other
|
//We need to disable depth testing so that nearby characters don't occlude each other
|
||||||
gl.Disable(gl.DEPTH_TEST)
|
gl.Disable(gl.DEPTH_TEST)
|
||||||
|
|
||||||
gl.DrawElementsInstanced(gl.TRIANGLES, gr.GlyphMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0), int32(gr.GlyphCount))
|
gl.DrawElementsInstanced(gl.TRIANGLES, gr.GlyphMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0), int32(gr.GlyphCount))
|
||||||
gl.Enable(gl.DEPTH_TEST)
|
|
||||||
gr.GlyphCount = 0
|
gr.GlyphCount = 0
|
||||||
|
|
||||||
|
gl.Enable(gl.DEPTH_TEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetFace updates the underlying font atlas used by the glyph renderer.
|
//SetFace updates the underlying font atlas used by the glyph renderer.
|
||||||
|
|||||||
62
main.go
62
main.go
@ -73,9 +73,9 @@ type program struct {
|
|||||||
gridMat *materials.Material
|
gridMat *materials.Material
|
||||||
|
|
||||||
CurrLine Line
|
CurrLine Line
|
||||||
CurrLineValid bool
|
// CurrLineValid bool
|
||||||
Lines []Line
|
|
||||||
LineCount uint64
|
Lines *ring.Buffer[Line]
|
||||||
|
|
||||||
textBuf *ring.Buffer[byte]
|
textBuf *ring.Buffer[byte]
|
||||||
textBufMutex sync.Mutex
|
textBufMutex sync.Mutex
|
||||||
@ -143,9 +143,7 @@ func main() {
|
|||||||
imguiInfo: nmageimgui.NewImGUI(),
|
imguiInfo: nmageimgui.NewImGUI(),
|
||||||
FontSize: 40,
|
FontSize: 40,
|
||||||
|
|
||||||
Lines: make([]Line, defaultTextBufSize),
|
Lines: ring.NewBuffer[Line](defaultTextBufSize),
|
||||||
LineCount: 0,
|
|
||||||
CurrLineValid: true,
|
|
||||||
|
|
||||||
textBuf: ring.NewBuffer[byte](defaultTextBufSize),
|
textBuf: ring.NewBuffer[byte](defaultTextBufSize),
|
||||||
|
|
||||||
@ -270,8 +268,10 @@ func (p *program) WriteToTextBuf(text []byte) {
|
|||||||
p.textBufMutex.Lock()
|
p.textBufMutex.Lock()
|
||||||
p.ParseLines(text)
|
p.ParseLines(text)
|
||||||
p.textBuf.Write(text...)
|
p.textBuf.Write(text...)
|
||||||
p.scrollPos = clamp(p.textBuf.Len-p.CellCount, 0, p.textBuf.Len-1)
|
|
||||||
p.textBufMutex.Unlock()
|
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) {
|
func (p *program) WriteToCmdBuf(text []rune) {
|
||||||
@ -316,14 +316,13 @@ func (p *program) MainUpdate() {
|
|||||||
|
|
||||||
if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 {
|
if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 {
|
||||||
|
|
||||||
var newPosNewLines int64
|
|
||||||
if mouseWheelYNorm < 0 {
|
if mouseWheelYNorm < 0 {
|
||||||
newPosNewLines, _ = findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm-1, p.CellCountX)
|
p.scrollPos--
|
||||||
} else {
|
} else {
|
||||||
newPosNewLines, _ = findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.scrollSpd*mouseWheelYNorm, p.CellCountX)
|
p.scrollPos++
|
||||||
}
|
}
|
||||||
|
|
||||||
p.scrollPos = clamp(newPosNewLines, 0, p.textBuf.Len)
|
p.scrollPos = clamp(p.scrollPos, 0, p.Lines.Len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete inputs
|
// Delete inputs
|
||||||
@ -336,26 +335,27 @@ func (p *program) MainUpdate() {
|
|||||||
p.DeleteNextChar()
|
p.DeleteNextChar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Line separator
|
||||||
|
sepLinePos.SetY(2 * p.GlyphRend.Atlas.LineHeight)
|
||||||
|
|
||||||
// Draw textBuf
|
// Draw textBuf
|
||||||
from := p.scrollPos
|
linesIt := p.Lines.Iterator()
|
||||||
to, _ := findNLinesIndexIterator(p.textBuf.Iterator(), p.scrollPos, p.CellCountY-2, p.CellCountX)
|
linesIt.GotoIndex(p.scrollPos)
|
||||||
assert.T(to >= 0, "'to' was less than zero")
|
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() {
|
||||||
|
|
||||||
// to is the first character after the nth line. Passing this index to ViewsFromTo will show 1 more char than we want,
|
v1, v2 := p.textBuf.ViewsFromTo(v.StartIndex%uint64(p.textBuf.Cap), v.EndIndex%uint64(p.textBuf.Cap))
|
||||||
// so we decrement if needed
|
if len(v1) > 0 && v1[0] == '\n' {
|
||||||
if to > 0 {
|
v1 = v1[1:]
|
||||||
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, *p.lastCmdCharPos).Data
|
||||||
p.lastCmdCharPos.Data = p.DrawTextAnsiCodes(v2, *p.lastCmdCharPos).Data
|
p.lastCmdCharPos.Data = p.DrawTextAnsiCodes(v2, *p.lastCmdCharPos).Data
|
||||||
|
}
|
||||||
sepLinePos.Data = p.lastCmdCharPos.Data
|
|
||||||
|
|
||||||
// Draw cmd buf
|
// Draw cmd buf
|
||||||
p.lastCmdCharPos.SetX(0)
|
p.lastCmdCharPos.SetX(0)
|
||||||
p.lastCmdCharPos.AddY(-p.GlyphRend.Atlas.LineHeight)
|
p.lastCmdCharPos.SetY(sepLinePos.Y() - p.GlyphRend.Atlas.LineHeight)
|
||||||
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(p.cmdBuf[:p.cmdBufLen], *p.lastCmdCharPos).Data
|
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(p.cmdBuf[:p.cmdBufLen], *p.lastCmdCharPos).Data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +396,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.DrawTextOpenGLAbs(rs[startIndex:i], &pos, &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(startPos.X())
|
||||||
pos.AddY(-p.GlyphRend.Atlas.LineHeight)
|
pos.AddY(-p.GlyphRend.Atlas.LineHeight)
|
||||||
startIndex = i + 1
|
startIndex = i + 1
|
||||||
@ -405,7 +405,7 @@ func (p *program) DrawTextAnsiCodes(bs []byte, pos gglm.Vec3) gglm.Vec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if startIndex < len(rs) {
|
if startIndex < len(rs) {
|
||||||
pos.Data = p.GlyphRend.DrawTextOpenGLAbs(rs[startIndex:], &pos, &currColor).Data
|
pos.Data = p.GlyphRend.DrawTextOpenGLAbsRectWithStartPos(rs[startIndex:], &pos, gglm.NewVec3(0, 0, 0), gglm.NewVec2(float32(p.GlyphRend.ScreenWidth), 2*p.GlyphRend.Atlas.LineHeight), &currColor).Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,21 +679,15 @@ func (p *program) ParseLines(bs []byte) {
|
|||||||
bs = bs[index+1:]
|
bs = bs[index+1:]
|
||||||
|
|
||||||
checkedBytes += uint64(index + 1)
|
checkedBytes += uint64(index + 1)
|
||||||
if p.CurrLineValid {
|
|
||||||
p.CurrLine.EndIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
p.CurrLine.EndIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
||||||
p.WriteLine(&p.CurrLine)
|
p.WriteLine(&p.CurrLine)
|
||||||
p.CurrLine.StartIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
p.CurrLine.StartIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
||||||
} else {
|
|
||||||
p.CurrLine.StartIndex = p.textBuf.WrittenElements + checkedBytes - 1
|
|
||||||
p.CurrLineValid = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) WriteLine(l *Line) {
|
func (p *program) WriteLine(l *Line) {
|
||||||
p.Lines[p.LineCount] = *l
|
|
||||||
p.LineCount = (p.LineCount + 1) % uint64(len(p.Lines))
|
|
||||||
assert.T(l.StartIndex <= l.EndIndex, "Invalid line: %+v\n", l)
|
assert.T(l.StartIndex <= l.EndIndex, "Invalid line: %+v\n", l)
|
||||||
|
p.Lines.Write(*l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) IsLineValid(l *Line) bool {
|
func (p *program) IsLineValid(l *Line) bool {
|
||||||
@ -913,14 +907,14 @@ func FindNthOrLastIndex[T comparable](arr []T, x T, startIndex, n int64) (lastIn
|
|||||||
return lastIndex
|
return lastIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// findNLinesIndexIterator 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 findNLinesIndexIterator(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
|
||||||
|
|
||||||
|
|||||||
10
ring/ring.go
10
ring/ring.go
@ -196,6 +196,16 @@ func (it *Iterator[T]) Next() (v T, done bool) {
|
|||||||
return v, false
|
return v, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (it *Iterator[T]) HasNext() bool {
|
||||||
|
hasNext := it.InV1 || it.Curr < int64(len(it.V2))
|
||||||
|
return hasNext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *Iterator[T]) HasPrev() bool {
|
||||||
|
hasPrev := (!it.InV1 && it.Curr-1 >= 0) || (it.InV1 && it.Curr > 0)
|
||||||
|
return hasPrev
|
||||||
|
}
|
||||||
|
|
||||||
// Next returns the value at Iterator.Curr-1 and done=false
|
// Next returns the value at Iterator.Curr-1 and done=false
|
||||||
//
|
//
|
||||||
// If there are no more values to return the default value is returned for v and done=true
|
// If there are no more values to return the default value is returned for v and done=true
|
||||||
|
|||||||
Reference in New Issue
Block a user