2019-02-16 12:01:17 +02:00
|
|
|
package gui
|
|
|
|
|
2020-08-16 02:05:45 +02:00
|
|
|
import (
|
2021-11-21 03:48:49 +02:00
|
|
|
"errors"
|
2020-08-19 00:04:39 +02:00
|
|
|
"fmt"
|
2022-02-13 01:48:41 +02:00
|
|
|
"sort"
|
|
|
|
"strings"
|
2020-08-19 00:04:39 +02:00
|
|
|
|
2022-03-19 07:34:46 +02:00
|
|
|
"github.com/jesseduffield/generics/maps"
|
2022-03-19 10:12:58 +02:00
|
|
|
"github.com/jesseduffield/generics/slices"
|
2020-08-16 05:58:29 +02:00
|
|
|
"github.com/jesseduffield/gocui"
|
2022-01-29 10:15:46 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
2022-01-16 05:46:53 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
2020-08-16 02:05:45 +02:00
|
|
|
)
|
|
|
|
|
2022-05-07 07:42:36 +02:00
|
|
|
// This file is for the management of contexts. There is a context stack such that
|
|
|
|
// for example you might start off in the commits context and then open a menu, putting
|
|
|
|
// you in the menu context. When contexts are activated/deactivated certain things need
|
|
|
|
// to happen like showing/hiding views and rendering content.
|
|
|
|
|
2021-04-03 04:43:43 +02:00
|
|
|
func (gui *Gui) popupViewNames() []string {
|
2022-03-20 00:24:39 +02:00
|
|
|
popups := slices.Filter(gui.State.Contexts.Flatten(), func(c types.Context) bool {
|
|
|
|
return c.GetKind() == types.PERSISTENT_POPUP || c.GetKind() == types.TEMPORARY_POPUP
|
|
|
|
})
|
|
|
|
|
|
|
|
return slices.Map(popups, func(c types.Context) string {
|
|
|
|
return c.GetViewName()
|
|
|
|
})
|
2021-04-03 04:43:43 +02:00
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey {
|
2021-04-06 08:01:07 +02:00
|
|
|
gui.State.ContextManager.RLock()
|
|
|
|
defer gui.State.ContextManager.RUnlock()
|
2021-04-03 04:43:43 +02:00
|
|
|
|
|
|
|
stack := gui.State.ContextManager.ContextStack
|
2020-08-23 03:23:32 +02:00
|
|
|
|
|
|
|
for i := range stack {
|
|
|
|
reversedIndex := len(stack) - 1 - i
|
|
|
|
context := stack[reversedIndex]
|
|
|
|
kind := stack[reversedIndex].GetKind()
|
2022-01-16 05:46:53 +02:00
|
|
|
if kind != types.TEMPORARY_POPUP && kind != types.PERSISTENT_POPUP {
|
2020-08-23 03:23:32 +02:00
|
|
|
return context.GetKey()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-11-28 04:14:48 +02:00
|
|
|
// 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.
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) replaceContext(c types.Context) error {
|
2022-02-05 07:56:36 +02:00
|
|
|
if !c.IsFocusable() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-13 03:47:15 +02:00
|
|
|
gui.State.ContextManager.Lock()
|
|
|
|
|
2022-01-15 03:04:00 +02:00
|
|
|
if len(gui.State.ContextManager.ContextStack) == 0 {
|
2022-01-16 05:46:53 +02:00
|
|
|
gui.State.ContextManager.ContextStack = []types.Context{c}
|
2022-01-15 03:04:00 +02:00
|
|
|
} else {
|
|
|
|
// replace the last item with the given item
|
|
|
|
gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack[0:len(gui.State.ContextManager.ContextStack)-1], c)
|
|
|
|
}
|
2020-11-28 04:14:48 +02:00
|
|
|
|
2022-02-13 03:47:15 +02:00
|
|
|
defer gui.State.ContextManager.Unlock()
|
|
|
|
|
2022-01-15 03:04:00 +02:00
|
|
|
return gui.activateContext(c)
|
2020-11-28 04:14:48 +02:00
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error {
|
2021-11-21 03:48:49 +02:00
|
|
|
// using triple dot but you should only ever pass one of these opt structs
|
|
|
|
if len(opts) > 1 {
|
|
|
|
return errors.New("cannot pass multiple opts to pushContext")
|
|
|
|
}
|
|
|
|
|
2022-02-05 07:56:36 +02:00
|
|
|
if !c.IsFocusable() {
|
|
|
|
return nil
|
2022-02-05 05:42:56 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 05:32:55 +02:00
|
|
|
gui.State.ContextManager.Lock()
|
|
|
|
|
2021-04-03 04:43:43 +02:00
|
|
|
// push onto stack
|
|
|
|
// if we are switching to a side context, remove all other contexts in the stack
|
2022-01-16 05:46:53 +02:00
|
|
|
if c.GetKind() == types.SIDE_CONTEXT {
|
2021-04-03 04:43:43 +02:00
|
|
|
for _, stackContext := range gui.State.ContextManager.ContextStack {
|
|
|
|
if stackContext.GetKey() != c.GetKey() {
|
|
|
|
if err := gui.deactivateContext(stackContext); err != nil {
|
2021-04-06 05:32:55 +02:00
|
|
|
gui.State.ContextManager.Unlock()
|
2021-04-03 04:43:43 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-16 05:46:53 +02:00
|
|
|
gui.State.ContextManager.ContextStack = []types.Context{c}
|
2021-04-11 05:17:20 +02:00
|
|
|
} else if len(gui.State.ContextManager.ContextStack) == 0 || gui.currentContextWithoutLock().GetKey() != c.GetKey() {
|
2021-04-06 02:09:53 +02:00
|
|
|
// Do not append if the one at the end is the same context (e.g. opening a menu from a menu)
|
|
|
|
// In that case we'll just close the menu entirely when the user hits escape.
|
|
|
|
|
2021-04-03 04:43:43 +02:00
|
|
|
// TODO: think about other exceptional cases
|
|
|
|
gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c)
|
|
|
|
}
|
|
|
|
|
2021-04-06 05:32:55 +02:00
|
|
|
gui.State.ContextManager.Unlock()
|
|
|
|
|
2021-11-21 03:48:49 +02:00
|
|
|
return gui.activateContext(c, opts...)
|
2021-04-03 04:43:43 +02:00
|
|
|
}
|
|
|
|
|
2020-11-28 04:14:48 +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
|
2020-11-28 04:14:48 +02:00
|
|
|
func (gui *Gui) pushContextWithView(viewName string) error {
|
2022-02-05 07:56:36 +02:00
|
|
|
return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName))
|
2020-08-16 05:58:29 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 10:17:16 +02:00
|
|
|
func (gui *Gui) returnFromContext() error {
|
2021-09-25 05:21:28 +02:00
|
|
|
gui.State.ContextManager.Lock()
|
2020-08-16 10:17:16 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
if len(gui.State.ContextManager.ContextStack) == 1 {
|
|
|
|
// cannot escape from bottommost context
|
|
|
|
gui.State.ContextManager.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-16 10:17:16 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
n := len(gui.State.ContextManager.ContextStack) - 1
|
2020-08-16 10:17:16 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
currentContext := gui.State.ContextManager.ContextStack[n]
|
|
|
|
newContext := gui.State.ContextManager.ContextStack[n-1]
|
2020-08-16 10:17:16 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
gui.State.ContextManager.ContextStack = gui.State.ContextManager.ContextStack[:n]
|
2021-04-06 05:32:55 +02:00
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.g.SetCurrentContext(string(newContext.GetKey()))
|
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
gui.State.ContextManager.Unlock()
|
2020-08-16 10:17:16 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
if err := gui.deactivateContext(currentContext); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-18 14:41:27 +02:00
|
|
|
|
2021-09-25 05:21:28 +02:00
|
|
|
return gui.activateContext(newContext)
|
2020-08-16 05:58:29 +02:00
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) deactivateContext(c types.Context) error {
|
2021-04-06 02:26:18 +02:00
|
|
|
view, _ := gui.g.View(c.GetViewName())
|
|
|
|
|
|
|
|
if view != nil && view.IsSearching() {
|
|
|
|
if err := gui.onSearchEscape(); err != nil {
|
|
|
|
return err
|
2021-04-04 15:51:59 +02:00
|
|
|
}
|
2020-08-17 13:58:30 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 02:26:18 +02:00
|
|
|
// if we are the kind of context that is sent to back upon deactivation, we should do that
|
2022-03-24 13:07:30 +02:00
|
|
|
if view != nil &&
|
|
|
|
(c.GetKind() == types.TEMPORARY_POPUP ||
|
2022-03-26 05:23:47 +02:00
|
|
|
c.GetKind() == types.PERSISTENT_POPUP) {
|
2021-04-06 02:26:18 +02:00
|
|
|
view.Visible = false
|
|
|
|
}
|
|
|
|
|
2020-08-17 13:58:30 +02:00
|
|
|
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.
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) postRefreshUpdate(c types.Context) error {
|
2022-02-05 07:56:36 +02:00
|
|
|
if gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() != c.GetKey() {
|
2020-08-19 11:07:14 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) 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 err != nil {
|
2021-04-06 05:32:55 +02:00
|
|
|
return err
|
2020-08-16 10:17:16 +02:00
|
|
|
}
|
2022-02-13 01:57:30 +02:00
|
|
|
|
|
|
|
originalViewContext := gui.State.ViewContextMap.Get(viewName)
|
|
|
|
var originalViewContextKey types.ContextKey = ""
|
|
|
|
if originalViewContext != nil {
|
|
|
|
originalViewContextKey = originalViewContext.GetKey()
|
|
|
|
}
|
2020-08-19 10:41:57 +02:00
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.setWindowContext(c)
|
|
|
|
gui.setViewTabForContext(c)
|
2020-08-19 11:07:14 +02:00
|
|
|
|
2020-08-19 01:05:43 +02:00
|
|
|
if viewName == "main" {
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.changeMainViewsContext(c)
|
2020-08-19 10:41:57 +02:00
|
|
|
} else {
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.changeMainViewsContext(gui.State.Contexts.Normal)
|
2020-08-19 01:05:43 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.g.SetCurrentContext(string(c.GetKey()))
|
2020-08-16 10:17:16 +02:00
|
|
|
if _, err := gui.g.SetCurrentView(viewName); err != nil {
|
2021-04-06 05:32:55 +02:00
|
|
|
return err
|
2020-08-16 05:58:29 +02:00
|
|
|
}
|
|
|
|
|
2022-03-24 13:07:30 +02:00
|
|
|
desiredTitle := c.Title()
|
|
|
|
if desiredTitle != "" {
|
|
|
|
v.Title = desiredTitle
|
|
|
|
}
|
|
|
|
|
2021-04-04 15:51:59 +02:00
|
|
|
v.Visible = true
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 07:56:36 +02:00
|
|
|
gui.ViewContextMapSet(viewName, c)
|
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
|
|
|
|
2020-08-23 02:50:27 +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
|
|
|
}
|
2020-08-23 02:50:27 +02:00
|
|
|
gui.renderOptionsMap(optionsMap)
|
2020-08-16 05:58:29 +02:00
|
|
|
|
2021-11-21 03:48:49 +02:00
|
|
|
if err := c.HandleFocus(opts...); err != nil {
|
2020-08-16 05:58:29 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-13 01:48:41 +02:00
|
|
|
func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
|
2022-03-19 12:01:10 +02:00
|
|
|
options := maps.MapToSlice(optionsMap, func(key string, description string) string {
|
2022-03-19 07:34:46 +02:00
|
|
|
return key + ": " + description
|
|
|
|
})
|
2022-03-19 12:01:10 +02:00
|
|
|
sort.Strings(options)
|
|
|
|
return strings.Join(options, ", ")
|
2022-02-13 01:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (gui *Gui) renderOptionsMap(optionsMap map[string]string) {
|
|
|
|
_ = gui.renderString(gui.Views.Options, gui.optionsMapToString(optionsMap))
|
|
|
|
}
|
|
|
|
|
2022-02-05 07:56:36 +02:00
|
|
|
// also setting context on view for now. We'll need to pick one of these two approaches to stick with.
|
|
|
|
func (gui *Gui) ViewContextMapSet(viewName string, c types.Context) {
|
|
|
|
gui.State.ViewContextMap.Set(viewName, c)
|
|
|
|
view, err := gui.g.View(viewName)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
view.Context = string(c.GetKey())
|
|
|
|
}
|
|
|
|
|
2021-04-05 04:45:27 +02:00
|
|
|
// // currently unused
|
|
|
|
// func (gui *Gui) renderContextStack() string {
|
|
|
|
// result := ""
|
|
|
|
// for _, context := range gui.State.ContextManager.ContextStack {
|
|
|
|
// result += string(context.GetKey()) + "\n"
|
|
|
|
// }
|
|
|
|
// return result
|
|
|
|
// }
|
2020-08-16 05:58:29 +02:00
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentContext() types.Context {
|
2021-04-06 08:01:07 +02:00
|
|
|
gui.State.ContextManager.RLock()
|
|
|
|
defer gui.State.ContextManager.RUnlock()
|
2021-04-03 04:43:43 +02:00
|
|
|
|
2021-04-11 05:17:20 +02:00
|
|
|
return gui.currentContextWithoutLock()
|
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentContextWithoutLock() types.Context {
|
2021-04-03 04:43:43 +02:00
|
|
|
if len(gui.State.ContextManager.ContextStack) == 0 {
|
2020-08-23 02:17:17 +02:00
|
|
|
return gui.defaultSideContext()
|
2020-08-19 00:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-04-03 04:43:43 +02:00
|
|
|
return gui.State.ContextManager.ContextStack[len(gui.State.ContextManager.ContextStack)-1]
|
2020-08-16 02:05:45 +02:00
|
|
|
}
|
|
|
|
|
2021-04-04 15:51:59 +02:00
|
|
|
// the status panel is not yet a list context (and may never be), so this method is not
|
|
|
|
// quite the same as currentSideContext()
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentSideListContext() types.IListContext {
|
2021-04-04 15:51:59 +02:00
|
|
|
context := gui.currentSideContext()
|
2022-01-16 05:46:53 +02:00
|
|
|
listContext, ok := context.(types.IListContext)
|
2021-04-04 15:51:59 +02:00
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return listContext
|
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentSideContext() types.Context {
|
2021-04-06 08:01:07 +02:00
|
|
|
gui.State.ContextManager.RLock()
|
|
|
|
defer gui.State.ContextManager.RUnlock()
|
2021-04-03 04:43:43 +02:00
|
|
|
|
|
|
|
stack := gui.State.ContextManager.ContextStack
|
2020-08-22 00:49:02 +02:00
|
|
|
|
|
|
|
// on startup the stack can be empty so we'll return an empty string in that case
|
|
|
|
if len(stack) == 0 {
|
2021-04-04 15:51:59 +02:00
|
|
|
return gui.defaultSideContext()
|
2020-08-22 00:49:02 +02:00
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
// find the first context in the stack with the type of types.SIDE_CONTEXT
|
2020-08-22 00:49:02 +02:00
|
|
|
for i := range stack {
|
|
|
|
context := stack[len(stack)-1-i]
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
if context.GetKind() == types.SIDE_CONTEXT {
|
2021-04-04 15:51:59 +02:00
|
|
|
return context
|
2020-08-22 00:49:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-04 15:51:59 +02:00
|
|
|
return gui.defaultSideContext()
|
2020-08-22 00:49:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-11 07:01:49 +02:00
|
|
|
// static as opposed to popup
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) currentStaticContext() types.Context {
|
2021-04-11 07:01:49 +02:00
|
|
|
gui.State.ContextManager.RLock()
|
|
|
|
defer gui.State.ContextManager.RUnlock()
|
|
|
|
|
|
|
|
stack := gui.State.ContextManager.ContextStack
|
|
|
|
|
|
|
|
if len(stack) == 0 {
|
|
|
|
return gui.defaultSideContext()
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the first context in the stack without a popup type
|
|
|
|
for i := range stack {
|
|
|
|
context := stack[len(stack)-1-i]
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
if context.GetKind() != types.TEMPORARY_POPUP && context.GetKind() != types.PERSISTENT_POPUP {
|
2021-04-11 07:01:49 +02:00
|
|
|
return context
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return gui.defaultSideContext()
|
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) defaultSideContext() types.Context {
|
2021-04-04 15:51:59 +02:00
|
|
|
if gui.State.Modes.Filtering.Active() {
|
2022-02-13 08:01:53 +02:00
|
|
|
return gui.State.Contexts.LocalCommits
|
2021-04-04 15:51:59 +02:00
|
|
|
} else {
|
|
|
|
return gui.State.Contexts.Files
|
|
|
|
}
|
2020-08-22 00:49:02 +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()
|
|
|
|
// 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
|
|
|
|
2021-04-04 16:53:34 +02:00
|
|
|
func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error {
|
|
|
|
if oldView == nil {
|
2020-08-16 05:58:29 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-15 06:01:13 +02:00
|
|
|
oldView.Highlight = false
|
|
|
|
|
2021-11-02 11:35:53 +02:00
|
|
|
_ = oldView.SetOriginX(0)
|
|
|
|
|
2020-08-16 05:58:29 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-26 05:44:30 +02:00
|
|
|
func (gui *Gui) TransientContexts() []types.Context {
|
|
|
|
return slices.Filter(gui.State.Contexts.Flatten(), func(context types.Context) bool {
|
|
|
|
return context.IsTransient()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
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
|
2022-02-05 05:42:56 +02:00
|
|
|
func (gui *Gui) changeMainViewsContext(c types.Context) {
|
|
|
|
if gui.State.MainContext == c.GetKey() {
|
2020-08-16 10:17:16 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
switch c.GetKey() {
|
2022-01-29 10:15:46 +02:00
|
|
|
case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY:
|
2022-02-05 07:56:36 +02:00
|
|
|
gui.ViewContextMapSet(gui.Views.Main.Name(), c)
|
|
|
|
gui.ViewContextMapSet(gui.Views.Secondary.Name(), c)
|
2020-08-19 00:04:39 +02:00
|
|
|
default:
|
2022-02-05 05:42:56 +02:00
|
|
|
panic(fmt.Sprintf("unknown context for main: %s", c.GetKey()))
|
2020-08-16 10:17:16 +02:00
|
|
|
}
|
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
gui.State.MainContext = c.GetKey()
|
2020-08-16 10:17:16 +02:00
|
|
|
}
|
2020-08-19 01:05:43 +02:00
|
|
|
|
2020-08-19 10:41:57 +02:00
|
|
|
func (gui *Gui) viewTabNames(viewName string) []string {
|
2021-04-03 05:36:22 +02:00
|
|
|
tabContexts := gui.State.ViewTabContextMap[viewName]
|
2020-08-19 10:41:57 +02:00
|
|
|
|
2022-03-19 10:12:58 +02:00
|
|
|
return slices.Map(tabContexts, func(tabContext context.TabContext) string {
|
|
|
|
return tabContext.Tab
|
|
|
|
})
|
2020-08-19 10:41:57 +02:00
|
|
|
}
|
|
|
|
|
2022-01-16 05:46:53 +02:00
|
|
|
func (gui *Gui) setViewTabForContext(c types.Context) {
|
2020-08-19 01:05:43 +02:00
|
|
|
// search for the context in our map and if we find it, set the tab for the corresponding view
|
2021-04-03 05:36:22 +02:00
|
|
|
tabContexts, ok := gui.State.ViewTabContextMap[c.GetViewName()]
|
2020-08-19 01:05:43 +02:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for tabIndex, tabContext := range tabContexts {
|
2022-03-26 05:33:39 +02:00
|
|
|
if tabContext.Context.GetKey() == c.GetKey() {
|
|
|
|
// get the view, set the tab
|
|
|
|
v, err := gui.g.View(c.GetViewName())
|
|
|
|
if err != nil {
|
|
|
|
gui.c.Log.Error(err)
|
2020-08-19 01:05:43 +02:00
|
|
|
return
|
|
|
|
}
|
2022-03-26 05:33:39 +02:00
|
|
|
v.TabIndex = tabIndex
|
|
|
|
return
|
2020-08-19 01:05:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-04 16:44:13 +02:00
|
|
|
func (gui *Gui) rerenderView(view *gocui.View) error {
|
2022-02-05 07:56:36 +02:00
|
|
|
return gui.State.ViewContextMap.Get(view.Name()).HandleRender()
|
2020-08-19 10:41:57 +02:00
|
|
|
}
|
2020-08-22 01:55:49 +02:00
|
|
|
|
2020-08-22 07:56:30 +02:00
|
|
|
func (gui *Gui) getSideContextSelectedItemId() string {
|
2021-04-04 15:51:59 +02:00
|
|
|
currentSideContext := gui.currentSideListContext()
|
2020-08-22 04:07:03 +02:00
|
|
|
if currentSideContext == nil {
|
2020-08-22 07:56:30 +02:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-01-30 11:03:08 +02:00
|
|
|
return currentSideContext.GetSelectedItemId()
|
2020-08-22 04:07:03 +02:00
|
|
|
}
|
2021-04-06 06:21:17 +02:00
|
|
|
|
2022-02-05 05:42:56 +02:00
|
|
|
func (gui *Gui) isContextVisible(c types.Context) bool {
|
2022-03-26 05:23:47 +02:00
|
|
|
return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() &&
|
|
|
|
gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() == c.GetKey()
|
2022-02-05 05:42:56 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 06:21:17 +02:00
|
|
|
// currently unused
|
|
|
|
// func (gui *Gui) getCurrentSideView() *gocui.View {
|
|
|
|
// currentSideContext := gui.currentSideContext()
|
|
|
|
// if currentSideContext == nil {
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
|
|
|
|
// view, _ := gui.g.View(currentSideContext.GetViewName())
|
|
|
|
|
|
|
|
// return view
|
|
|
|
// }
|
|
|
|
|
|
|
|
// currently unused
|
|
|
|
// func (gui *Gui) renderContextStack() string {
|
|
|
|
// result := ""
|
|
|
|
// for _, context := range gui.State.ContextManager.ContextStack {
|
|
|
|
// result += context.GetViewName() + "\n"
|
|
|
|
// }
|
|
|
|
// return result
|
|
|
|
// }
|