diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2021-04-05 10:20:02 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2021-04-06 19:34:32 +1000 |
commit | 843b8ceab0fa3888357f0e86026bebb6f4f1c305 (patch) | |
tree | 6c8b3b5be5948c62be6c3ee8144ac7c92e85cde1 /vendor | |
parent | 011451464fea4992b2dd8a09008b3e0ce45ba775 (diff) |
support tcell simulation screen
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/gui.go | 129 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/tcell_driver.go | 39 |
2 files changed, 130 insertions, 38 deletions
diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 0fd89fbb5..deeb4371a 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -85,11 +85,13 @@ const ( ) type Recording struct { - KeyEvents []*TcellKeyEventWrapper + KeyEvents []*TcellKeyEventWrapper + ResizeEvents []*TcellResizeEventWrapper } type replayedEvents struct { - keys chan *TcellKeyEventWrapper + keys chan *TcellKeyEventWrapper + resizes chan *TcellResizeEventWrapper } type RecordingConfig struct { @@ -159,14 +161,19 @@ type Gui struct { } // NewGui returns a new Gui object with a given output mode. -func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode) (*Gui, error) { - err := tcellInit() +func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless bool) (*Gui, error) { + g := &Gui{} + + var err error + if headless { + err = tcellInitSimulation() + } else { + err = tcellInit() + } if err != nil { return nil, err } - g := &Gui{} - g.outputMode = mode g.stop = make(chan struct{}) @@ -176,11 +183,13 @@ func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode) (*Gui, err if playMode == RECORDING { g.Recording = &Recording{ - KeyEvents: []*TcellKeyEventWrapper{}, + KeyEvents: []*TcellKeyEventWrapper{}, + ResizeEvents: []*TcellResizeEventWrapper{}, } } else if playMode == REPLAYING { g.ReplayedEvents = replayedEvents{ - keys: make(chan *TcellKeyEventWrapper), + keys: make(chan *TcellKeyEventWrapper), + resizes: make(chan *TcellResizeEventWrapper), } } @@ -562,8 +571,10 @@ func (g *Gui) SetManagerFunc(manager func(*Gui) error) { // MainLoop runs the main loop until an error is returned. A successful // finish should return ErrQuit. func (g *Gui) MainLoop() error { + + g.StartTime = time.Now() if g.PlayMode == REPLAYING { - g.replayRecording() + go g.replayRecording() } go func() { @@ -1182,38 +1193,80 @@ func IsQuit(err error) bool { } func (g *Gui) replayRecording() { - ticker := time.NewTicker(time.Millisecond) - defer ticker.Stop() - - // The playback could be paused at any time because integration tests run concurrently. - // Therefore we can't just check for a given event whether we've passed its timestamp, - // or else we'll have an explosion of keypresses after the test is resumed. - // We need to check if we've waited long enough since the last event was replayed. - // Only handling key events for now. - for i, event := range g.Recording.KeyEvents { - var prevEventTimestamp int64 = 0 - if i > 0 { - prevEventTimestamp = g.Recording.KeyEvents[i-1].Timestamp - } - timeToWait := (event.Timestamp - prevEventTimestamp) / int64(g.RecordingConfig.Speed) - if i == 0 { - timeToWait += int64(g.RecordingConfig.Leeway) - } - var timeWaited int64 = 0 - middle: - for { - select { - case <-ticker.C: - timeWaited += 1 - if g != nil && timeWaited >= timeToWait { - g.ReplayedEvents.keys <- event - break middle + waitGroup := sync.WaitGroup{} + + waitGroup.Add(2) + + go func() { + ticker := time.NewTicker(time.Millisecond) + defer ticker.Stop() + + // The playback could be paused at any time because integration tests run concurrently. + // Therefore we can't just check for a given event whether we've passed its timestamp, + // or else we'll have an explosion of keypresses after the test is resumed. + // We need to check if we've waited long enough since the last event was replayed. + for i, event := range g.Recording.KeyEvents { + var prevEventTimestamp int64 = 0 + if i > 0 { + prevEventTimestamp = g.Recording.KeyEvents[i-1].Timestamp + } + timeToWait := (event.Timestamp - prevEventTimestamp) / int64(g.RecordingConfig.Speed) + if i == 0 { + timeToWait += int64(g.RecordingConfig.Leeway) + } + var timeWaited int64 = 0 + middle: + for { + select { + case <-ticker.C: + timeWaited += 1 + if timeWaited >= timeToWait { + g.ReplayedEvents.keys <- event + break middle + } + case <-g.stop: + return } - case <-g.stop: - return } } - } + + waitGroup.Done() + }() + + go func() { + ticker := time.NewTicker(time.Millisecond) + defer ticker.Stop() + + // duplicating until Go gets generics + for i, event := range g.Recording.ResizeEvents { + var prevEventTimestamp int64 = 0 + if i > 0 { + prevEventTimestamp = g.Recording.ResizeEvents[i-1].Timestamp + } + timeToWait := (event.Timestamp - prevEventTimestamp) / int64(g.RecordingConfig.Speed) + if i == 0 { + timeToWait += int64(g.RecordingConfig.Leeway) + } + var timeWaited int64 = 0 + middle2: + for { + select { + case <-ticker.C: + timeWaited += 1 + if timeWaited >= timeToWait { + g.ReplayedEvents.resizes <- event + break middle2 + } + case <-g.stop: + return + } + } + } + + waitGroup.Done() + }() + + waitGroup.Wait() // leaving some time for any handlers to execute before quitting time.Sleep(time.Second * 1) diff --git a/vendor/github.com/jesseduffield/gocui/tcell_driver.go b/vendor/github.com/jesseduffield/gocui/tcell_driver.go index 12f269f04..e0378ac13 100644 --- a/vendor/github.com/jesseduffield/gocui/tcell_driver.go +++ b/vendor/github.com/jesseduffield/gocui/tcell_driver.go @@ -38,6 +38,17 @@ func tcellInit() error { } } +// tcellInitSimulation initializes tcell screen for use. +func tcellInitSimulation() error { + s := tcell.NewSimulationScreen("") + if e := s.Init(); e != nil { + return e + } else { + Screen = s + return nil + } +} + // tcellSetCell sets the character cell at a given location to the given // content (rune) and attributes using provided OutputMode func tcellSetCell(x, y int, ch rune, fg, bg Attribute, outputMode OutputMode) { @@ -166,6 +177,26 @@ func (wrapper TcellKeyEventWrapper) toTcellEvent() tcell.Event { return tcell.NewEventKey(wrapper.Key, wrapper.Ch, wrapper.Mod) } +type TcellResizeEventWrapper struct { + Timestamp int64 + Width int + Height int +} + +func NewTcellResizeEventWrapper(event *tcell.EventResize, timestamp int64) *TcellResizeEventWrapper { + w, h := event.Size() + + return &TcellResizeEventWrapper{ + Timestamp: timestamp, + Width: w, + Height: h, + } +} + +func (wrapper TcellResizeEventWrapper) toTcellEvent() tcell.Event { + return tcell.NewEventResize(wrapper.Width, wrapper.Height) +} + func (g *Gui) timeSinceStart() int64 { return time.Since(g.StartTime).Nanoseconds() / 1e6 } @@ -177,6 +208,8 @@ func (g *Gui) pollEvent() GocuiEvent { select { case ev := <-g.ReplayedEvents.keys: tev = (ev).toTcellEvent() + case ev := <-g.ReplayedEvents.resizes: + tev = (ev).toTcellEvent() } } else { tev = Screen.PollEvent() @@ -186,6 +219,12 @@ func (g *Gui) pollEvent() GocuiEvent { case *tcell.EventInterrupt: return GocuiEvent{Type: eventInterrupt} case *tcell.EventResize: + if g.PlayMode == RECORDING { + g.Recording.ResizeEvents = append( + g.Recording.ResizeEvents, NewTcellResizeEventWrapper(tev, g.timeSinceStart()), + ) + } + w, h := tev.Size() return GocuiEvent{Type: eventResize, Width: w, Height: h} case *tcell.EventKey: |