mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-22 07:11:01 +00:00
use context instead of struct channel
This commit is contained in:
parent
7f38cf2ab2
commit
b0241c79db
9 changed files with 48 additions and 68 deletions
|
|
@ -18,25 +18,23 @@ import (
|
|||
|
||||
func (gui *Gui) renderContainerLogsToMain(container *commands.Container) tasks.TaskFunc {
|
||||
return gui.NewTickerTask(TickerTaskOpts{
|
||||
Func: func(stop, notifyStopped chan struct{}) {
|
||||
gui.renderContainerLogsToMainAux(container, stop, notifyStopped)
|
||||
Func: func(ctx context.Context, notifyStopped chan struct{}) {
|
||||
gui.renderContainerLogsToMainAux(container, ctx, notifyStopped)
|
||||
},
|
||||
Duration: time.Millisecond * 200,
|
||||
// TODO: see why this isn't working (when switching from Top tab to Logs tab in the services panel, the tops tab's content isn't removed)
|
||||
Before: func(stop chan struct{}) { gui.clearMainView() },
|
||||
Before: func(ctx context.Context) { gui.clearMainView() },
|
||||
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
|
||||
Autoscroll: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, stop, notifyStopped chan struct{}) {
|
||||
func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, ctx context.Context, notifyStopped chan struct{}) {
|
||||
gui.clearMainView()
|
||||
defer func() {
|
||||
notifyStopped <- struct{}{}
|
||||
}()
|
||||
|
||||
ctx := stopIntoCtx(stop)
|
||||
|
||||
mainView := gui.Views.Main
|
||||
|
||||
if err := gui.writeContainerLogs(container, ctx, mainView); err != nil {
|
||||
|
|
@ -49,7 +47,7 @@ func (gui *Gui) renderContainerLogsToMainAux(container *commands.Container, stop
|
|||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
result, err := container.Inspect()
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func (gui *Gui) containerConfigStr(container *commands.Container) string {
|
|||
|
||||
func (gui *Gui) renderContainerStats(container *commands.Container) tasks.TaskFunc {
|
||||
return gui.NewTickerTask(TickerTaskOpts{
|
||||
Func: func(stop, notifyStopped chan struct{}) {
|
||||
Func: func(ctx context.Context, notifyStopped chan struct{}) {
|
||||
contents, err := presentation.RenderStats(gui.Config.UserConfig, container, gui.Views.Main.Width())
|
||||
if err != nil {
|
||||
_ = gui.createErrorPanel(err.Error())
|
||||
|
|
@ -221,26 +221,15 @@ func (gui *Gui) renderContainerStats(container *commands.Container) tasks.TaskFu
|
|||
gui.reRenderStringMain(contents)
|
||||
},
|
||||
Duration: time.Second,
|
||||
Before: func(stop chan struct{}) { gui.clearMainView() },
|
||||
Before: func(ctx context.Context) { gui.clearMainView() },
|
||||
Wrap: false, // wrapping looks bad here so we're overriding the config value
|
||||
Autoscroll: false,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: remove this and just use a context
|
||||
func stopIntoCtx(stop chan struct{}) context.Context {
|
||||
ctx, ctxCancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
<-stop
|
||||
ctxCancel()
|
||||
}()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (gui *Gui) renderContainerTop(container *commands.Container) tasks.TaskFunc {
|
||||
return gui.NewTickerTask(TickerTaskOpts{
|
||||
Func: func(stop, notifyStopped chan struct{}) {
|
||||
ctx := stopIntoCtx(stop)
|
||||
Func: func(ctx context.Context, notifyStopped chan struct{}) {
|
||||
contents, err := container.RenderTop(ctx)
|
||||
if err != nil {
|
||||
gui.RenderStringMain(err.Error())
|
||||
|
|
@ -249,7 +238,7 @@ func (gui *Gui) renderContainerTop(container *commands.Container) tasks.TaskFunc
|
|||
gui.reRenderStringMain(contents)
|
||||
},
|
||||
Duration: time.Second,
|
||||
Before: func(stop chan struct{}) { gui.clearMainView() },
|
||||
Before: func(ctx context.Context) { gui.clearMainView() },
|
||||
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
|
||||
Autoscroll: false,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -76,13 +76,6 @@ func (gui *Gui) jumpToTopMain(g *gocui.Gui, v *gocui.View) error {
|
|||
func (gui *Gui) onMainTabClick(tabIndex int) error {
|
||||
gui.Log.Warn(tabIndex)
|
||||
|
||||
viewName := gui.currentViewName()
|
||||
|
||||
mainView := gui.Views.Main
|
||||
if viewName == "main" && mainView.ParentView != nil {
|
||||
viewName = mainView.ParentView.Name()
|
||||
}
|
||||
|
||||
currentSidePanel, ok := gui.currentSidePanel()
|
||||
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -41,10 +41,6 @@ func (gui *Gui) getBindings(v *gocui.View) []*Binding {
|
|||
}
|
||||
}
|
||||
|
||||
// } else if v.ParentView != nil && binding.ViewName == v.ParentView.Name() {
|
||||
// // only add this if we don't have our own matching binding
|
||||
// bindingsPanel = append(bindingsPanel, binding)
|
||||
|
||||
// append dummy element to have a separator between
|
||||
// panel and global keybindings
|
||||
bindingsPanel = append(bindingsPanel, &Binding{})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package panels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
|
@ -74,7 +75,7 @@ type IGui interface {
|
|||
IgnoreStrings() []string
|
||||
Update(func() error)
|
||||
|
||||
QueueTask(f func(stop chan struct{})) error
|
||||
QueueTask(f func(ctx context.Context)) error
|
||||
}
|
||||
|
||||
func (self *SideListPanel[T]) HandleClick() error {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package gui
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
|
|
@ -115,7 +116,7 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
return gui.NewTask(TaskOpts{
|
||||
Autoscroll: true,
|
||||
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
|
||||
Func: func(stop chan struct{}) {
|
||||
Func: func(ctx context.Context) {
|
||||
gui.clearMainView()
|
||||
|
||||
cmd := gui.OSCommand.RunCustomCommand(
|
||||
|
|
@ -132,7 +133,7 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
_ = cmd.Start()
|
||||
|
||||
go func() {
|
||||
<-stop
|
||||
<-ctx.Done()
|
||||
if err := gui.OSCommand.Kill(cmd); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
|
@ -106,8 +107,7 @@ func (gui *Gui) renderServiceStats(service *commands.Service) tasks.TaskFunc {
|
|||
|
||||
func (gui *Gui) renderServiceTop(service *commands.Service) tasks.TaskFunc {
|
||||
return gui.NewTickerTask(TickerTaskOpts{
|
||||
Func: func(stop, notifyStopped chan struct{}) {
|
||||
ctx := stopIntoCtx(stop)
|
||||
Func: func(ctx context.Context, notifyStopped chan struct{}) {
|
||||
contents, err := service.RenderTop(ctx)
|
||||
if err != nil {
|
||||
gui.RenderStringMain(err.Error())
|
||||
|
|
@ -116,7 +116,7 @@ func (gui *Gui) renderServiceTop(service *commands.Service) tasks.TaskFunc {
|
|||
gui.reRenderStringMain(contents)
|
||||
},
|
||||
Duration: time.Second,
|
||||
Before: func(stop chan struct{}) { gui.clearMainView() },
|
||||
Before: func(ctx context.Context) { gui.clearMainView() },
|
||||
Wrap: gui.Config.UserConfig.Gui.WrapMainPanel,
|
||||
Autoscroll: false,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazydocker/pkg/tasks"
|
||||
)
|
||||
|
||||
func (gui *Gui) QueueTask(f func(stop chan struct{})) error {
|
||||
func (gui *Gui) QueueTask(f func(ctx context.Context)) error {
|
||||
return gui.taskManager.NewTask(f)
|
||||
}
|
||||
|
||||
|
|
@ -19,13 +20,13 @@ type RenderStringTaskOpts struct {
|
|||
type TaskOpts struct {
|
||||
Autoscroll bool
|
||||
Wrap bool
|
||||
Func func(stop chan struct{})
|
||||
Func func(ctx context.Context)
|
||||
}
|
||||
|
||||
type TickerTaskOpts struct {
|
||||
Duration time.Duration
|
||||
Before func(stop chan struct{})
|
||||
Func func(stop, notifyStopped chan struct{})
|
||||
Before func(ctx context.Context)
|
||||
Func func(ctx context.Context, notifyStopped chan struct{})
|
||||
Autoscroll bool
|
||||
Wrap bool
|
||||
}
|
||||
|
|
@ -34,10 +35,7 @@ func (gui *Gui) NewRenderStringTask(opts RenderStringTaskOpts) tasks.TaskFunc {
|
|||
taskOpts := TaskOpts{
|
||||
Autoscroll: opts.Autoscroll,
|
||||
Wrap: opts.Wrap,
|
||||
Func: func(stop chan struct{}) {
|
||||
// GetStrContent may be a slow function, so we clear the main view first
|
||||
// so that we're not seeing the previous tab's content appear.
|
||||
gui.clearMainView()
|
||||
Func: func(ctx context.Context) {
|
||||
gui.RenderStringMain(opts.GetStrContent())
|
||||
},
|
||||
}
|
||||
|
|
@ -55,12 +53,12 @@ func (gui *Gui) NewSimpleRenderStringTask(getContent func() string) tasks.TaskFu
|
|||
}
|
||||
|
||||
func (gui *Gui) NewTask(opts TaskOpts) tasks.TaskFunc {
|
||||
return func(stop chan struct{}) {
|
||||
return func(ctx context.Context) {
|
||||
mainView := gui.Views.Main
|
||||
mainView.Autoscroll = opts.Autoscroll
|
||||
mainView.Wrap = opts.Wrap
|
||||
|
||||
opts.Func(stop)
|
||||
opts.Func(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,25 +68,25 @@ func (gui *Gui) NewTask(opts TaskOpts) tasks.TaskFunc {
|
|||
func (gui *Gui) NewTickerTask(opts TickerTaskOpts) tasks.TaskFunc {
|
||||
notifyStopped := make(chan struct{}, 10)
|
||||
|
||||
task := func(stop chan struct{}) {
|
||||
task := func(ctx context.Context) {
|
||||
if opts.Before != nil {
|
||||
opts.Before(stop)
|
||||
opts.Before(ctx)
|
||||
}
|
||||
tickChan := time.NewTicker(opts.Duration)
|
||||
defer tickChan.Stop()
|
||||
// calling f first so that we're not waiting for the first tick
|
||||
opts.Func(stop, notifyStopped)
|
||||
opts.Func(ctx, notifyStopped)
|
||||
for {
|
||||
select {
|
||||
case <-notifyStopped:
|
||||
gui.Log.Info("exiting ticker task due to notifyStopped channel")
|
||||
return
|
||||
case <-stop:
|
||||
case <-ctx.Done():
|
||||
gui.Log.Info("exiting ticker task due to stopped channel")
|
||||
return
|
||||
case <-tickChan.C:
|
||||
gui.Log.Info("running ticker task again")
|
||||
opts.Func(stop, notifyStopped)
|
||||
opts.Func(ctx, notifyStopped)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
|
@ -19,15 +20,16 @@ type TaskManager struct {
|
|||
}
|
||||
|
||||
type Task struct {
|
||||
stop chan struct{}
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
stopped bool
|
||||
stopMutex deadlock.Mutex
|
||||
notifyStopped chan struct{}
|
||||
Log *logrus.Entry
|
||||
f func(chan struct{})
|
||||
f func(ctx context.Context)
|
||||
}
|
||||
|
||||
type TaskFunc func(stop chan struct{})
|
||||
type TaskFunc func(ctx context.Context)
|
||||
|
||||
func NewTaskManager(log *logrus.Entry, translationSet *i18n.TranslationSet) *TaskManager {
|
||||
return &TaskManager{Log: log, Tr: translationSet}
|
||||
|
|
@ -54,7 +56,7 @@ func (t *TaskManager) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
||||
func (t *TaskManager) NewTask(f func(ctx context.Context)) error {
|
||||
go func() {
|
||||
t.taskIDMutex.Lock()
|
||||
t.newTaskId++
|
||||
|
|
@ -67,7 +69,7 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
|||
return
|
||||
}
|
||||
|
||||
stop := make(chan struct{}, 1) // we don't want to block on this in case the task already returned
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
notifyStopped := make(chan struct{})
|
||||
|
||||
if t.currentTask != nil {
|
||||
|
|
@ -77,14 +79,15 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
|||
}
|
||||
|
||||
t.currentTask = &Task{
|
||||
stop: stop,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
notifyStopped: notifyStopped,
|
||||
Log: t.Log,
|
||||
f: f,
|
||||
}
|
||||
|
||||
go func() {
|
||||
f(stop)
|
||||
f(ctx)
|
||||
t.Log.Info("returned from function, closing notifyStopped")
|
||||
close(notifyStopped)
|
||||
}()
|
||||
|
|
@ -99,7 +102,8 @@ func (t *Task) Stop() {
|
|||
if t.stopped {
|
||||
return
|
||||
}
|
||||
close(t.stop)
|
||||
|
||||
t.cancel()
|
||||
t.Log.Info("closed stop channel, waiting for notifyStopped message")
|
||||
<-t.notifyStopped
|
||||
t.Log.Info("received notifystopped message")
|
||||
|
|
@ -109,28 +113,28 @@ func (t *Task) Stop() {
|
|||
// NewTickerTask is a convenience function for making a new task that repeats some action once per e.g. second
|
||||
// the before function gets called after the lock is obtained, but before the ticker starts.
|
||||
// if you handle a message on the stop channel in f() you need to send a message on the notifyStopped channel because returning is not sufficient. Here, unlike in a regular task, simply returning means we're now going to wait till the next tick to run again.
|
||||
func (t *TaskManager) NewTickerTask(duration time.Duration, before func(stop chan struct{}), f func(stop, notifyStopped chan struct{})) error {
|
||||
func (t *TaskManager) NewTickerTask(duration time.Duration, before func(ctx context.Context), f func(ctx context.Context, notifyStopped chan struct{})) error {
|
||||
notifyStopped := make(chan struct{}, 10)
|
||||
|
||||
return t.NewTask(func(stop chan struct{}) {
|
||||
return t.NewTask(func(ctx context.Context) {
|
||||
if before != nil {
|
||||
before(stop)
|
||||
before(ctx)
|
||||
}
|
||||
tickChan := time.NewTicker(duration)
|
||||
defer tickChan.Stop()
|
||||
// calling f first so that we're not waiting for the first tick
|
||||
f(stop, notifyStopped)
|
||||
f(ctx, notifyStopped)
|
||||
for {
|
||||
select {
|
||||
case <-notifyStopped:
|
||||
t.Log.Info("exiting ticker task due to notifyStopped channel")
|
||||
return
|
||||
case <-stop:
|
||||
case <-ctx.Done():
|
||||
t.Log.Info("exiting ticker task due to stopped cahnnel")
|
||||
return
|
||||
case <-tickChan.C:
|
||||
t.Log.Info("running ticker task again")
|
||||
f(stop, notifyStopped)
|
||||
f(ctx, notifyStopped)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue