mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-21 21:47:32 +02:00
Add WithInlineStatus helper function
Very similar to WithWaitingStatus, except that the status is shown in a view next to the affected item, rather than in the status bar. Not used by anything yet; again, committing separately to get smaller commits.
This commit is contained in:
parent
9d55d71fdd
commit
7075b66bc6
@ -112,6 +112,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
Confirmation: helpers.NewConfirmationHelper(helperCommon),
|
||||
Mode: modeHelper,
|
||||
AppStatus: appStatusHelper,
|
||||
InlineStatus: helpers.NewInlineStatusHelper(helperCommon),
|
||||
WindowArrangement: helpers.NewWindowArrangementHelper(
|
||||
gui.c,
|
||||
windowHelper,
|
||||
|
@ -46,6 +46,7 @@ type Helpers struct {
|
||||
Confirmation *ConfirmationHelper
|
||||
Mode *ModeHelper
|
||||
AppStatus *AppStatusHelper
|
||||
InlineStatus *InlineStatusHelper
|
||||
WindowArrangement *WindowArrangementHelper
|
||||
Search *SearchHelper
|
||||
Worktree *WorktreeHelper
|
||||
@ -81,6 +82,7 @@ func NewStubHelpers() *Helpers {
|
||||
Confirmation: &ConfirmationHelper{},
|
||||
Mode: &ModeHelper{},
|
||||
AppStatus: &AppStatusHelper{},
|
||||
InlineStatus: &InlineStatusHelper{},
|
||||
WindowArrangement: &WindowArrangementHelper{},
|
||||
Search: &SearchHelper{},
|
||||
Worktree: &WorktreeHelper{},
|
||||
|
129
pkg/gui/controllers/helpers/inline_status_helper.go
Normal file
129
pkg/gui/controllers/helpers/inline_status_helper.go
Normal file
@ -0,0 +1,129 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/sasha-s/go-deadlock"
|
||||
)
|
||||
|
||||
type InlineStatusHelper struct {
|
||||
c *HelperCommon
|
||||
|
||||
contextsWithInlineStatus map[types.ContextKey]*inlineStatusInfo
|
||||
mutex *deadlock.Mutex
|
||||
}
|
||||
|
||||
func NewInlineStatusHelper(c *HelperCommon) *InlineStatusHelper {
|
||||
return &InlineStatusHelper{
|
||||
c: c,
|
||||
contextsWithInlineStatus: make(map[types.ContextKey]*inlineStatusInfo),
|
||||
mutex: &deadlock.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
type InlineStatusOpts struct {
|
||||
Item types.HasUrn
|
||||
Operation types.ItemOperation
|
||||
ContextKey types.ContextKey
|
||||
}
|
||||
|
||||
type inlineStatusInfo struct {
|
||||
refCount int
|
||||
stop chan struct{}
|
||||
}
|
||||
|
||||
// A custom task for WithInlineStatus calls; it wraps the original one and
|
||||
// hides the status whenever the task is paused, and shows it again when
|
||||
// continued.
|
||||
type inlineStatusHelperTask struct {
|
||||
gocui.Task
|
||||
|
||||
inlineStatusHelper *InlineStatusHelper
|
||||
opts InlineStatusOpts
|
||||
}
|
||||
|
||||
// poor man's version of explicitly saying that struct X implements interface Y
|
||||
var _ gocui.Task = inlineStatusHelperTask{}
|
||||
|
||||
func (self inlineStatusHelperTask) Pause() {
|
||||
self.inlineStatusHelper.stop(self.opts)
|
||||
self.Task.Pause()
|
||||
|
||||
self.inlineStatusHelper.renderContext(self.opts.ContextKey)
|
||||
}
|
||||
|
||||
func (self inlineStatusHelperTask) Continue() {
|
||||
self.Task.Continue()
|
||||
self.inlineStatusHelper.start(self.opts)
|
||||
}
|
||||
|
||||
func (self *InlineStatusHelper) WithInlineStatus(opts InlineStatusOpts, f func(gocui.Task) error) {
|
||||
self.c.OnWorker(func(task gocui.Task) {
|
||||
self.start(opts)
|
||||
|
||||
err := f(inlineStatusHelperTask{task, self, opts})
|
||||
if err != nil {
|
||||
self.c.OnUIThread(func() error {
|
||||
return self.c.Error(err)
|
||||
})
|
||||
}
|
||||
|
||||
self.stop(opts)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *InlineStatusHelper) start(opts InlineStatusOpts) {
|
||||
self.c.State().SetItemOperation(opts.Item, opts.Operation)
|
||||
|
||||
self.mutex.Lock()
|
||||
defer self.mutex.Unlock()
|
||||
|
||||
info := self.contextsWithInlineStatus[opts.ContextKey]
|
||||
if info == nil {
|
||||
info = &inlineStatusInfo{refCount: 0, stop: make(chan struct{})}
|
||||
self.contextsWithInlineStatus[opts.ContextKey] = info
|
||||
|
||||
go utils.Safe(func() {
|
||||
ticker := time.NewTicker(time.Millisecond * utils.LoaderAnimationInterval)
|
||||
defer ticker.Stop()
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
self.renderContext(opts.ContextKey)
|
||||
case <-info.stop:
|
||||
break outer
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
info.refCount++
|
||||
}
|
||||
|
||||
func (self *InlineStatusHelper) stop(opts InlineStatusOpts) {
|
||||
self.mutex.Lock()
|
||||
|
||||
if info := self.contextsWithInlineStatus[opts.ContextKey]; info != nil {
|
||||
info.refCount--
|
||||
if info.refCount <= 0 {
|
||||
info.stop <- struct{}{}
|
||||
delete(self.contextsWithInlineStatus, opts.ContextKey)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
self.mutex.Unlock()
|
||||
|
||||
self.c.State().ClearItemOperation(opts.Item)
|
||||
}
|
||||
|
||||
func (self *InlineStatusHelper) renderContext(contextKey types.ContextKey) {
|
||||
self.c.OnUIThread(func() error {
|
||||
_ = self.c.ContextForKey(contextKey).HandleRender()
|
||||
return nil
|
||||
})
|
||||
}
|
@ -5,6 +5,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
@ -199,3 +200,8 @@ func (self *guiCommon) RunningIntegrationTest() bool {
|
||||
func (self *guiCommon) InDemo() bool {
|
||||
return self.gui.integrationTest != nil && self.gui.integrationTest.IsDemo()
|
||||
}
|
||||
|
||||
func (self *guiCommon) WithInlineStatus(item types.HasUrn, operation types.ItemOperation, contextKey types.ContextKey, f func(gocui.Task) error) error {
|
||||
self.gui.helpers.InlineStatus.WithInlineStatus(helpers.InlineStatusOpts{Item: item, Operation: operation, ContextKey: contextKey}, f)
|
||||
return nil
|
||||
}
|
||||
|
@ -87,6 +87,12 @@ type IGuiCommon interface {
|
||||
// resized, if in accordion mode.
|
||||
AfterLayout(f func() error)
|
||||
|
||||
// Wraps a function, attaching the given operation to the given item while
|
||||
// the function is executing, and also causes the given context to be
|
||||
// redrawn periodically. This allows the operation to be visualized with a
|
||||
// spinning loader animation (e.g. when a branch is being pushed).
|
||||
WithInlineStatus(item HasUrn, operation ItemOperation, contextKey ContextKey, f func(gocui.Task) error) error
|
||||
|
||||
// returns the gocui Gui struct. There is a good chance you don't actually want to use
|
||||
// this struct and instead want to use another method above
|
||||
GocuiGui() *gocui.Gui
|
||||
|
Loading…
x
Reference in New Issue
Block a user