package main
import (
"bytes"
"fmt"
"strings"
"sync"
"time"
log "github.com/Sirupsen/logrus"
)
const (
cvLoadRefreshMs = 500
cvColumnNum = 4
cvDateFormat = "2006-01-02 15:04"
cvCommitGraphLoadRequestChannelSize = 10
cvCommitSelectedChannelSize = 100
cvCommitGraphCommitIndexOffset = uint(200)
)
type commitViewHandler func(*CommitView, Action) error
type loadingCommitsRefreshTask struct {
refreshRate time.Duration
ticker *time.Ticker
channels Channels
cancelCh chan<- bool
}
type referenceViewData struct {
viewPos ViewPos
tableFormatter *TableFormatter
commitGraph *CommitGraph
}
type commitGraphLoadRequest struct {
commitIndex uint
ref Ref
}
// CommitViewListener is notified when a commit is selected
type CommitViewListener interface {
OnCommitSelected(*Commit) error
}
// CommitView is the overall instance representing the commit view
type CommitView struct {
*AbstractWindowView
channels Channels
repoData RepoData
repoController RepoController
config Config
activeRef Ref
refViewData map[string]*referenceViewData
handlers map[ActionType]commitViewHandler
refreshTask *loadingCommitsRefreshTask
commitViewListeners []CommitViewListener
commitViewListenerLock sync.Mutex
lastViewDimension ViewDimension
loadingDotCount uint
lastDotRenderTime time.Time
commitGraphLoadCh chan commitGraphLoadRequest
commitSelectedCh chan *Commit
variables GRVVariableSetter
waitGroup sync.WaitGroup
lock sync.Mutex
}
// NewCommitView creates a new instance of the commit view
func NewCommitView(repoData RepoData, repoController RepoController, channels Channels, config Config, variables GRVVariableSetter) *CommitView {
commitView := &CommitView{
channels: channels,
repoData: repoData,
repoController: repoController,
config: config,
commitGraphLoadCh: make(chan commitGraphLoadRequest, cvCommitGraphLoadRequestChannelSize),
commitSelectedCh: make(chan *Commit, cvCommitSelectedChannelSize),
refViewData: make(map[string]*referenceViewData),
lastDotRenderTime: time.Now(),
variables: variables,
handlers: map[ActionType]commitViewHandler{
ActionAddFilter: addCommitFilter,
ActionRemoveFilter: removeCommitFilter,
ActionSelect: selectCommit,
ActionCheckoutCommit: checkoutCommit,
ActionCreateBranch: createBranchFromCommit,
ActionCreateBranchAndCheckout: createBranchFromCommitAndCheckout,
ActionCreateTag: createTagFromCommit,
ActionCreateAnnotatedTag: createAnnotatedTagFromCommit,
ActionShowAvailableActions: showActionsForCommit,
},
}
commitView.AbstractWindowView = NewAbstractWindowView(commitView, channels, config, variables, &commitView.lock, "commit")
return commitView
}
// Initialise currently does nothing
func (commitView *CommitView) Initialise() (err error) {
log.Info("Initialising CommitView")
commitView.lock.Lock()
defer commitView.lock.Unlock()
commitView.repoData.RegisterCommitSetListener(commitView)
commitView.waitGroup.Add(2)
go commitView.processCommitGraphLoadRequests()
go commitView.processSelectedCommits()
return
}
// Dispose of any resources held by the view
func (commitView *CommitView) Dispose() {
commitView.lock.Lock()
if commitView.refreshTask != nil {
commitView.refreshTask.stop()
}
close(commitView.commitGraphLoadCh)
close(commitView.commitSelectedCh)
commitView.commitGraphLoadCh = nil
commitView.commitSelectedCh = nil
commitView.lock.Unlock()
commitView.waitGroup.Wait()
}
// Render generates and draws the commit view to the provided window
func (commitView *CommitView) Render(win RenderWindow) (err error) {
commitView.lock.Lock()
defer commitView.lock.Unlock()
commitView.lastViewDimension = win.ViewDimensi