Use ring.Buffer in textBuf+display only needed chars+show bottom of buffer

This commit is contained in:
bloeys
2022-07-15 20:54:23 +04:00
parent 4992210bdb
commit cdcfe4c13d
2 changed files with 45 additions and 23 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@
# vendor/ # vendor/
*.png *.png
*.cpu *.cpu
1gb.txt

63
main.go
View File

@ -8,6 +8,7 @@ import (
"os/exec" "os/exec"
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"time"
"github.com/bloeys/gglm/gglm" "github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/engine" "github.com/bloeys/nmage/engine"
@ -20,6 +21,7 @@ import (
"github.com/bloeys/nterm/assert" "github.com/bloeys/nterm/assert"
"github.com/bloeys/nterm/consts" "github.com/bloeys/nterm/consts"
"github.com/bloeys/nterm/glyphs" "github.com/bloeys/nterm/glyphs"
"github.com/bloeys/nterm/ring"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
"golang.org/x/exp/constraints" "golang.org/x/exp/constraints"
@ -52,8 +54,7 @@ type program struct {
gridMesh *meshes.Mesh gridMesh *meshes.Mesh
gridMat *materials.Material gridMat *materials.Material
textBuf []rune textBuf *ring.Buffer[rune]
textBufLen int64
cmdBuf []rune cmdBuf []rune
cmdBufLen int64 cmdBufLen int64
@ -63,6 +64,8 @@ type program struct {
lastCmdCharPos *gglm.Vec3 lastCmdCharPos *gglm.Vec3
scrollPos int64 scrollPos int64
scrollSpd int64 scrollSpd int64
maxCharsToShow int64
maxLinesToShow int64
activeCmd *Cmd activeCmd *Cmd
@ -112,8 +115,7 @@ func main() {
imguiInfo: nmageimgui.NewImGUI(), imguiInfo: nmageimgui.NewImGUI(),
FontSize: 40, FontSize: 40,
textBuf: make([]rune, defaultTextBufSize), textBuf: ring.NewBuffer[rune](defaultTextBufSize),
textBufLen: 0,
cursorCharIndex: 0, cursorCharIndex: 0,
lastCmdCharPos: gglm.NewVec3(0, 0, 0), lastCmdCharPos: gglm.NewVec3(0, 0, 0),
@ -217,10 +219,10 @@ func (p *program) Update() {
err := p.GlyphRend.SetFace(&truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY, Hinting: hinting}) err := p.GlyphRend.SetFace(&truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY, Hinting: hinting})
if err != nil { if err != nil {
p.FontSize = oldFont p.FontSize = oldFont
println("Failed to update font face. Err: " + err.Error()) fmt.Println("Failed to update font face. Err: " + err.Error())
} else { } else {
glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png") glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png")
println("New font size:", p.FontSize, "; New texture size:", p.GlyphRend.Atlas.Img.Rect.Max.X, "\n") fmt.Println("New font size:", p.FontSize, "; New texture size:", p.GlyphRend.Atlas.Img.Rect.Max.X)
} }
} }
@ -229,15 +231,8 @@ func (p *program) Update() {
// @TODO: These probably need a mutex // @TODO: These probably need a mutex
func (p *program) WriteToTextBuf(text []rune) { func (p *program) WriteToTextBuf(text []rune) {
p.textBuf.Write(text...)
newHeadPos := p.textBufLen + int64(len(text)) p.scrollPos = clamp(p.textBuf.Len-p.maxCharsToShow, 0, p.textBuf.Len-1)
if newHeadPos <= int64(len(p.textBuf)) {
copy(p.textBuf[p.textBufLen:], text)
p.textBufLen = newHeadPos
return
}
assert.T(false, "Circular buffer not implemented for text buf")
} }
func (p *program) WriteToCmdBuf(text []rune) { func (p *program) WriteToCmdBuf(text []rune) {
@ -246,11 +241,8 @@ func (p *program) WriteToCmdBuf(text []rune) {
newHeadPos := p.cmdBufLen + delta newHeadPos := p.cmdBufLen + delta
if newHeadPos <= defaultCmdBufSize { if newHeadPos <= defaultCmdBufSize {
// fmt.Println("\nBuf before delta:", p.cmdBuf[:p.cmdBufHead])
copy(p.cmdBuf[p.cursorCharIndex+delta:], p.cmdBuf[p.cursorCharIndex:]) copy(p.cmdBuf[p.cursorCharIndex+delta:], p.cmdBuf[p.cursorCharIndex:])
// fmt.Println("Buf after delta:", p.cmdBuf[:p.cmdBufHead+delta])
copy(p.cmdBuf[p.cursorCharIndex:], text) copy(p.cmdBuf[p.cursorCharIndex:], text)
// fmt.Println("Buf after write:", p.cmdBuf[:p.cmdBufHead+delta])
p.cursorCharIndex += delta p.cursorCharIndex += delta
p.cmdBufLen = newHeadPos p.cmdBufLen = newHeadPos
@ -284,7 +276,7 @@ func (p *program) MainUpdate() {
} }
if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 { if mouseWheelYNorm := -int64(input.GetMouseWheelYNorm()); mouseWheelYNorm != 0 {
p.scrollPos = clamp(p.scrollPos+p.scrollSpd*mouseWheelYNorm, 0, p.textBufLen) p.scrollPos = clamp(p.scrollPos+p.scrollSpd*mouseWheelYNorm, 0, p.textBuf.Len)
} }
// Delete inputs // Delete inputs
@ -298,7 +290,19 @@ func (p *program) MainUpdate() {
} }
//Draw textBuf //Draw textBuf
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(p.textBuf[p.scrollPos:p.textBufLen], gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0)).Data v1, v2 := p.textBuf.Views()
from := clamp(p.scrollPos, 0, int64(len(v1)-1))
to := clamp(p.scrollPos+p.maxCharsToShow, 0, int64(len(v1)-1))
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(v1[from:to], gglm.NewVec3(0, float32(p.GlyphRend.ScreenHeight)-p.GlyphRend.Atlas.LineHeight, 0)).Data
if p.scrollPos >= int64(len(v1)) {
from := clamp(p.scrollPos-int64(len(v1)), 0, int64(len(v2)-1))
to := clamp(p.scrollPos+p.maxCharsToShow, 0, int64(len(v2)-1))
p.lastCmdCharPos.Data = p.SyntaxHighlightAndDraw(v2[from:to], p.lastCmdCharPos).Data
}
sepLinePos.Data = p.lastCmdCharPos.Data sepLinePos.Data = p.lastCmdCharPos.Data
//Draw cmd buf //Draw cmd buf
@ -456,6 +460,7 @@ func (p *program) HandleReturn() {
return return
} }
startTime := time.Now()
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
p.PrintToTextBuf(fmt.Sprintf("Running '%s' failed. Error: %s\n", cmdName, err.Error())) p.PrintToTextBuf(fmt.Sprintf("Running '%s' failed. Error: %s\n", cmdName, err.Error()))
@ -471,8 +476,11 @@ func (p *program) HandleReturn() {
//Stdout //Stdout
go func() { go func() {
defer p.ClearActiveCmd() defer func() {
fmt.Printf("Cmd '%s' took %0.2fs\n", cmdName, time.Since(startTime).Seconds())
}()
defer p.ClearActiveCmd()
buf := make([]byte, 1024) buf := make([]byte, 1024)
for p.activeCmd != nil { for p.activeCmd != nil {
@ -492,6 +500,7 @@ func (p *program) HandleReturn() {
} }
p.PrintToTextBuf(string(buf[:readBytes])) p.PrintToTextBuf(string(buf[:readBytes]))
// println("Read:", string(buf[:readBytes]))
} }
}() }()
@ -656,14 +665,26 @@ func (p *program) HandleWindowResize() {
projMtx := gglm.Ortho(0, float32(w), float32(h), 0, 0.1, 20) projMtx := gglm.Ortho(0, float32(w), float32(h), 0, 0.1, 20)
viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -10), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0)) viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -10), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0))
p.gridMat.SetUnifMat4("projViewMat", &projMtx.Mul(viewMtx).Mat4) p.gridMat.SetUnifMat4("projViewMat", &projMtx.Mul(viewMtx).Mat4)
// We show a bit more than calculated to be safe against showing empty space
p.maxLinesToShow = int64(CeilF32(float32(h)/float32(p.GlyphRend.Atlas.LineHeight)) * 1.25)
p.maxCharsToShow = int64(CeilF32(float32(w)/float32(p.GlyphRend.Atlas.SpaceAdvance))*1.25) * p.maxLinesToShow
} }
func FloorF32(x float32) float32 { func FloorF32(x float32) float32 {
return float32(math.Floor(float64(x))) return float32(math.Floor(float64(x)))
} }
func CeilF32(x float32) float32 {
return float32(math.Ceil(float64(x)))
}
func clamp[T constraints.Ordered](x, min, max T) T { func clamp[T constraints.Ordered](x, min, max T) T {
if max < min {
min, max = max, min
}
if x < min { if x < min {
return min return min
} }