@@ -25,13 +25,14 @@ import (
2525)
2626
2727type Graph struct {
28- ui gui.GUI
29- Term * terminal.Terminal
30- dataChannel <- chan ping.PingResults
31- data * graphdata.GraphData
32- frameMutex * sync.Mutex
33- drawingBuffer * draw.Buffer
34- presentation * controlState
28+ ui gui.GUI
29+ Term * terminal.Terminal
30+ dataChannel <- chan ping.PingResults
31+ data * graphdata.GraphData
32+ frameMutex * sync.Mutex
33+ drawingBuffer * draw.Buffer
34+ presentation * controlState
35+
3536 controlChannel <- chan Control
3637 lastFrame frame
3738 initial ping.PingsPerMinute
@@ -128,12 +129,9 @@ func NewGraph(ctx context.Context, cfg GraphConfiguration) *Graph {
128129func (g * Graph ) Run (
129130 ctx context.Context ,
130131 stop context.CancelCauseFunc ,
131- fps int , // this isn't really an FPS given how the GUI is setup and paint buffers, more like a max re-paint delay timer thing.
132132 listeners []terminal.ConditionalListener ,
133133 fallbacks []terminal.Listener ,
134134) (func () error , func (), <- chan terminal.Size , error ) {
135- timeBetweenFrames := getTimeBetweenFrames (fps , g .initial )
136- frameRate := time .NewTicker (timeBetweenFrames )
137135 cleanup , err := g .Term .StartRaw (ctx , stop , listeners , fallbacks )
138136 if err != nil {
139137 return nil , cleanup , nil , err
@@ -143,12 +141,14 @@ func (g *Graph) Run(
143141 size := g .Term .GetSize ()
144142 defer close (terminalUpdates )
145143 slog .Info ("running acci-ping" )
144+ // The main loop of acci-ping, await on the context (will be fired by the terminal)
146145 for {
147146 select {
148147 case <- ctx .Done ():
149148 return context .Cause (ctx )
150- case <- frameRate .C :
151- err = g .Term .UpdateSize ()
149+ default :
150+ // The main body of acci-ping, get the terminal size and send on the channel if changed
151+ err := g .Term .UpdateSize ()
152152 if err != nil {
153153 return err
154154 }
@@ -157,14 +157,18 @@ func (g *Graph) Run(
157157 terminalUpdates <- size
158158 size = g .Term .GetSize ()
159159 }
160+ // Lock the presentation layer (this ensures we don't get GUI tearing - as in one component
161+ // has data from last frame and another component has data from this frame), compute a new
162+ // frame. Note that the optimisations to do no drawing are all in this function.
160163 g .presentation .m .Lock ()
161164 toWrite := g .computeFrame (computeFrameConfig {
162- timeBetweenFrames : timeBetweenFrames ,
163- followLatestSpan : g .presentation .Following ,
164- drawSpinner : true ,
165- yAxisScale : g .presentation .YAxisScale ,
165+ followLatestSpan : g .presentation .Following ,
166+ drawSpinner : true ,
167+ yAxisScale : g .presentation .YAxisScale ,
166168 })
167169 g .presentation .m .Unlock ()
170+ // Now that we have a frame to draw (may just be a spinner update), execute this function
171+ // writing the painted frame to the terminal.
168172 err = toWrite (g .Term )
169173 if err != nil {
170174 return err
0 commit comments