diff --git a/go.mod b/go.mod index 46ad9d742..c710eee99 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/integrii/flaggy v1.4.0 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d - github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5 + github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index 96b177507..194b5f494 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= -github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5 h1:8k7VTfj/RSKwYQ7Cn+iy876CjixBrTyyn+npxT/Wn/Q= -github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= +github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa h1:E9G1mj94rMal1YLaABwdxLUUgKq+xGbElFjHRNaDJUg= +github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 3dcf146dc..a88134639 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -3,7 +3,6 @@ package gui import ( "fmt" "io" - "log" "os" "strings" "sync" @@ -436,17 +435,9 @@ var RuneReplacements = map[rune]string{ } func (gui *Gui) initGocui(headless bool, test integrationTypes.IntegrationTest) (*gocui.Gui, error) { - recordEvents := RecordingEvents() - playMode := gocui.NORMAL - if recordEvents { - playMode = gocui.RECORDING - } else if Replaying() { - playMode = gocui.REPLAYING - } else if test != nil && os.Getenv(components.SANDBOX_ENV_VAR) != "true" { - playMode = gocui.REPLAYING_NEW - } + playRecording := test != nil && os.Getenv(components.SANDBOX_ENV_VAR) != "true" - g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode, headless, RuneReplacements) + g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playRecording, headless, RuneReplacements) if err != nil { return nil, err } @@ -577,10 +568,6 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error { } } - if err := SaveRecording(gui.g.Recording); err != nil { - return err - } - return nil default: @@ -611,14 +598,6 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool, gui.Mutexes.SubprocessMutex.Lock() defer gui.Mutexes.SubprocessMutex.Unlock() - if Replaying() { - // we do not yet support running subprocesses within integration tests. So if - // we're replaying an integration test and we're inside this method, something - // has gone wrong, so we should fail - - log.Fatal("opening subprocesses not yet supported in integration tests. Chances are that this test is running too fast and a subprocess is accidentally opened") - } - if err := gui.g.Suspend(); err != nil { return false, gui.c.Error(err) } diff --git a/pkg/gui/test_mode.go b/pkg/gui/test_mode.go index 9c6b5f30d..be46041db 100644 --- a/pkg/gui/test_mode.go +++ b/pkg/gui/test_mode.go @@ -1,10 +1,8 @@ package gui import ( - "encoding/json" "log" "os" - "strconv" "time" "github.com/jesseduffield/gocui" @@ -42,87 +40,8 @@ func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) { log.Fatal("40 seconds is up, lazygit recording took too long to complete") }) } - - if Replaying() { - gui.g.RecordingConfig = gocui.RecordingConfig{ - Speed: GetRecordingSpeed(), - Leeway: 1000, - } - - var err error - gui.g.Recording, err = LoadRecording() - if err != nil { - panic(err) - } - - go utils.Safe(func() { - time.Sleep(time.Second * 40) - log.Fatal("40 seconds is up, lazygit recording took too long to complete") - }) - } } func Headless() bool { return os.Getenv("HEADLESS") != "" } - -// OLD integration test format stuff - -func Replaying() bool { - return os.Getenv("REPLAY_EVENTS_FROM") != "" -} - -func RecordingEvents() bool { - return recordEventsTo() != "" -} - -func recordEventsTo() string { - return os.Getenv("RECORD_EVENTS_TO") -} - -func GetRecordingSpeed() float64 { - // humans are slow so this speeds things up. - speed := 1.0 - envReplaySpeed := os.Getenv("SPEED") - if envReplaySpeed != "" { - var err error - speed, err = strconv.ParseFloat(envReplaySpeed, 64) - if err != nil { - log.Fatal(err) - } - } - return speed -} - -func LoadRecording() (*gocui.Recording, error) { - path := os.Getenv("REPLAY_EVENTS_FROM") - - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - recording := &gocui.Recording{} - - err = json.Unmarshal(data, &recording) - if err != nil { - return nil, err - } - - return recording, nil -} - -func SaveRecording(recording *gocui.Recording) error { - if !RecordingEvents() { - return nil - } - - jsonEvents, err := json.Marshal(recording) - if err != nil { - return err - } - - path := recordEventsTo() - - return os.WriteFile(path, jsonEvents, 0o600) -} diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index 6778bc012..b931e8954 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -28,7 +28,7 @@ func RunTUI() { app := newApp(testDir) app.loadTests() - g, err := gocui.NewGui(gocui.OutputTrue, false, gocui.NORMAL, false, gui.RuneReplacements) + g, err := gocui.NewGui(gocui.OutputTrue, false, false, false, gui.RuneReplacements) if err != nil { log.Panicln(err) } diff --git a/scripts/bump_gocui.sh b/scripts/bump_gocui.sh index 3e0adebae..13a1f575a 100755 --- a/scripts/bump_gocui.sh +++ b/scripts/bump_gocui.sh @@ -1,5 +1,7 @@ +#!/bin/sh + # Go's proxy servers are not very up-to-date so that's why we use `GOPROXY=direct` -# We specify the `awesome` branch to avoid the default behaviour of looking for a semver tag. -GOPROXY=direct go get -u github.com/jesseduffield/gocui@awesome && go mod vendor && go mod tidy +# We specify the `master` branch to avoid the default behaviour of looking for a semver tag. +GOPROXY=direct go get -u github.com/jesseduffield/gocui@master && go mod vendor && go mod tidy # Note to self if you ever want to fork a repo be sure to use this same approach: it's important to use the branch name (e.g. master) diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index a33399c67..84ec8d234 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -7,7 +7,6 @@ package gocui import ( "context" standardErrors "errors" - "log" "runtime" "strings" "sync" @@ -103,21 +102,6 @@ type GuiMutexes struct { ViewsMutex sync.Mutex } -type PlayMode int - -const ( - NORMAL PlayMode = iota - RECORDING - REPLAYING - // for the new form of integration tests - REPLAYING_NEW -) - -type Recording struct { - KeyEvents []*TcellKeyEventWrapper - ResizeEvents []*TcellResizeEventWrapper -} - type replayedEvents struct { Keys chan *TcellKeyEventWrapper Resizes chan *TcellResizeEventWrapper @@ -132,11 +116,9 @@ type RecordingConfig struct { // and keybindings. type Gui struct { RecordingConfig - Recording *Recording // ReplayedEvents is for passing pre-recorded input events, for the purposes of testing ReplayedEvents replayedEvents - PlayMode PlayMode - StartTime time.Time + playRecording bool tabClickBindings []*tabClickBinding viewMouseBindings []*ViewMouseBinding @@ -194,7 +176,7 @@ type Gui struct { } // NewGui returns a new Gui object with a given output mode. -func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless bool, runeReplacements map[rune]string) (*Gui, error) { +func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless bool, runeReplacements map[rune]string) (*Gui, error) { g := &Gui{} var err error @@ -224,12 +206,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless b g.gEvents = make(chan GocuiEvent, 20) g.userEvents = make(chan userEvent, 20) - if playMode == RECORDING { - g.Recording = &Recording{ - KeyEvents: []*TcellKeyEventWrapper{}, - ResizeEvents: []*TcellResizeEventWrapper{}, - } - } else if playMode == REPLAYING || playMode == REPLAYING_NEW { + if playRecording { g.ReplayedEvents = replayedEvents{ Keys: make(chan *TcellKeyEventWrapper), Resizes: make(chan *TcellResizeEventWrapper), @@ -248,7 +225,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless b g.NextSearchMatchKey = 'n' g.PrevSearchMatchKey = 'N' - g.PlayMode = playMode + g.playRecording = playRecording return g, nil } @@ -673,11 +650,6 @@ 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 { - go g.replayRecording() - } - go func() { for { select { @@ -1417,97 +1389,6 @@ func IsQuit(err error) bool { return err != nil && err.Error() == ErrQuit.Error() } -func (g *Gui) replayRecording() { - waitGroup := sync.WaitGroup{} - - waitGroup.Add(2) - - // lots of duplication here due to lack of generics. Also we don't support mouse - // events because it would be awkward to replicate but it would be trivial to add - // support - 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 := float64(event.Timestamp-prevEventTimestamp) / g.RecordingConfig.Speed - if i == 0 { - timeToWait += float64(g.RecordingConfig.Leeway) - } - var timeWaited float64 = 0 - middle: - for { - select { - case <-ticker.C: - timeWaited += 1 - if timeWaited >= timeToWait { - g.ReplayedEvents.Keys <- event - break middle - } - 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 := float64(event.Timestamp-prevEventTimestamp) / g.RecordingConfig.Speed - if i == 0 { - timeToWait += float64(g.RecordingConfig.Leeway) - } - var timeWaited float64 = 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) - - g.Update(func(*Gui) error { - return ErrQuit - }) - - time.Sleep(time.Second * 1) - - log.Fatal("gocui should have already exited") -} - func (g *Gui) Suspend() error { g.suspendedMutex.Lock() defer g.suspendedMutex.Unlock() diff --git a/vendor/github.com/jesseduffield/gocui/tcell_driver.go b/vendor/github.com/jesseduffield/gocui/tcell_driver.go index f72cabefd..59238ed07 100644 --- a/vendor/github.com/jesseduffield/gocui/tcell_driver.go +++ b/vendor/github.com/jesseduffield/gocui/tcell_driver.go @@ -5,8 +5,6 @@ package gocui import ( - "time" - "github.com/gdamore/tcell/v2" "github.com/mattn/go-runewidth" ) @@ -236,14 +234,10 @@ 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 -} - // pollEvent get tcell.Event and transform it into gocuiEvent func (g *Gui) pollEvent() GocuiEvent { var tev tcell.Event - if g.PlayMode == REPLAYING || g.PlayMode == REPLAYING_NEW { + if g.playRecording { select { case ev := <-g.ReplayedEvents.Keys: tev = (ev).toTcellEvent() @@ -258,21 +252,9 @@ 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: - if g.PlayMode == RECORDING { - g.Recording.KeyEvents = append( - g.Recording.KeyEvents, NewTcellKeyEventWrapper(tev, g.timeSinceStart()), - ) - } - k := tev.Key() ch := rune(0) if k == tcell.KeyRune { diff --git a/vendor/modules.txt b/vendor/modules.txt index b62cafde7..788171757 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5 +# github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa ## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10