summaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2021-04-05 10:20:02 +1000
committerJesse Duffield <jessedduffield@gmail.com>2021-04-06 19:34:32 +1000
commit843b8ceab0fa3888357f0e86026bebb6f4f1c305 (patch)
tree6c8b3b5be5948c62be6c3ee8144ac7c92e85cde1 /vendor
parent011451464fea4992b2dd8a09008b3e0ce45ba775 (diff)
support tcell simulation screen
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/jesseduffield/gocui/gui.go129
-rw-r--r--vendor/github.com/jesseduffield/gocui/tcell_driver.go39
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: