1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-01 13:17:53 +02:00

big refactor to give our enums actual types

This commit is contained in:
Jesse Duffield 2021-03-31 23:55:06 +11:00
parent 9e85d37fb9
commit 7d62f103e4
26 changed files with 185 additions and 134 deletions

View File

@ -10,8 +10,10 @@ import (
"github.com/sirupsen/logrus"
)
type PatchLineKind int
const (
PATCH_HEADER = iota
PATCH_HEADER PatchLineKind = iota
COMMIT_SHA
COMMIT_DESCRIPTION
HUNK_HEADER
@ -24,7 +26,7 @@ const (
// the job of this file is to parse a diff, find out where the hunks begin and end, which lines are stageable, and how to find the next hunk from the current position or the next stageable line from the current position.
type PatchLine struct {
Kind int
Kind PatchLineKind
Content string // something like '+ hello' (note the first character is not removed)
}
@ -144,7 +146,7 @@ func parsePatch(patch string) ([]int, []int, []*PatchLine, error) {
pastFirstHunkHeader := false
pastCommitDescription := true
patchLines := make([]*PatchLine, len(lines))
var lineKind int
var lineKind PatchLineKind
var firstChar string
for index, line := range lines {
firstChar = " "

View File

@ -9,8 +9,10 @@ type Dimensions struct {
Y1 int
}
type Direction int
const (
ROW = iota
ROW Direction = iota
COLUMN
)
@ -26,10 +28,10 @@ const (
type Box struct {
// Direction decides how the children boxes are laid out. ROW means the children will each form a row i.e. that they will be stacked on top of eachother.
Direction int // ROW or COLUMN
Direction Direction
// function which takes the width and height assigned to the box and decides which orientation it will have
ConditionalDirection func(width int, height int) int
ConditionalDirection func(width int, height int) Direction
Children []*Box
@ -120,7 +122,7 @@ func (b *Box) isStatic() bool {
return b.Size > 0
}
func (b *Box) getDirection(width int, height int) int {
func (b *Box) getDirection(width int, height int) Direction {
if b.ConditionalDirection != nil {
return b.ConditionalDirection(width, height)
}

View File

@ -87,7 +87,7 @@ func TestArrangeWindows(t *testing.T) {
},
{
"Box with COLUMN direction only on wide boxes with narrow box",
&Box{ConditionalDirection: func(width int, height int) int {
&Box{ConditionalDirection: func(width int, height int) Direction {
if width > 4 {
return COLUMN
} else {
@ -111,7 +111,7 @@ func TestArrangeWindows(t *testing.T) {
},
{
"Box with COLUMN direction only on wide boxes with wide box",
&Box{ConditionalDirection: func(width int, height int) int {
&Box{ConditionalDirection: func(width int, height int) Direction {
if width > 4 {
return COLUMN
} else {

View File

@ -293,7 +293,7 @@ func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) err
}
return gui.createErrorPanel(errMessage)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{BRANCHES}})
},
})
}
@ -408,7 +408,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
} else {
err := gui.GitCommand.FastForward(branch.Name, remoteName, remoteBranchName, gui.promptUserForCredential)
gui.handleCredentialsPopup(err)
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}})
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{BRANCHES}})
}
})
return nil

View File

@ -437,7 +437,7 @@ func (gui *Gui) handleCommitRevert(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
gui.State.Panels.Commits.SelectedLineIdx++
return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI, scope: []int{COMMITS, BRANCHES}})
return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI, scope: []RefreshableView{COMMITS, BRANCHES}})
}
func (gui *Gui) handleViewCommitFiles() error {
@ -527,7 +527,7 @@ func (gui *Gui) handleCreateLightweightTag(commitSha string) error {
if err := gui.GitCommand.CreateLightweightTag(response, commitSha); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}})
},
})
}
@ -560,7 +560,7 @@ func (gui *Gui) handleOpenSearchForCommitsPanel(g *gocui.Gui, v *gocui.View) err
// we usually lazyload these commits but now that we're searching we need to load them now
if gui.State.Panels.Commits.LimitCommits {
gui.State.Panels.Commits.LimitCommits = false
if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS}}); err != nil {
return err
}
}
@ -572,7 +572,7 @@ func (gui *Gui) handleGotoBottomForCommitsPanel(g *gocui.Gui, v *gocui.View) err
// we usually lazyload these commits but now that we're searching we need to load them now
if gui.State.Panels.Commits.LimitCommits {
gui.State.Panels.Commits.LimitCommits = false
if err := gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []int{COMMITS}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}}); err != nil {
return err
}
}

View File

@ -6,8 +6,10 @@ import (
"github.com/jesseduffield/gocui"
)
type ContextKind int
const (
SIDE_CONTEXT int = iota
SIDE_CONTEXT ContextKind = iota
MAIN_CONTEXT
TEMPORARY_POPUP
PERSISTENT_POPUP
@ -126,7 +128,7 @@ type Context interface {
HandleFocus() error
HandleFocusLost() error
HandleRender() error
GetKind() int
GetKind() ContextKind
GetViewName() string
GetWindowName() string
SetWindowName(string)
@ -143,7 +145,7 @@ type BasicContext struct {
OnFocusLost func() error
OnRender func() error
OnGetOptionsMap func() map[string]string
Kind int
Kind ContextKind
Key string
ViewName string
}
@ -194,7 +196,7 @@ func (c BasicContext) HandleFocusLost() error {
return nil
}
func (c BasicContext) GetKind() int {
func (c BasicContext) GetKind() ContextKind {
return c.Kind
}

View File

@ -15,7 +15,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
if err := gui.GitCommand.DiscardAllDirChanges(node); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
}
@ -28,7 +28,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
})
}
@ -55,7 +55,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
if err := gui.GitCommand.DiscardAllFileChanges(file); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
}
@ -68,7 +68,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
})
}

42
pkg/gui/errors.go Normal file
View File

@ -0,0 +1,42 @@
package gui
import "github.com/go-errors/errors"
// SentinelErrors are the errors that have special meaning and need to be checked
// by calling functions. The less of these, the better
type SentinelErrors struct {
ErrSubProcess error
ErrNoFiles error
ErrSwitchRepo error
ErrRestart error
}
const UNKNOWN_VIEW_ERROR_MSG = "unknown view"
// GenerateSentinelErrors makes the sentinel errors for the gui. We're defining it here
// because we can't do package-scoped errors with localization, and also because
// it seems like package-scoped variables are bad in general
// https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables
// In the future it would be good to implement some of the recommendations of
// that article. For now, if we don't need an error to be a sentinel, we will just
// define it inline. This has implications for error messages that pop up everywhere
// in that we'll be duplicating the default values. We may need to look at
// having a default localisation bundle defined, and just using keys-only when
// localising things in the code.
func (gui *Gui) GenerateSentinelErrors() {
gui.Errors = SentinelErrors{
ErrSubProcess: errors.New(gui.Tr.RunningSubprocess),
ErrNoFiles: errors.New(gui.Tr.NoChangedFiles),
ErrSwitchRepo: errors.New("switching repo"),
ErrRestart: errors.New("restarting"),
}
}
func (gui *Gui) sentinelErrorsArr() []error {
return []error{
gui.Errors.ErrSubProcess,
gui.Errors.ErrNoFiles,
gui.Errors.ErrSwitchRepo,
gui.Errors.ErrRestart,
}
}

View File

@ -117,7 +117,7 @@ func (gui *Gui) watchFilesForChanges() {
}
// only refresh if we're not already
if !gui.State.IsRefreshingFiles {
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
}
// watch for errors

View File

@ -256,7 +256,7 @@ func (gui *Gui) handleFilePress() error {
}
}
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
return err
}
@ -287,7 +287,7 @@ func (gui *Gui) handleStageAll(g *gocui.Gui, v *gocui.View) error {
_ = gui.surfaceError(err)
}
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
return err
}
@ -333,7 +333,7 @@ func (gui *Gui) handleIgnoreFile() error {
if err := gui.GitCommand.Ignore(node.GetPath()); err != nil {
return err
}
return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}})
},
})
}
@ -346,7 +346,7 @@ func (gui *Gui) handleIgnoreFile() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}})
}
func (gui *Gui) handleWIPCommitPress(g *gocui.Gui, filesView *gocui.View) error {
@ -522,7 +522,7 @@ func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error {
return gui.refreshSidePanels(refreshOptions{scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}})
}
func (gui *Gui) refreshStateFiles() error {

View File

@ -22,14 +22,40 @@ func (gui *Gui) rerenderViewsWithScreenModeDependentContent() error {
return nil
}
// TODO: GENERICS
func nextIntInCycle(sl []WindowMaximisation, current WindowMaximisation) WindowMaximisation {
for i, val := range sl {
if val == current {
if i == len(sl)-1 {
return sl[0]
}
return sl[i+1]
}
}
return sl[0]
}
// TODO: GENERICS
func prevIntInCycle(sl []WindowMaximisation, current WindowMaximisation) WindowMaximisation {
for i, val := range sl {
if val == current {
if i > 0 {
return sl[i-1]
}
return sl[len(sl)-1]
}
}
return sl[len(sl)-1]
}
func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error {
gui.State.ScreenMode = utils.NextIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
gui.State.ScreenMode = nextIntInCycle([]WindowMaximisation{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
return gui.rerenderViewsWithScreenModeDependentContent()
}
func (gui *Gui) prevScreenMode(g *gocui.Gui, v *gocui.View) error {
gui.State.ScreenMode = utils.PrevIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
gui.State.ScreenMode = prevIntInCycle([]WindowMaximisation{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
return gui.rerenderViewsWithScreenModeDependentContent()
}
@ -179,7 +205,7 @@ func (gui *Gui) fetch(canPromptForCredentials bool) (err error) {
_ = gui.createErrorPanel(gui.Tr.PassUnameWrong)
}
_ = gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC})
_ = gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC})
return err
}

View File

@ -11,8 +11,6 @@ import (
"strings"
"time"
"github.com/go-errors/errors"
"github.com/fatih/color"
"github.com/golang-collections/collections/stack"
"github.com/jesseduffield/gocui"
@ -33,8 +31,14 @@ import (
"github.com/sirupsen/logrus"
)
// screen sizing determines how much space your selected window takes up (window
// as in panel, not your terminal's window). Sometimes you want a bit more space
// to see the contents of a panel, and this keeps track of how much maximisation
// you've set
type WindowMaximisation int
const (
SCREEN_NORMAL int = iota
SCREEN_NORMAL WindowMaximisation = iota
SCREEN_HALF
SCREEN_FULL
)
@ -44,45 +48,6 @@ const StartupPopupVersion = 3
// OverlappingEdges determines if panel edges overlap
var OverlappingEdges = false
// SentinelErrors are the errors that have special meaning and need to be checked
// by calling functions. The less of these, the better
type SentinelErrors struct {
ErrSubProcess error
ErrNoFiles error
ErrSwitchRepo error
ErrRestart error
}
const UNKNOWN_VIEW_ERROR_MSG = "unknown view"
// GenerateSentinelErrors makes the sentinel errors for the gui. We're defining it here
// because we can't do package-scoped errors with localization, and also because
// it seems like package-scoped variables are bad in general
// https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables
// In the future it would be good to implement some of the recommendations of
// that article. For now, if we don't need an error to be a sentinel, we will just
// define it inline. This has implications for error messages that pop up everywhere
// in that we'll be duplicating the default values. We may need to look at
// having a default localisation bundle defined, and just using keys-only when
// localising things in the code.
func (gui *Gui) GenerateSentinelErrors() {
gui.Errors = SentinelErrors{
ErrSubProcess: errors.New(gui.Tr.RunningSubprocess),
ErrNoFiles: errors.New(gui.Tr.NoChangedFiles),
ErrSwitchRepo: errors.New("switching repo"),
ErrRestart: errors.New("restarting"),
}
}
func (gui *Gui) sentinelErrorsArr() []error {
return []error{
gui.Errors.ErrSubProcess,
gui.Errors.ErrNoFiles,
gui.Errors.ErrSwitchRepo,
gui.Errors.ErrRestart,
}
}
// Gui wraps the gocui Gui object which handles rendering and events
type Gui struct {
g *gocui.Gui
@ -151,7 +116,7 @@ type lBlPanelState struct {
LastLineIdx int
Diff string
PatchParser *patch.PatchParser
SelectMode int // one of LINE, HUNK, or RANGE
SelectMode SelectMode
SecondaryFocused bool // this is for if we show the left or right panel
}
@ -255,8 +220,10 @@ type searchingState struct {
}
// startup stages so we don't need to load everything at once
type StartupStage int
const (
INITIAL = iota
INITIAL StartupStage = iota
COMPLETE
)
@ -331,13 +298,13 @@ type guiState struct {
RetainOriginalDir bool
IsRefreshingFiles bool
Searching searchingState
ScreenMode int
ScreenMode WindowMaximisation
SideView *gocui.View
Ptmx *os.File
PrevMainWidth int
PrevMainHeight int
OldInformation string
StartupStage int // one of INITIAL and COMPLETE. Allows us to not load everything at once
StartupStage StartupStage // Allows us to not load everything at once
Modes Modes

View File

@ -16,8 +16,10 @@ import (
// use cases
// these represent what select mode we're in
type SelectMode int
const (
LINE = iota
LINE SelectMode = iota
RANGE
HUNK
)

View File

@ -23,7 +23,7 @@ type ListContext struct {
Gui *Gui
ResetMainViewOriginOnFocus bool
Kind int
Kind ContextKind
ParentContext Context
// we can't know on the calling end whether a Context is actually a nil value without reflection, so we're storing this flag here to tell us. There has got to be a better way around this.
hasParent bool
@ -102,7 +102,7 @@ func (lc *ListContext) GetKey() string {
return lc.ContextKey
}
func (lc *ListContext) GetKind() int {
func (lc *ListContext) GetKind() ContextKind {
return lc.Kind
}

View File

@ -20,8 +20,10 @@ type refreshMainOpts struct {
}
// constants for updateTask's kind field
type TaskKind int
const (
RENDER_STRING = iota
RENDER_STRING TaskKind = iota
RENDER_STRING_WITHOUT_SCROLL
RUN_FUNCTION
RUN_COMMAND
@ -29,14 +31,14 @@ const (
)
type updateTask interface {
GetKind() int
GetKind() TaskKind
}
type renderStringTask struct {
str string
}
func (t *renderStringTask) GetKind() int {
func (t *renderStringTask) GetKind() TaskKind {
return RENDER_STRING
}
@ -48,7 +50,7 @@ type renderStringWithoutScrollTask struct {
str string
}
func (t *renderStringWithoutScrollTask) GetKind() int {
func (t *renderStringWithoutScrollTask) GetKind() TaskKind {
return RENDER_STRING_WITHOUT_SCROLL
}
@ -61,7 +63,7 @@ type runCommandTask struct {
prefix string
}
func (t *runCommandTask) GetKind() int {
func (t *runCommandTask) GetKind() TaskKind {
return RUN_COMMAND
}
@ -78,7 +80,7 @@ type runPtyTask struct {
prefix string
}
func (t *runPtyTask) GetKind() int {
func (t *runPtyTask) GetKind() TaskKind {
return RUN_PTY
}
@ -95,7 +97,7 @@ type runFunctionTask struct {
f func(chan struct{}) error
}
func (t *runFunctionTask) GetKind() int {
func (t *runFunctionTask) GetKind() TaskKind {
return RUN_FUNCTION
}

View File

@ -303,7 +303,7 @@ func (gui *Gui) handleEscapeMerge() error {
gui.takeOverScrolling()
gui.State.Panels.Merging.EditHistory = stack.New()
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
return err
}
// it's possible this method won't be called from the merging view so we need to
@ -318,7 +318,7 @@ func (gui *Gui) handleCompleteMerge() error {
if err := gui.stageSelectedFile(); err != nil {
return err
}
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
return err
}
// if we got conflicts after unstashing, we don't want to call any git

View File

@ -63,7 +63,7 @@ func (gui *Gui) handleDeleteRemoteBranch(g *gocui.Gui, v *gocui.View) error {
err := gui.GitCommand.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name, gui.promptUserForCredential)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}})
})
},
})
@ -94,7 +94,7 @@ func (gui *Gui) handleSetBranchUpstream(g *gocui.Gui, v *gocui.View) error {
return err
}
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}})
},
})
}

View File

@ -94,7 +94,7 @@ func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil {
return err
}
return gui.refreshSidePanels(refreshOptions{scope: []int{REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{REMOTES}})
},
})
},
@ -116,7 +116,7 @@ func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}})
},
})
}
@ -164,7 +164,7 @@ func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}})
},
})
},
@ -184,6 +184,6 @@ func (gui *Gui) handleFetchRemote(g *gocui.Gui, v *gocui.View) error {
err := gui.GitCommand.FetchRemote(remote.Name, gui.promptUserForCredential)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}})
})
}

View File

@ -21,7 +21,7 @@ func (gui *Gui) resetToRef(ref string, strength string, options oscommands.RunCo
return err
}
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES, BRANCHES, REFLOG, COMMITS}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES, BRANCHES, REFLOG, COMMITS}}); err != nil {
return err
}

View File

@ -152,7 +152,7 @@ func (gui *Gui) applySelection(reverse bool, state *lBlPanelState) error {
state.SelectMode = LINE
}
if err := gui.refreshSidePanels(refreshOptions{scope: []int{FILES}}); err != nil {
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
return err
}
if err := gui.refreshStagingPanel(false, -1, state); err != nil {

View File

@ -110,7 +110,7 @@ func (gui *Gui) stashDo(method string) error {
if err := gui.GitCommand.StashDo(stashEntry.Index, method); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{STASH, FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH, FILES}})
}
func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
@ -124,7 +124,7 @@ func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
if err := stashFunc(stashComment); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{STASH, FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH, FILES}})
},
})
}

View File

@ -86,7 +86,7 @@ func (gui *Gui) removeSubmodule(submodule *models.SubmoduleConfig) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES, FILES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES, FILES}})
},
})
}
@ -122,7 +122,7 @@ func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES, SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES, SUBMODULES}})
}
func (gui *Gui) handleAddSubmodule() error {
@ -144,7 +144,7 @@ func (gui *Gui) handleAddSubmodule() error {
err := gui.GitCommand.SubmoduleAdd(submoduleName, submodulePath, submoduleUrl)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
})
@ -164,7 +164,7 @@ func (gui *Gui) handleEditSubmoduleUrl(submodule *models.SubmoduleConfig) error
err := gui.GitCommand.SubmoduleUpdateUrl(submodule.Name, submodule.Path, newUrl)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
})
@ -175,7 +175,7 @@ func (gui *Gui) handleSubmoduleInit(submodule *models.SubmoduleConfig) error {
err := gui.GitCommand.SubmoduleInit(submodule.Path)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
}
@ -221,7 +221,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
},
@ -233,7 +233,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
},
@ -245,7 +245,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
},
@ -257,7 +257,7 @@ func (gui *Gui) handleBulkSubmoduleActionsMenu() error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
},
},
@ -271,6 +271,6 @@ func (gui *Gui) handleUpdateSubmodule(submodule *models.SubmoduleConfig) error {
err := gui.GitCommand.SubmoduleUpdate(submodule.Path)
gui.handleCredentialsPopup(err)
return gui.refreshSidePanels(refreshOptions{scope: []int{SUBMODULES}})
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}})
})
}

View File

@ -79,7 +79,7 @@ func (gui *Gui) handleDeleteTag(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.DeleteTag(tag.Name); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{COMMITS, TAGS}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}})
},
})
}
@ -119,7 +119,7 @@ func (gui *Gui) handleCreateTag(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.CreateLightweightTag(tagName, ""); err != nil {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{scope: []int{COMMITS, TAGS}, then: func() {
return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{COMMITS, TAGS}, then: func() {
// find the index of the tag and set that as the currently selected line
for i, tag := range gui.State.Tags {
if tag.Name == tagName {

View File

@ -17,15 +17,17 @@ import (
// the reflog will read UUCBA, and when I read the first two undos, I know to skip the following
// two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way.
type ReflogActionKind int
const (
CHECKOUT = iota
CHECKOUT ReflogActionKind = iota
COMMIT
REBASE
CURRENT_REBASE
)
type reflogAction struct {
kind int // one of CHECKOUT, REBASE, and COMMIT
kind ReflogActionKind
from string
to string
}

View File

@ -16,8 +16,10 @@ func (gui *Gui) getCyclableWindows() []string {
}
// models/views that we can refresh
type RefreshableView int
const (
COMMITS = iota
COMMITS RefreshableView = iota
BRANCHES
FILES
STASH
@ -28,8 +30,8 @@ const (
SUBMODULES
)
func getScopeNames(scopes []int) []string {
scopeNameMap := map[int]string{
func getScopeNames(scopes []RefreshableView) []string {
scopeNameMap := map[RefreshableView]string{
COMMITS: "commits",
BRANCHES: "branches",
FILES: "files",
@ -49,7 +51,7 @@ func getScopeNames(scopes []int) []string {
return scopeNames
}
func getModeName(mode int) string {
func getModeName(mode RefreshMode) string {
switch mode {
case SYNC:
return "sync"
@ -62,20 +64,22 @@ func getModeName(mode int) string {
}
}
type RefreshMode int
const (
SYNC = iota // wait until everything is done before returning
ASYNC // return immediately, allowing each independent thing to update itself
BLOCK_UI // wrap code in an update call to ensure UI updates all at once and keybindings aren't executed till complete
SYNC RefreshMode = iota // wait until everything is done before returning
ASYNC // return immediately, allowing each independent thing to update itself
BLOCK_UI // wrap code in an update call to ensure UI updates all at once and keybindings aren't executed till complete
)
type refreshOptions struct {
then func()
scope []int // e.g. []int{COMMITS, BRANCHES}. Leave empty to refresh everything
mode int // one of SYNC (default), ASYNC, and BLOCK_UI
scope []RefreshableView // e.g. []int{COMMITS, BRANCHES}. Leave empty to refresh everything
mode RefreshMode // one of SYNC (default), ASYNC, and BLOCK_UI
}
func intArrToMap(arr []int) map[int]bool {
output := map[int]bool{}
func arrToMap(arr []RefreshableView) map[RefreshableView]bool {
output := map[RefreshableView]bool{}
for _, el := range arr {
output[el] = true
}
@ -99,11 +103,11 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
wg := sync.WaitGroup{}
f := func() {
var scopeMap map[int]bool
var scopeMap map[RefreshableView]bool
if len(options.scope) == 0 {
scopeMap = intArrToMap([]int{COMMITS, BRANCHES, FILES, STASH, REFLOG, TAGS, REMOTES, STATUS})
scopeMap = arrToMap([]RefreshableView{COMMITS, BRANCHES, FILES, STASH, REFLOG, TAGS, REMOTES, STATUS})
} else {
scopeMap = intArrToMap(options.scope)
scopeMap = arrToMap(options.scope)
}
if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] {

View File

@ -26,7 +26,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
{
@ -39,7 +39,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
{
@ -52,7 +52,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
{
@ -65,7 +65,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
{
@ -78,7 +78,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
{
@ -91,7 +91,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error {
return gui.surfaceError(err)
}
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{FILES}})
return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}})
},
},
}