diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index b14738e38c0..f070e485627 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -1,7 +1,6 @@ package oscommands import ( - "fmt" "io" "os" "os/exec" @@ -329,15 +328,3 @@ func GetLazygitPath() string { } return `"` + filepath.ToSlash(ex) + `"` } - -func (c *OSCommand) UpdateWindowTitle() error { - if c.Platform.OS != "windows" { - return nil - } - path, getWdErr := os.Getwd() - if getWdErr != nil { - return getWdErr - } - argString := fmt.Sprint("title ", filepath.Base(path), " - Lazygit") - return c.Cmd.NewShell(argString, c.UserConfig().OS.ShellFunctionsFile).Run() -} diff --git a/pkg/commands/oscommands/os_default_platform.go b/pkg/commands/oscommands/os_default_platform.go index 11e1dc9aac4..3d7eae48177 100644 --- a/pkg/commands/oscommands/os_default_platform.go +++ b/pkg/commands/oscommands/os_default_platform.go @@ -5,8 +5,10 @@ package oscommands import ( "os" + "os/exec" "runtime" "strings" + "syscall" ) func GetPlatform() *Platform { @@ -34,3 +36,15 @@ func getUserShell() string { return "bash" } + +func (c *OSCommand) UpdateWindowTitle() error { + return nil +} + +func TerminateProcessGracefully(cmd *exec.Cmd) error { + if cmd.Process == nil { + return nil + } + + return cmd.Process.Signal(syscall.SIGTERM) +} diff --git a/pkg/commands/oscommands/os_windows.go b/pkg/commands/oscommands/os_windows.go index 783f50518a1..605ed768275 100644 --- a/pkg/commands/oscommands/os_windows.go +++ b/pkg/commands/oscommands/os_windows.go @@ -1,5 +1,12 @@ package oscommands +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + func GetPlatform() *Platform { return &Platform{ OS: "windows", @@ -7,3 +14,17 @@ func GetPlatform() *Platform { ShellArg: "/c", } } + +func (c *OSCommand) UpdateWindowTitle() error { + path, getWdErr := os.Getwd() + if getWdErr != nil { + return getWdErr + } + argString := fmt.Sprint("title ", filepath.Base(path), " - Lazygit") + return c.Cmd.NewShell(argString, c.UserConfig().OS.ShellFunctionsFile).Run() +} + +func TerminateProcessGracefully(cmd *exec.Cmd) error { + // Signals other than SIGKILL are not supported on Windows + return nil +} diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 5401b171430..5c5875fa879 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -9,6 +9,7 @@ import ( "time" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sasha-s/go-deadlock" "github.com/sirupsen/logrus" @@ -165,6 +166,17 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p // and the user is flicking through a bunch of items. self.throttle = time.Since(startTime) < THROTTLE_TIME && timeToStart > COMMAND_START_THRESHOLD + // Kill the still-running command. The only reason to do this is to save CPU usage + // when flicking through several very long diffs when diff.algorithm = histogram is + // being used, in which case multiple git processes continue to calculate expensive + // diffs in the background even though they have been stopped already. + // + // Unfortunately this will do nothing on Windows, so Windows users will have to live + // with the higher CPU usage. + if err := oscommands.TerminateProcessGracefully(cmd); err != nil { + self.Log.Errorf("error when trying to terminate cmd task: %v; Command: %v %v", err, cmd.Path, cmd.Args) + } + // close the task's stdout pipe (or the pty if we're using one) to make the command terminate onDone() } @@ -291,11 +303,15 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p refreshViewIfStale() - if err := cmd.Wait(); err != nil { - select { - case <-opts.Stop: - // it's fine if we've killed this program ourselves - default: + select { + case <-opts.Stop: + // If we stopped the task, don't block waiting for it; this could cause a delay if + // the process takes a while until it actually terminates. We still want to call + // Wait to reclaim any resources, but do it on a background goroutine, and ignore + // any errors. + go func() { _ = cmd.Wait() }() + default: + if err := cmd.Wait(); err != nil { self.Log.Errorf("Unexpected error when running cmd task: %v; Failed command: %v %v", err, cmd.Path, cmd.Args) } }