1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-14 11:23:09 +02:00
lazygit/pkg/gui/context.go

807 lines
20 KiB
Go
Raw Normal View History

2019-02-16 12:01:17 +02:00
package gui
2020-08-16 02:05:45 +02:00
import (
"fmt"
2020-08-16 05:58:29 +02:00
"github.com/jesseduffield/gocui"
2020-08-16 02:05:45 +02:00
)
2020-08-16 05:58:29 +02:00
const (
SIDE_CONTEXT int = iota
MAIN_CONTEXT
TEMPORARY_POPUP
PERSISTENT_POPUP
)
2020-08-20 01:00:55 +02:00
const (
STATUS_CONTEXT_KEY = "status"
FILES_CONTEXT_KEY = "files"
LOCAL_BRANCHES_CONTEXT_KEY = "localBranches"
REMOTES_CONTEXT_KEY = "remotes"
REMOTE_BRANCHES_CONTEXT_KEY = "remoteBranches"
TAGS_CONTEXT_KEY = "tags"
BRANCH_COMMITS_CONTEXT_KEY = "commits"
REFLOG_COMMITS_CONTEXT_KEY = "reflogCommits"
2020-08-22 00:49:02 +02:00
SUB_COMMITS_CONTEXT_KEY = "subCommits"
2020-08-20 01:00:55 +02:00
COMMIT_FILES_CONTEXT_KEY = "commitFiles"
STASH_CONTEXT_KEY = "stash"
MAIN_NORMAL_CONTEXT_KEY = "normal"
MAIN_MERGING_CONTEXT_KEY = "merging"
MAIN_PATCH_BUILDING_CONTEXT_KEY = "patchBuilding"
MAIN_STAGING_CONTEXT_KEY = "staging"
MENU_CONTEXT_KEY = "menu"
CREDENTIALS_CONTEXT_KEY = "credentials"
CONFIRMATION_CONTEXT_KEY = "confirmation"
2020-09-26 09:50:22 +02:00
SEARCH_CONTEXT_KEY = "search"
2020-08-20 01:00:55 +02:00
COMMIT_MESSAGE_CONTEXT_KEY = "commitMessage"
2020-09-30 00:27:23 +02:00
SUBMODULES_CONTEXT_KEY = "submodules"
SUGGESTIONS_CONTEXT_KEY = "suggestions"
2020-08-20 01:00:55 +02:00
)
2020-09-27 01:37:22 +02:00
var allContextKeys = []string{
STATUS_CONTEXT_KEY,
FILES_CONTEXT_KEY,
LOCAL_BRANCHES_CONTEXT_KEY,
REMOTES_CONTEXT_KEY,
REMOTE_BRANCHES_CONTEXT_KEY,
TAGS_CONTEXT_KEY,
BRANCH_COMMITS_CONTEXT_KEY,
REFLOG_COMMITS_CONTEXT_KEY,
SUB_COMMITS_CONTEXT_KEY,
COMMIT_FILES_CONTEXT_KEY,
STASH_CONTEXT_KEY,
MAIN_NORMAL_CONTEXT_KEY,
MAIN_MERGING_CONTEXT_KEY,
MAIN_PATCH_BUILDING_CONTEXT_KEY,
MAIN_STAGING_CONTEXT_KEY,
MENU_CONTEXT_KEY,
CREDENTIALS_CONTEXT_KEY,
CONFIRMATION_CONTEXT_KEY,
SEARCH_CONTEXT_KEY,
COMMIT_MESSAGE_CONTEXT_KEY,
2020-09-30 00:27:23 +02:00
SUBMODULES_CONTEXT_KEY,
SUGGESTIONS_CONTEXT_KEY,
2020-09-30 00:27:23 +02:00
}
type SimpleContextNode struct {
Context Context
}
type RemotesContextNode struct {
Context Context
Branches SimpleContextNode
}
type ContextTree struct {
Status SimpleContextNode
Files SimpleContextNode
Submodules SimpleContextNode
Menu SimpleContextNode
Branches SimpleContextNode
Remotes RemotesContextNode
Tags SimpleContextNode
BranchCommits SimpleContextNode
CommitFiles SimpleContextNode
ReflogCommits SimpleContextNode
SubCommits SimpleContextNode
Stash SimpleContextNode
Normal SimpleContextNode
Staging SimpleContextNode
PatchBuilding SimpleContextNode
Merging SimpleContextNode
Credentials SimpleContextNode
Confirmation SimpleContextNode
CommitMessage SimpleContextNode
Search SimpleContextNode
Suggestions SimpleContextNode
2020-09-30 00:27:23 +02:00
}
func (gui *Gui) allContexts() []Context {
return []Context{
gui.Contexts.Status.Context,
gui.Contexts.Files.Context,
gui.Contexts.Submodules.Context,
gui.Contexts.Branches.Context,
gui.Contexts.Remotes.Context,
gui.Contexts.Remotes.Branches.Context,
gui.Contexts.Tags.Context,
gui.Contexts.BranchCommits.Context,
gui.Contexts.CommitFiles.Context,
gui.Contexts.ReflogCommits.Context,
gui.Contexts.Stash.Context,
gui.Contexts.Menu.Context,
gui.Contexts.Confirmation.Context,
gui.Contexts.Credentials.Context,
gui.Contexts.CommitMessage.Context,
gui.Contexts.Normal.Context,
gui.Contexts.Staging.Context,
gui.Contexts.Merging.Context,
gui.Contexts.PatchBuilding.Context,
gui.Contexts.SubCommits.Context,
gui.Contexts.Suggestions.Context,
2020-09-30 00:27:23 +02:00
}
2020-09-27 01:37:22 +02:00
}
2020-08-16 02:05:45 +02:00
type Context interface {
2020-08-16 05:58:29 +02:00
HandleFocus() error
HandleFocusLost() error
2020-08-19 10:06:51 +02:00
HandleRender() error
2020-08-16 05:58:29 +02:00
GetKind() int
GetViewName() string
2020-08-21 11:53:45 +02:00
GetWindowName() string
SetWindowName(string)
2020-08-16 05:58:29 +02:00
GetKey() string
SetParentContext(Context)
// we return a bool here to tell us whether or not the returned value just wraps a nil
GetParentContext() (Context, bool)
GetOptionsMap() map[string]string
2020-08-16 02:05:45 +02:00
}
2020-08-16 05:58:29 +02:00
type BasicContext struct {
OnFocus func() error
OnFocusLost func() error
OnRender func() error
OnGetOptionsMap func() map[string]string
Kind int
Key string
ViewName string
}
func (c BasicContext) GetOptionsMap() map[string]string {
if c.OnGetOptionsMap != nil {
return c.OnGetOptionsMap()
}
return nil
2020-08-16 02:05:45 +02:00
}
2020-08-21 11:53:45 +02:00
func (c BasicContext) SetWindowName(windowName string) {
panic("can't set window name on basic context")
}
func (c BasicContext) GetWindowName() string {
// TODO: fix this up
return c.GetViewName()
}
func (c BasicContext) SetParentContext(Context) {
panic("can't set parent context on basic context")
}
func (c BasicContext) GetParentContext() (Context, bool) {
return nil, false
}
2020-08-19 10:06:51 +02:00
func (c BasicContext) HandleRender() error {
if c.OnRender != nil {
return c.OnRender()
}
return nil
}
2020-08-16 05:58:29 +02:00
func (c BasicContext) GetViewName() string {
return c.ViewName
2020-08-16 02:05:45 +02:00
}
2020-08-16 05:58:29 +02:00
func (c BasicContext) HandleFocus() error {
return c.OnFocus()
}
func (c BasicContext) HandleFocusLost() error {
if c.OnFocusLost != nil {
return c.OnFocusLost()
}
return nil
}
func (c BasicContext) GetKind() int {
return c.Kind
}
func (c BasicContext) GetKey() string {
return c.Key
}
2020-08-19 11:07:14 +02:00
func (gui *Gui) contextTree() ContextTree {
return ContextTree{
Status: SimpleContextNode{
Context: BasicContext{
OnFocus: gui.handleStatusSelect,
Kind: SIDE_CONTEXT,
ViewName: "status",
2020-08-20 11:42:58 +02:00
Key: STATUS_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Files: SimpleContextNode{
Context: gui.filesListContext(),
},
2020-09-30 00:27:23 +02:00
Submodules: SimpleContextNode{
Context: gui.submodulesListContext(),
},
2020-08-19 11:07:14 +02:00
Menu: SimpleContextNode{
Context: gui.menuListContext(),
},
Remotes: RemotesContextNode{
Context: gui.remotesListContext(),
Branches: SimpleContextNode{
Context: gui.remoteBranchesListContext(),
},
},
BranchCommits: SimpleContextNode{
2020-08-19 11:07:14 +02:00
Context: gui.branchCommitsListContext(),
},
CommitFiles: SimpleContextNode{
Context: gui.commitFilesListContext(),
2020-08-19 11:07:14 +02:00
},
ReflogCommits: SimpleContextNode{
Context: gui.reflogCommitsListContext(),
},
2020-08-22 00:49:02 +02:00
SubCommits: SimpleContextNode{
Context: gui.subCommitsListContext(),
},
2020-08-19 11:07:14 +02:00
Branches: SimpleContextNode{
Context: gui.branchesListContext(),
},
Tags: SimpleContextNode{
Context: gui.tagsListContext(),
},
Stash: SimpleContextNode{
Context: gui.stashListContext(),
},
Normal: SimpleContextNode{
Context: BasicContext{
OnFocus: func() error {
return nil // TODO: should we do something here? We should allow for scrolling the panel
},
Kind: MAIN_CONTEXT,
ViewName: "main",
2020-08-23 02:13:56 +02:00
Key: MAIN_NORMAL_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Staging: SimpleContextNode{
Context: BasicContext{
OnFocus: func() error {
return nil
// TODO: centralise the code here
2020-08-19 11:07:14 +02:00
// return gui.refreshStagingPanel(false, -1)
},
Kind: MAIN_CONTEXT,
ViewName: "main",
2020-08-23 02:13:56 +02:00
Key: MAIN_STAGING_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
PatchBuilding: SimpleContextNode{
Context: BasicContext{
OnFocus: func() error {
return nil
// TODO: centralise the code here
// return gui.refreshPatchBuildingPanel(-1)
2020-08-19 11:07:14 +02:00
},
Kind: MAIN_CONTEXT,
ViewName: "main",
2020-08-23 02:13:56 +02:00
Key: MAIN_PATCH_BUILDING_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Merging: SimpleContextNode{
Context: BasicContext{
2020-11-16 11:38:26 +02:00
OnFocus: gui.refreshMergePanel,
Kind: MAIN_CONTEXT,
ViewName: "main",
Key: MAIN_MERGING_CONTEXT_KEY,
OnGetOptionsMap: gui.getMergingOptions,
2020-08-19 11:07:14 +02:00
},
},
Credentials: SimpleContextNode{
Context: BasicContext{
2020-11-16 11:38:26 +02:00
OnFocus: gui.handleCredentialsViewFocused,
2020-08-19 11:07:14 +02:00
Kind: PERSISTENT_POPUP,
ViewName: "credentials",
2020-08-23 02:13:56 +02:00
Key: CREDENTIALS_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Confirmation: SimpleContextNode{
Context: BasicContext{
OnFocus: func() error { return nil },
Kind: TEMPORARY_POPUP,
ViewName: "confirmation",
2020-08-23 02:13:56 +02:00
Key: CONFIRMATION_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Suggestions: SimpleContextNode{
Context: gui.suggestionsListContext(),
},
2020-08-19 11:07:14 +02:00
CommitMessage: SimpleContextNode{
Context: BasicContext{
2020-11-16 11:38:26 +02:00
OnFocus: gui.handleCommitMessageFocused,
2020-08-19 11:07:14 +02:00
Kind: PERSISTENT_POPUP,
ViewName: "commitMessage",
2020-08-23 02:13:56 +02:00
Key: COMMIT_MESSAGE_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
Search: SimpleContextNode{
Context: BasicContext{
OnFocus: func() error { return nil },
Kind: PERSISTENT_POPUP,
ViewName: "search",
2020-08-23 02:13:56 +02:00
Key: SEARCH_CONTEXT_KEY,
2020-08-19 11:07:14 +02:00
},
},
}
}
func (gui *Gui) initialViewContextMap() map[string]Context {
return map[string]Context{
"status": gui.Contexts.Status.Context,
"files": gui.Contexts.Files.Context,
"branches": gui.Contexts.Branches.Context,
"commits": gui.Contexts.BranchCommits.Context,
"commitFiles": gui.Contexts.CommitFiles.Context,
2020-08-19 11:07:14 +02:00
"stash": gui.Contexts.Stash.Context,
"menu": gui.Contexts.Menu.Context,
"confirmation": gui.Contexts.Confirmation.Context,
"credentials": gui.Contexts.Credentials.Context,
"commitMessage": gui.Contexts.CommitMessage.Context,
"main": gui.Contexts.Normal.Context,
"secondary": gui.Contexts.Normal.Context,
}
}
2020-08-19 13:13:43 +02:00
func (gui *Gui) viewTabContextMap() map[string][]tabContext {
return map[string][]tabContext{
"branches": {
{
tab: "Local Branches",
contexts: []Context{gui.Contexts.Branches.Context},
},
{
tab: "Remotes",
contexts: []Context{
gui.Contexts.Remotes.Context,
gui.Contexts.Remotes.Branches.Context,
},
},
{
tab: "Tags",
contexts: []Context{gui.Contexts.Tags.Context},
},
},
"commits": {
{
tab: "Commits",
contexts: []Context{gui.Contexts.BranchCommits.Context},
},
{
tab: "Reflog",
contexts: []Context{
gui.Contexts.ReflogCommits.Context,
},
},
},
2020-09-30 00:27:23 +02:00
"files": {
{
tab: "Files",
contexts: []Context{gui.Contexts.Files.Context},
},
{
tab: "Submodules",
contexts: []Context{
gui.Contexts.Submodules.Context,
},
},
},
2020-08-19 13:13:43 +02:00
}
}
2020-08-23 03:23:32 +02:00
func (gui *Gui) currentContextKeyIgnoringPopups() string {
stack := gui.State.ContextStack
for i := range stack {
reversedIndex := len(stack) - 1 - i
context := stack[reversedIndex]
kind := stack[reversedIndex].GetKind()
if kind != TEMPORARY_POPUP && kind != PERSISTENT_POPUP {
return context.GetKey()
}
}
return ""
}
// use replaceContext when you don't want to return to the original context upon
// hitting escape: you want to go that context's parent instead.
func (gui *Gui) replaceContext(c Context) error {
gui.g.Update(func(*gocui.Gui) error {
if len(gui.State.ContextStack) == 0 {
gui.State.ContextStack = []Context{c}
} else {
// replace the last item with the given item
gui.State.ContextStack = append(gui.State.ContextStack[0:len(gui.State.ContextStack)-1], c)
}
return gui.activateContext(c)
})
return nil
}
func (gui *Gui) pushContext(c Context) error {
gui.g.Update(func(*gocui.Gui) error {
// push onto stack
// if we are switching to a side context, remove all other contexts in the stack
if c.GetKind() == SIDE_CONTEXT {
for _, stackContext := range gui.State.ContextStack {
if stackContext.GetKey() != c.GetKey() {
if err := gui.deactivateContext(stackContext); err != nil {
return err
}
}
}
gui.State.ContextStack = []Context{c}
} else {
// TODO: think about other exceptional cases
gui.State.ContextStack = append(gui.State.ContextStack, c)
}
2020-08-16 05:58:29 +02:00
return gui.activateContext(c)
})
return nil
2020-08-16 05:58:29 +02:00
}
// pushContextWithView is to be used when you don't know which context you
2020-08-16 05:58:29 +02:00
// want to switch to: you only know the view that you want to switch to. It will
// look up the context currently active for that view and switch to that context
func (gui *Gui) pushContextWithView(viewName string) error {
return gui.pushContext(gui.State.ViewContextMap[viewName])
2020-08-16 05:58:29 +02:00
}
2020-08-16 10:17:16 +02:00
func (gui *Gui) returnFromContext() error {
gui.g.Update(func(*gocui.Gui) error {
// TODO: add mutexes
2020-08-16 10:17:16 +02:00
if len(gui.State.ContextStack) == 1 {
// cannot escape from bottommost context
return nil
}
2020-08-16 10:17:16 +02:00
n := len(gui.State.ContextStack) - 1
2020-08-16 10:17:16 +02:00
currentContext := gui.State.ContextStack[n]
newContext := gui.State.ContextStack[n-1]
2020-08-16 10:17:16 +02:00
gui.State.ContextStack = gui.State.ContextStack[:n]
2020-08-16 10:17:16 +02:00
if err := gui.deactivateContext(currentContext); err != nil {
return err
}
2020-08-16 10:17:16 +02:00
return gui.activateContext(newContext)
})
return nil
2020-08-16 05:58:29 +02:00
}
2020-08-17 13:58:30 +02:00
func (gui *Gui) deactivateContext(c Context) error {
// if we are the kind of context that is sent to back upon deactivation, we should do that
if c.GetKind() == TEMPORARY_POPUP || c.GetKind() == PERSISTENT_POPUP {
_, _ = gui.g.SetViewOnBottom(c.GetViewName())
}
if err := c.HandleFocusLost(); err != nil {
return err
}
return nil
}
2020-08-19 11:07:14 +02:00
// postRefreshUpdate is to be called on a context after the state that it depends on has been refreshed
// if the context's view is set to another context we do nothing.
// if the context's view is the current view we trigger a focus; re-selecting the current item.
func (gui *Gui) postRefreshUpdate(c Context) error {
2020-08-19 10:41:57 +02:00
v, err := gui.g.View(c.GetViewName())
if err != nil {
return nil
}
2020-08-19 11:07:14 +02:00
if v.Context != c.GetKey() {
return nil
}
if err := c.HandleRender(); err != nil {
return err
}
if gui.currentViewName() == c.GetViewName() {
if err := c.HandleFocus(); err != nil {
2020-08-19 10:41:57 +02:00
return err
}
}
return nil
}
2020-08-16 05:58:29 +02:00
func (gui *Gui) activateContext(c Context) error {
2020-08-16 10:17:16 +02:00
viewName := c.GetViewName()
2020-08-19 10:41:57 +02:00
v, err := gui.g.View(viewName)
2020-08-16 10:17:16 +02:00
// if view no longer exists, pop again
if err != nil {
return gui.returnFromContext()
}
2020-08-23 03:08:51 +02:00
originalViewContextKey := v.Context
2020-08-19 10:41:57 +02:00
2020-08-21 11:53:45 +02:00
// ensure that any other window for which this view was active is now set to the default for that window.
2020-08-19 11:07:14 +02:00
gui.setViewAsActiveForWindow(viewName)
if viewName == "main" {
gui.changeMainViewsContext(c.GetKey())
2020-08-19 10:41:57 +02:00
} else {
2020-11-16 11:38:26 +02:00
gui.changeMainViewsContext(MAIN_NORMAL_CONTEXT_KEY)
}
gui.setViewTabForContext(c)
2020-08-16 10:17:16 +02:00
if _, err := gui.g.SetCurrentView(viewName); err != nil {
// if view no longer exists, pop again
return gui.returnFromContext()
2020-08-16 05:58:29 +02:00
}
2020-08-16 10:17:16 +02:00
if _, err := gui.g.SetViewOnTop(viewName); err != nil {
// if view no longer exists, pop again
return gui.returnFromContext()
2020-08-16 05:58:29 +02:00
}
2020-08-23 03:08:51 +02:00
// if the new context's view was previously displaying another context, render the new context
if originalViewContextKey != c.GetKey() {
if err := c.HandleRender(); err != nil {
return err
}
}
v.Context = c.GetKey()
2020-08-16 05:58:29 +02:00
2020-08-23 03:08:51 +02:00
gui.g.Cursor = v.Editable
2020-08-16 05:58:29 +02:00
// render the options available for the current context at the bottom of the screen
optionsMap := c.GetOptionsMap()
if optionsMap == nil {
optionsMap = gui.globalOptionsMap()
2020-08-16 05:58:29 +02:00
}
gui.renderOptionsMap(optionsMap)
2020-08-16 05:58:29 +02:00
if err := c.HandleFocus(); err != nil {
return err
}
2020-08-16 06:16:28 +02:00
// TODO: consider removing this and instead depending on the .Context field of views
2020-08-16 05:58:29 +02:00
gui.State.ViewContextMap[c.GetViewName()] = c
return nil
}
2020-11-16 11:38:26 +02:00
// currently unused
// func (gui *Gui) renderContextStack() string {
// result := ""
// for _, context := range gui.State.ContextStack {
// result += context.GetKey() + "\n"
// }
// return result
// }
2020-08-16 05:58:29 +02:00
func (gui *Gui) currentContext() Context {
if len(gui.State.ContextStack) == 0 {
return gui.defaultSideContext()
}
return gui.State.ContextStack[len(gui.State.ContextStack)-1]
2020-08-16 02:05:45 +02:00
}
2020-08-22 00:49:02 +02:00
func (gui *Gui) currentSideContext() *ListContext {
stack := gui.State.ContextStack
// on startup the stack can be empty so we'll return an empty string in that case
if len(stack) == 0 {
return nil
}
// find the first context in the stack with the type of SIDE_CONTEXT
for i := range stack {
context := stack[len(stack)-1-i]
if context.GetKind() == SIDE_CONTEXT {
// not all side contexts are list contexts (e.g. the status panel)
listContext, ok := context.(*ListContext)
if !ok {
return nil
}
return listContext
2020-08-22 00:49:02 +02:00
}
}
return nil
}
func (gui *Gui) defaultSideContext() Context {
return gui.Contexts.Files.Context
}
func (gui *Gui) setInitialViewContexts() {
2020-08-17 14:00:23 +02:00
// arguably we should only have our ViewContextMap and we should do away with
// contexts on views, or vice versa
2020-08-17 13:58:30 +02:00
for viewName, context := range gui.State.ViewContextMap {
// see if the view exists. If it does, set the context on it
view, err := gui.g.View(viewName)
if err != nil {
continue
}
view.Context = context.GetKey()
2020-08-16 02:05:45 +02:00
}
}
2020-08-16 05:58:29 +02:00
// getFocusLayout returns a manager function for when view gain and lose focus
func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error {
var previousView *gocui.View
return func(g *gocui.Gui) error {
newView := gui.g.CurrentView()
2020-08-16 09:29:06 +02:00
if err := gui.onViewFocusChange(); err != nil {
2020-08-16 05:58:29 +02:00
return err
}
// for now we don't consider losing focus to a popup panel as actually losing focus
if newView != previousView && !gui.isPopupPanel(newView.Name()) {
if err := gui.onViewFocusLost(previousView, newView); err != nil {
return err
}
previousView = newView
}
return nil
}
}
2020-08-16 02:05:45 +02:00
2020-08-16 09:29:06 +02:00
func (gui *Gui) onViewFocusChange() error {
2020-09-30 22:54:29 +02:00
gui.g.Mutexes.ViewsMutex.Lock()
defer gui.g.Mutexes.ViewsMutex.Unlock()
2020-08-16 05:58:29 +02:00
currentView := gui.g.CurrentView()
for _, view := range gui.g.Views() {
view.Highlight = view.Name() != "main" && view == currentView
}
return nil
}
func (gui *Gui) onViewFocusLost(v *gocui.View, newView *gocui.View) error {
if v == nil {
return nil
}
if v.IsSearching() && newView.Name() != "search" {
if err := gui.onSearchEscape(); err != nil {
return err
}
}
return nil
}
2020-08-16 10:17:16 +02:00
// changeContext is a helper function for when we want to change a 'main' context
// which currently just means a context that affects both the main and secondary views
// other views can have their context changed directly but this function helps
// keep the main and secondary views in sync
2020-08-23 02:31:19 +02:00
func (gui *Gui) changeMainViewsContext(contextKey string) {
if gui.State.MainContext == contextKey {
2020-08-16 10:17:16 +02:00
return
}
2020-08-23 02:31:19 +02:00
switch contextKey {
case MAIN_NORMAL_CONTEXT_KEY, MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY, MAIN_MERGING_CONTEXT_KEY:
gui.getMainView().Context = contextKey
gui.getSecondaryView().Context = contextKey
default:
2020-08-23 02:31:19 +02:00
panic(fmt.Sprintf("unknown context for main: %s", contextKey))
2020-08-16 10:17:16 +02:00
}
2020-08-23 02:31:19 +02:00
gui.State.MainContext = contextKey
2020-08-16 10:17:16 +02:00
}
2020-08-19 10:41:57 +02:00
func (gui *Gui) viewTabNames(viewName string) []string {
tabContexts := gui.ViewTabContextMap[viewName]
2020-09-30 00:27:12 +02:00
if len(tabContexts) == 0 {
return nil
}
2020-08-19 10:41:57 +02:00
result := make([]string, len(tabContexts))
for i, tabContext := range tabContexts {
result[i] = tabContext.tab
}
return result
}
func (gui *Gui) setViewTabForContext(c Context) {
// search for the context in our map and if we find it, set the tab for the corresponding view
tabContexts, ok := gui.ViewTabContextMap[c.GetViewName()]
if !ok {
return
}
for tabIndex, tabContext := range tabContexts {
for _, context := range tabContext.contexts {
if context.GetKey() == c.GetKey() {
// get the view, set the tab
v, err := gui.g.View(c.GetViewName())
if err != nil {
gui.Log.Error(err)
return
}
v.TabIndex = tabIndex
return
}
}
}
}
2020-08-19 10:06:51 +02:00
type tabContext struct {
tab string
contexts []Context
}
2020-08-19 10:41:57 +02:00
2020-09-27 01:37:22 +02:00
func (gui *Gui) mustContextForContextKey(contextKey string) Context {
context, ok := gui.contextForContextKey(contextKey)
if !ok {
2020-10-07 12:19:38 +02:00
panic(fmt.Sprintf("context not found for key %s", contextKey))
2020-09-27 01:37:22 +02:00
}
return context
}
func (gui *Gui) contextForContextKey(contextKey string) (Context, bool) {
2020-08-19 11:07:14 +02:00
for _, context := range gui.allContexts() {
if context.GetKey() == contextKey {
2020-09-27 01:37:22 +02:00
return context, true
2020-08-19 11:07:14 +02:00
}
}
2020-09-27 01:37:22 +02:00
return nil, false
2020-08-19 11:07:14 +02:00
}
func (gui *Gui) rerenderView(viewName string) error {
v, err := gui.g.View(viewName)
if err != nil {
return nil
}
contextKey := v.Context
2020-09-27 01:37:22 +02:00
context := gui.mustContextForContextKey(contextKey)
2020-08-19 10:41:57 +02:00
2020-08-19 11:07:14 +02:00
return context.HandleRender()
2020-08-19 10:41:57 +02:00
}
2020-11-16 11:38:26 +02:00
// currently unused
// func (gui *Gui) getCurrentSideView() *gocui.View {
// currentSideContext := gui.currentSideContext()
// if currentSideContext == nil {
// return nil
// }
2020-11-16 11:38:26 +02:00
// view, _ := gui.g.View(currentSideContext.GetViewName())
2020-11-16 11:38:26 +02:00
// return view
// }
func (gui *Gui) getSideContextSelectedItemId() string {
currentSideContext := gui.currentSideContext()
if currentSideContext == nil {
return ""
}
item, ok := currentSideContext.GetSelectedItem()
if ok {
return item.ID()
}
return ""
}