mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-01 13:17:53 +02:00
more refactoring
This commit is contained in:
parent
8e3484d8e9
commit
482bdc4f1e
@ -124,7 +124,7 @@ func formatBinding(binding *types.Binding) string {
|
||||
func getBindingSections(mApp *app.App) []*bindingSection {
|
||||
bindingSections := []*bindingSection{}
|
||||
|
||||
bindings := mApp.Gui.GetInitialKeybindings()
|
||||
bindings, _ := mApp.Gui.GetInitialKeybindings()
|
||||
|
||||
type contextAndViewType struct {
|
||||
subtitle string
|
||||
|
@ -257,7 +257,7 @@ func (gui *Gui) handleToggleCommitFileDirCollapsed() error {
|
||||
func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error {
|
||||
// sometimes the commitFiles view is already shown in another window, so we need to ensure that window
|
||||
// no longer considers the commitFiles view as its main view.
|
||||
gui.resetWindowForView(gui.Views.CommitFiles)
|
||||
gui.resetWindowContext(gui.State.Contexts.CommitFiles)
|
||||
|
||||
gui.State.Contexts.CommitFiles.SetSelectedLineIdx(0)
|
||||
gui.State.Contexts.CommitFiles.SetRefName(opts.RefName)
|
||||
|
@ -60,6 +60,10 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error {
|
||||
return errors.New("cannot pass multiple opts to pushContext")
|
||||
}
|
||||
|
||||
if c.GetKey() == context.GLOBAL_CONTEXT_KEY {
|
||||
return errors.New("Cannot push global context")
|
||||
}
|
||||
|
||||
gui.State.ContextManager.Lock()
|
||||
|
||||
// push onto stack
|
||||
@ -112,6 +116,8 @@ func (gui *Gui) returnFromContext() error {
|
||||
|
||||
gui.State.ContextManager.ContextStack = gui.State.ContextManager.ContextStack[:n]
|
||||
|
||||
gui.g.SetCurrentContext(string(newContext.GetKey()))
|
||||
|
||||
gui.State.ContextManager.Unlock()
|
||||
|
||||
if err := gui.deactivateContext(currentContext); err != nil {
|
||||
@ -146,12 +152,7 @@ func (gui *Gui) deactivateContext(c types.Context) error {
|
||||
// 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 types.Context) error {
|
||||
v, err := gui.g.View(c.GetViewName())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if types.ContextKey(v.Context) != c.GetKey() {
|
||||
if gui.State.ViewContextMap[c.GetViewName()].GetKey() != c.GetKey() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -174,19 +175,18 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
originalViewContextKey := types.ContextKey(v.Context)
|
||||
|
||||
// ensure that any other window for which this view was active is now set to the default for that window.
|
||||
gui.setViewAsActiveForWindow(v)
|
||||
|
||||
if viewName == "main" {
|
||||
gui.changeMainViewsContext(c.GetKey())
|
||||
} else {
|
||||
gui.changeMainViewsContext(context.MAIN_NORMAL_CONTEXT_KEY)
|
||||
}
|
||||
originalViewContextKey := gui.State.ViewContextMap[viewName].GetKey()
|
||||
|
||||
gui.setWindowContext(c)
|
||||
gui.setViewTabForContext(c)
|
||||
|
||||
if viewName == "main" {
|
||||
gui.changeMainViewsContext(c)
|
||||
} else {
|
||||
gui.changeMainViewsContext(gui.State.Contexts.Normal)
|
||||
}
|
||||
|
||||
gui.g.SetCurrentContext(string(c.GetKey()))
|
||||
if _, err := gui.g.SetCurrentView(viewName); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -200,7 +200,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro
|
||||
}
|
||||
}
|
||||
|
||||
v.Context = string(c.GetKey())
|
||||
gui.State.ViewContextMap[viewName] = c
|
||||
|
||||
gui.g.Cursor = v.Editable
|
||||
|
||||
@ -310,21 +310,6 @@ func (gui *Gui) defaultSideContext() types.Context {
|
||||
}
|
||||
}
|
||||
|
||||
// remove the need to do this: always use a mapping
|
||||
func (gui *Gui) setInitialViewContexts() {
|
||||
// arguably we should only have our ViewContextMap and we should do away with
|
||||
// contexts on views, or vice versa
|
||||
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 = string(context.GetKey())
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -364,7 +349,7 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error
|
||||
_ = oldView.SetOriginX(0)
|
||||
|
||||
if oldView == gui.Views.CommitFiles && newView != gui.Views.Main && newView != gui.Views.Secondary && newView != gui.Views.Search {
|
||||
gui.resetWindowForView(gui.Views.CommitFiles)
|
||||
gui.resetWindowContext(gui.State.Contexts.CommitFiles)
|
||||
if err := gui.deactivateContext(gui.State.Contexts.CommitFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -377,20 +362,20 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error
|
||||
// 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
|
||||
func (gui *Gui) changeMainViewsContext(contextKey types.ContextKey) {
|
||||
if gui.State.MainContext == contextKey {
|
||||
func (gui *Gui) changeMainViewsContext(c types.Context) {
|
||||
if gui.State.MainContext == c.GetKey() {
|
||||
return
|
||||
}
|
||||
|
||||
switch contextKey {
|
||||
switch c.GetKey() {
|
||||
case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY:
|
||||
gui.Views.Main.Context = string(contextKey)
|
||||
gui.Views.Secondary.Context = string(contextKey)
|
||||
gui.State.ViewContextMap[gui.Views.Main.Name()] = c
|
||||
gui.State.ViewContextMap[gui.Views.Secondary.Name()] = c
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown context for main: %s", contextKey))
|
||||
panic(fmt.Sprintf("unknown context for main: %s", c.GetKey()))
|
||||
}
|
||||
|
||||
gui.State.MainContext = contextKey
|
||||
gui.State.MainContext = c.GetKey()
|
||||
}
|
||||
|
||||
func (gui *Gui) viewTabNames(viewName string) []string {
|
||||
@ -452,8 +437,11 @@ func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context
|
||||
}
|
||||
|
||||
func (gui *Gui) rerenderView(view *gocui.View) error {
|
||||
contextKey := types.ContextKey(view.Context)
|
||||
context := gui.mustContextForContextKey(contextKey)
|
||||
context, ok := gui.State.ViewContextMap[view.Name()]
|
||||
|
||||
if !ok {
|
||||
panic("no context set against view " + view.Name())
|
||||
}
|
||||
|
||||
return context.HandleRender()
|
||||
}
|
||||
@ -467,6 +455,10 @@ func (gui *Gui) getSideContextSelectedItemId() string {
|
||||
return currentSideContext.GetSelectedItemId()
|
||||
}
|
||||
|
||||
func (gui *Gui) isContextVisible(c types.Context) bool {
|
||||
return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap[c.GetViewName()].GetKey() == c.GetKey()
|
||||
}
|
||||
|
||||
// currently unused
|
||||
// func (gui *Gui) getCurrentSideView() *gocui.View {
|
||||
// currentSideContext := gui.currentSideContext()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
@ -11,8 +12,8 @@ type BaseContext struct {
|
||||
windowName string
|
||||
onGetOptionsMap func() map[string]string
|
||||
|
||||
keybindingsFns []types.KeybindingsFn
|
||||
keybindings []*types.Binding
|
||||
keybindingsFns []types.KeybindingsFn
|
||||
mouseKeybindingsFns []types.MouseKeybindingsFn
|
||||
|
||||
*ParentContextMgr
|
||||
}
|
||||
@ -80,3 +81,18 @@ func (self *BaseContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Bin
|
||||
func (self *BaseContext) AddKeybindingsFn(fn types.KeybindingsFn) {
|
||||
self.keybindingsFns = append(self.keybindingsFns, fn)
|
||||
}
|
||||
|
||||
func (self *BaseContext) AddMouseKeybindingsFn(fn types.MouseKeybindingsFn) {
|
||||
self.mouseKeybindingsFns = append(self.mouseKeybindingsFns, fn)
|
||||
}
|
||||
|
||||
func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
|
||||
bindings := []*gocui.ViewMouseBinding{}
|
||||
for i := range self.mouseKeybindingsFns {
|
||||
// the first binding in the bindings array takes precedence but we want the
|
||||
// last keybindingsFn to take precedence to we add them in reverse
|
||||
bindings = append(bindings, self.mouseKeybindingsFns[len(self.mouseKeybindingsFns)-1-i](opts)...)
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package context
|
||||
import "github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
||||
const (
|
||||
GLOBAL_CONTEXT_KEY types.ContextKey = "global"
|
||||
STATUS_CONTEXT_KEY types.ContextKey = "status"
|
||||
FILES_CONTEXT_KEY types.ContextKey = "files"
|
||||
LOCAL_BRANCHES_CONTEXT_KEY types.ContextKey = "localBranches"
|
||||
@ -29,6 +30,7 @@ const (
|
||||
)
|
||||
|
||||
var AllContextKeys = []types.ContextKey{
|
||||
GLOBAL_CONTEXT_KEY,
|
||||
STATUS_CONTEXT_KEY,
|
||||
FILES_CONTEXT_KEY,
|
||||
LOCAL_BRANCHES_CONTEXT_KEY,
|
||||
@ -55,6 +57,7 @@ var AllContextKeys = []types.ContextKey{
|
||||
}
|
||||
|
||||
type ContextTree struct {
|
||||
Global types.Context
|
||||
Status types.Context
|
||||
Files *WorkingTreeContext
|
||||
Submodules types.IListContext
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
func (gui *Gui) allContexts() []types.Context {
|
||||
return []types.Context{
|
||||
gui.State.Contexts.Global,
|
||||
gui.State.Contexts.Status,
|
||||
gui.State.Contexts.Files,
|
||||
gui.State.Contexts.Submodules,
|
||||
@ -34,12 +35,23 @@ func (gui *Gui) allContexts() []types.Context {
|
||||
|
||||
func (gui *Gui) contextTree() *context.ContextTree {
|
||||
return &context.ContextTree{
|
||||
Global: NewSimpleContext(
|
||||
context.NewBaseContext(context.NewBaseContextOpts{
|
||||
Kind: types.GLOBAL_CONTEXT,
|
||||
ViewName: "",
|
||||
WindowName: "",
|
||||
Key: context.GLOBAL_CONTEXT_KEY,
|
||||
}),
|
||||
NewSimpleContextOpts{
|
||||
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain),
|
||||
},
|
||||
),
|
||||
Status: NewSimpleContext(
|
||||
context.NewBaseContext(context.NewBaseContextOpts{
|
||||
Kind: types.SIDE_CONTEXT,
|
||||
ViewName: "status",
|
||||
Key: context.STATUS_CONTEXT_KEY,
|
||||
WindowName: "status",
|
||||
Key: context.STATUS_CONTEXT_KEY,
|
||||
}),
|
||||
NewSimpleContextOpts{
|
||||
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain),
|
||||
|
10
pkg/gui/controllers/attach.go
Normal file
10
pkg/gui/controllers/attach.go
Normal file
@ -0,0 +1,10 @@
|
||||
package controllers
|
||||
|
||||
import "github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
||||
func AttachControllers(context types.Context, controllers ...types.IController) {
|
||||
for _, controller := range controllers {
|
||||
context.AddKeybindingsFn(controller.GetKeybindings)
|
||||
context.AddMouseKeybindingsFn(controller.GetMouseKeybindings)
|
||||
}
|
||||
}
|
16
pkg/gui/controllers/base_controller.go
Normal file
16
pkg/gui/controllers/base_controller.go
Normal file
@ -0,0 +1,16 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type baseController struct{}
|
||||
|
||||
func (self *baseController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *baseController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
|
||||
return nil
|
||||
}
|
@ -11,6 +11,8 @@ import (
|
||||
)
|
||||
|
||||
type BisectController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
context types.IListContext
|
||||
git *commands.GitCommand
|
||||
@ -32,10 +34,11 @@ func NewBisectController(
|
||||
getCommits func() []*models.Commit,
|
||||
) *BisectController {
|
||||
return &BisectController{
|
||||
c: c,
|
||||
context: context,
|
||||
git: git,
|
||||
bisectHelper: bisectHelper,
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
context: context,
|
||||
git: git,
|
||||
bisectHelper: bisectHelper,
|
||||
|
||||
getSelectedLocalCommit: getSelectedLocalCommit,
|
||||
getCommits: getCommits,
|
||||
|
@ -190,6 +190,21 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
|
||||
return []*gocui.ViewMouseBinding{
|
||||
{
|
||||
ViewName: "main",
|
||||
Key: gocui.MouseLeft,
|
||||
Handler: self.onClickMain,
|
||||
},
|
||||
{
|
||||
ViewName: "secondary",
|
||||
Key: gocui.MouseLeft,
|
||||
Handler: self.onClickSecondary,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *FilesController) press(node *filetree.FileNode) error {
|
||||
if node.IsLeaf() {
|
||||
file := node.File
|
||||
@ -672,3 +687,13 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *FilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error {
|
||||
clickedViewLineIdx := opts.Cy + opts.Oy
|
||||
return self.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx})
|
||||
}
|
||||
|
||||
func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error {
|
||||
clickedViewLineIdx := opts.Cy + opts.Oy
|
||||
return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: clickedViewLineIdx})
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
)
|
||||
|
||||
type GlobalController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
os *oscommands.OSCommand
|
||||
}
|
||||
@ -16,8 +18,9 @@ func NewGlobalController(
|
||||
os *oscommands.OSCommand,
|
||||
) *GlobalController {
|
||||
return &GlobalController{
|
||||
c: c,
|
||||
os: os,
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
os: os,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ type (
|
||||
)
|
||||
|
||||
type LocalCommitsController struct {
|
||||
baseController
|
||||
c *types.ControllerCommon
|
||||
context types.IListContext
|
||||
os *oscommands.OSCommand
|
||||
@ -68,6 +69,7 @@ func NewLocalCommitsController(
|
||||
setShowWholeGitGraph func(bool),
|
||||
) *LocalCommitsController {
|
||||
return &LocalCommitsController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
context: context,
|
||||
os: os,
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
)
|
||||
|
||||
type MenuController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
context types.IListContext
|
||||
|
||||
@ -20,6 +22,8 @@ func NewMenuController(
|
||||
getSelectedMenuItem func() *types.MenuItem,
|
||||
) *MenuController {
|
||||
return &MenuController{
|
||||
baseController: baseController{},
|
||||
|
||||
c: c,
|
||||
context: context,
|
||||
getSelectedMenuItem: getSelectedMenuItem,
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
)
|
||||
|
||||
type RemotesController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
context types.IListContext
|
||||
git *commands.GitCommand
|
||||
@ -30,6 +32,7 @@ func NewRemotesController(
|
||||
setRemoteBranches func([]*models.RemoteBranch),
|
||||
) *RemotesController {
|
||||
return &RemotesController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
git: git,
|
||||
contexts: contexts,
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
)
|
||||
|
||||
type SubmodulesController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
context types.IListContext
|
||||
git *commands.GitCommand
|
||||
@ -31,6 +33,7 @@ func NewSubmodulesController(
|
||||
getSelectedSubmodule func() *models.SubmoduleConfig,
|
||||
) *SubmodulesController {
|
||||
return &SubmodulesController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
context: context,
|
||||
git: git,
|
||||
|
@ -11,10 +11,8 @@ import (
|
||||
)
|
||||
|
||||
type SyncController struct {
|
||||
// I've said publicly that I'm against single-letter variable names but in this
|
||||
// case I would actually prefer a _zero_ letter variable name in the form of
|
||||
// struct embedding, but Go does not allow hiding public fields in an embedded struct
|
||||
// to the client
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
git *commands.GitCommand
|
||||
|
||||
@ -35,8 +33,9 @@ func NewSyncController(
|
||||
CheckMergeOrRebase func(error) error,
|
||||
) *SyncController {
|
||||
return &SyncController{
|
||||
c: c,
|
||||
git: git,
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
git: git,
|
||||
|
||||
getCheckedOutBranch: getCheckedOutBranch,
|
||||
suggestionsHelper: suggestionsHelper,
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type TagsController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
context *context.TagsContext
|
||||
git *commands.GitCommand
|
||||
@ -35,6 +37,7 @@ func NewTagsController(
|
||||
switchToSubCommitsContext func(string) error,
|
||||
) *TagsController {
|
||||
return &TagsController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
context: context,
|
||||
git: git,
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
// two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way.
|
||||
|
||||
type UndoController struct {
|
||||
baseController
|
||||
|
||||
c *types.ControllerCommon
|
||||
git *commands.GitCommand
|
||||
|
||||
@ -39,6 +41,7 @@ func NewUndoController(
|
||||
getFilteredReflogCommits func() []*models.Commit,
|
||||
) *UndoController {
|
||||
return &UndoController{
|
||||
baseController: baseController{},
|
||||
c: c,
|
||||
git: git,
|
||||
refsHelper: refsHelper,
|
||||
|
@ -182,11 +182,6 @@ func (gui *Gui) handleRefresh() error {
|
||||
|
||||
func (gui *Gui) handleMouseDownMain() error {
|
||||
switch gui.currentSideContext() {
|
||||
case gui.State.Contexts.Files:
|
||||
// set filename, set primary/secondary selected, set line number, then switch context
|
||||
// I'll need to know it was changed though.
|
||||
// Could I pass something along to the context change?
|
||||
return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()})
|
||||
case gui.State.Contexts.CommitFiles:
|
||||
return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()})
|
||||
}
|
||||
@ -194,15 +189,6 @@ func (gui *Gui) handleMouseDownMain() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleMouseDownSecondary() error {
|
||||
switch gui.g.CurrentView() {
|
||||
case gui.Views.Files:
|
||||
return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: gui.Views.Secondary.SelectedLineIdx()})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) fetch() (err error) {
|
||||
gui.c.LogAction("Fetch")
|
||||
err = gui.git.Sync.Fetch(git_commands.FetchOptions{})
|
||||
|
@ -590,6 +590,15 @@ func (gui *Gui) resetControllers() {
|
||||
gui.getSelectedSubmodule,
|
||||
)
|
||||
|
||||
bisectController := controllers.NewBisectController(
|
||||
controllerCommon,
|
||||
gui.State.Contexts.BranchCommits,
|
||||
gui.git,
|
||||
gui.helpers.Bisect,
|
||||
gui.getSelectedLocalCommit,
|
||||
func() []*models.Commit { return gui.State.Model.Commits },
|
||||
)
|
||||
|
||||
gui.Controllers = Controllers{
|
||||
Submodules: submodulesController,
|
||||
Global: controllers.NewGlobalController(
|
||||
@ -660,14 +669,6 @@ func (gui *Gui) resetControllers() {
|
||||
gui.State.Contexts.Menu,
|
||||
gui.getSelectedMenuItem,
|
||||
),
|
||||
Bisect: controllers.NewBisectController(
|
||||
controllerCommon,
|
||||
gui.State.Contexts.BranchCommits,
|
||||
gui.git,
|
||||
gui.helpers.Bisect,
|
||||
gui.getSelectedLocalCommit,
|
||||
func() []*models.Commit { return gui.State.Model.Commits },
|
||||
),
|
||||
Undo: controllers.NewUndoController(
|
||||
controllerCommon,
|
||||
gui.git,
|
||||
@ -678,17 +679,13 @@ func (gui *Gui) resetControllers() {
|
||||
Sync: syncController,
|
||||
}
|
||||
|
||||
gui.State.Contexts.Submodules.AddKeybindingsFn(gui.Controllers.Submodules.GetKeybindings)
|
||||
gui.Controllers.Files.Attach(gui.State.Contexts.Files)
|
||||
gui.State.Contexts.Files.AddKeybindingsFn(gui.Controllers.Files.GetKeybindings)
|
||||
gui.State.Contexts.Tags.AddKeybindingsFn(gui.Controllers.Tags.GetKeybindings)
|
||||
// TODO: commit to one name here: local commits or branch commits
|
||||
gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.LocalCommits.GetKeybindings)
|
||||
gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.Bisect.GetKeybindings)
|
||||
gui.State.Contexts.Remotes.AddKeybindingsFn(gui.Controllers.Remotes.GetKeybindings)
|
||||
gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings)
|
||||
gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings)
|
||||
// TODO: handle global contexts
|
||||
controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files)
|
||||
controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags)
|
||||
controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules)
|
||||
controllers.AttachControllers(gui.State.Contexts.BranchCommits, gui.Controllers.LocalCommits, bisectController)
|
||||
controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes)
|
||||
controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu)
|
||||
controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global)
|
||||
}
|
||||
|
||||
var RuneReplacements = map[rune]string{
|
||||
|
@ -39,7 +39,6 @@ import (
|
||||
// original playback speed. Speed may be a decimal.
|
||||
|
||||
func Test(t *testing.T) {
|
||||
return
|
||||
mode := integration.GetModeFromEnv()
|
||||
speedEnv := os.Getenv("SPEED")
|
||||
includeSkipped := os.Getenv("INCLUDE_SKIPPED") != ""
|
||||
|
@ -194,8 +194,7 @@ func (gui *Gui) noPopupPanel(f func() error) func() error {
|
||||
}
|
||||
}
|
||||
|
||||
// GetInitialKeybindings is a function.
|
||||
func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
||||
func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) {
|
||||
config := gui.c.UserConfig.Keybinding
|
||||
|
||||
guards := types.KeybindingGuards{
|
||||
@ -306,12 +305,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCreateOptionsMenu,
|
||||
},
|
||||
{
|
||||
ViewName: "",
|
||||
Key: gocui.MouseMiddle,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCreateOptionsMenu,
|
||||
},
|
||||
{
|
||||
ViewName: "status",
|
||||
Key: gui.getKey(config.Universal.Edit),
|
||||
@ -788,13 +781,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownSecondary,
|
||||
},
|
||||
{
|
||||
ViewName: "secondary",
|
||||
Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)},
|
||||
Key: gocui.MouseLeft,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleMouseDownSecondary,
|
||||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)},
|
||||
@ -1361,35 +1347,24 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
||||
Guards: guards,
|
||||
}
|
||||
|
||||
// global bindings
|
||||
for _, controller := range []types.IController{
|
||||
gui.Controllers.Sync,
|
||||
gui.Controllers.Undo,
|
||||
gui.Controllers.Global,
|
||||
} {
|
||||
context := controller.Context()
|
||||
viewName := ""
|
||||
var contextKeys []string
|
||||
// nil context means global keybinding
|
||||
if context != nil {
|
||||
viewName = context.GetViewName()
|
||||
contextKeys = []string{string(context.GetKey())}
|
||||
}
|
||||
|
||||
for _, binding := range controller.GetKeybindings(keybindingsOpts) {
|
||||
binding.Contexts = contextKeys
|
||||
mouseKeybindings := []*gocui.ViewMouseBinding{}
|
||||
for _, c := range gui.allContexts() {
|
||||
viewName := c.GetViewName()
|
||||
contextKey := c.GetKey()
|
||||
for _, binding := range c.GetKeybindings(keybindingsOpts) {
|
||||
// TODO: move all mouse keybindings into the mouse keybindings approach below
|
||||
if !gocui.IsMouseKey(binding.Key) && contextKey != context.GLOBAL_CONTEXT_KEY {
|
||||
binding.Contexts = []string{string(contextKey)}
|
||||
}
|
||||
binding.ViewName = viewName
|
||||
bindings = append(bindings, binding)
|
||||
}
|
||||
}
|
||||
|
||||
for _, context := range gui.allContexts() {
|
||||
viewName := context.GetViewName()
|
||||
contextKey := context.GetKey()
|
||||
for _, binding := range context.GetKeybindings(keybindingsOpts) {
|
||||
binding.Contexts = []string{string(contextKey)}
|
||||
binding.ViewName = viewName
|
||||
bindings = append(bindings, binding)
|
||||
for _, binding := range c.GetMouseKeybindings(keybindingsOpts) {
|
||||
if contextKey != context.GLOBAL_CONTEXT_KEY {
|
||||
binding.FromContext = string(contextKey)
|
||||
}
|
||||
mouseKeybindings = append(mouseKeybindings, binding)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1438,7 +1413,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding {
|
||||
}...)
|
||||
}
|
||||
|
||||
return bindings
|
||||
return bindings, mouseKeybindings
|
||||
}
|
||||
|
||||
func (gui *Gui) resetKeybindings() error {
|
||||
@ -1446,7 +1421,10 @@ func (gui *Gui) resetKeybindings() error {
|
||||
|
||||
bindings := gui.GetCustomCommandKeybindings()
|
||||
|
||||
bindings = append(bindings, gui.GetInitialKeybindings()...)
|
||||
bindings, mouseBindings := gui.GetInitialKeybindings()
|
||||
|
||||
// prepending because we want to give our custom keybindings precedence over default keybindings
|
||||
bindings = append(gui.GetCustomCommandKeybindings(), bindings...)
|
||||
|
||||
for _, binding := range bindings {
|
||||
if err := gui.SetKeybinding(binding); err != nil {
|
||||
@ -1454,6 +1432,12 @@ func (gui *Gui) resetKeybindings() error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, binding := range mouseBindings {
|
||||
if err := gui.SetMouseKeybinding(binding); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for viewName := range gui.State.Contexts.InitialViewTabContextMap() {
|
||||
viewName := viewName
|
||||
tabClickCallback := func(tabIndex int) error { return gui.onViewTabClick(viewName, tabIndex) }
|
||||
@ -1474,7 +1458,8 @@ func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View)
|
||||
|
||||
func (gui *Gui) SetKeybinding(binding *types.Binding) error {
|
||||
handler := binding.Handler
|
||||
if isMouseKey(binding.Key) {
|
||||
// TODO: move all mouse-ey stuff into new mouse approach
|
||||
if gocui.IsMouseKey(binding.Key) {
|
||||
handler = func() error {
|
||||
// we ignore click events on views that aren't popup panels, when a popup panel is focused
|
||||
if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName {
|
||||
@ -1488,19 +1473,18 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) error {
|
||||
return gui.g.SetKeybinding(binding.ViewName, binding.Contexts, binding.Key, binding.Modifier, gui.wrappedHandler(handler))
|
||||
}
|
||||
|
||||
func isMouseKey(key interface{}) bool {
|
||||
switch key {
|
||||
case
|
||||
gocui.MouseLeft,
|
||||
gocui.MouseRight,
|
||||
gocui.MouseMiddle,
|
||||
gocui.MouseRelease,
|
||||
gocui.MouseWheelUp,
|
||||
gocui.MouseWheelDown,
|
||||
gocui.MouseWheelLeft,
|
||||
gocui.MouseWheelRight:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
// warning: mutates the binding
|
||||
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
|
||||
baseHandler := binding.Handler
|
||||
newHandler := func(opts gocui.ViewMouseBindingOpts) error {
|
||||
// we ignore click events on views that aren't popup panels, when a popup panel is focused
|
||||
if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName {
|
||||
return nil
|
||||
}
|
||||
|
||||
return baseHandler(opts)
|
||||
}
|
||||
binding.Handler = newHandler
|
||||
|
||||
return gui.g.SetViewClickBinding(binding)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package gui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
||||
@ -262,8 +261,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||
continue
|
||||
}
|
||||
|
||||
// ignore contexts whose view is owned by another context right now
|
||||
if types.ContextKey(view.Context) != listContext.GetKey() {
|
||||
if !gui.isContextVisible(listContext) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -300,8 +298,6 @@ func (gui *Gui) prepareView(viewName string) (*gocui.View, error) {
|
||||
}
|
||||
|
||||
func (gui *Gui) onInitialViewsCreationForRepo() error {
|
||||
gui.setInitialViewContexts()
|
||||
|
||||
// hide any popup views. This only applies when we've just switched repos
|
||||
for _, viewName := range gui.popupViewNames() {
|
||||
view, err := gui.g.View(viewName)
|
||||
|
@ -3,28 +3,25 @@ package gui
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) getBindings(v *gocui.View) []*types.Binding {
|
||||
func (gui *Gui) getBindings(context types.Context) []*types.Binding {
|
||||
var (
|
||||
bindingsGlobal, bindingsPanel []*types.Binding
|
||||
)
|
||||
|
||||
bindings := append(gui.GetCustomCommandKeybindings(), gui.GetInitialKeybindings()...)
|
||||
bindings, _ := gui.GetInitialKeybindings()
|
||||
bindings = append(gui.GetCustomCommandKeybindings(), bindings...)
|
||||
|
||||
for _, binding := range bindings {
|
||||
if GetKeyDisplay(binding.Key) != "" && binding.Description != "" {
|
||||
switch binding.ViewName {
|
||||
case "":
|
||||
if len(binding.Contexts) == 0 {
|
||||
bindingsGlobal = append(bindingsGlobal, binding)
|
||||
case v.Name():
|
||||
if len(binding.Contexts) == 0 || utils.IncludesString(binding.Contexts, v.Context) {
|
||||
bindingsPanel = append(bindingsPanel, binding)
|
||||
}
|
||||
} else if utils.IncludesString(binding.Contexts, string(context.GetKey())) {
|
||||
bindingsPanel = append(bindingsPanel, binding)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,12 +45,8 @@ func opensMenuStyle(str string) string {
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateOptionsMenu() error {
|
||||
view := gui.g.CurrentView()
|
||||
if view == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bindings := gui.getBindings(view)
|
||||
context := gui.currentContext()
|
||||
bindings := gui.getBindings(context)
|
||||
|
||||
menuItems := make([]*types.MenuItem, len(bindings))
|
||||
|
||||
|
@ -318,7 +318,7 @@ func (gui *Gui) refreshFilesAndSubmodules() error {
|
||||
gui.c.Log.Error(err)
|
||||
}
|
||||
|
||||
if types.ContextKey(gui.Views.Files.Context) == context.FILES_CONTEXT_KEY {
|
||||
if gui.isContextVisible(gui.State.Contexts.Files) {
|
||||
// doing this a little custom (as opposed to using gui.c.PostRefreshUpdate) because we handle selecting the file explicitly below
|
||||
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
|
||||
return err
|
||||
@ -503,7 +503,15 @@ func (gui *Gui) refreshRemotes() error {
|
||||
}
|
||||
}
|
||||
|
||||
return gui.c.PostRefreshUpdate(gui.mustContextForContextKey(types.ContextKey(gui.Views.Branches.Context)))
|
||||
if err := gui.c.PostRefreshUpdate(gui.State.Contexts.Remotes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gui.c.PostRefreshUpdate(gui.State.Contexts.RemoteBranches); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshStashEntries() error {
|
||||
|
@ -1,6 +1,9 @@
|
||||
package types
|
||||
|
||||
import "github.com/jesseduffield/lazygit/pkg/config"
|
||||
import (
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
)
|
||||
|
||||
type ContextKind int
|
||||
|
||||
@ -10,6 +13,8 @@ const (
|
||||
TEMPORARY_POPUP
|
||||
PERSISTENT_POPUP
|
||||
EXTRAS_CONTEXT
|
||||
// only used by the one global context
|
||||
GLOBAL_CONTEXT
|
||||
)
|
||||
|
||||
type ParentContexter interface {
|
||||
@ -31,6 +36,8 @@ type IBaseContext interface {
|
||||
|
||||
GetKeybindings(opts KeybindingsOpts) []*Binding
|
||||
AddKeybindingsFn(KeybindingsFn)
|
||||
GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding
|
||||
AddMouseKeybindingsFn(MouseKeybindingsFn)
|
||||
}
|
||||
|
||||
type Context interface {
|
||||
@ -56,9 +63,11 @@ type KeybindingsOpts struct {
|
||||
}
|
||||
|
||||
type KeybindingsFn func(opts KeybindingsOpts) []*Binding
|
||||
type MouseKeybindingsFn func(opts KeybindingsOpts) []*gocui.ViewMouseBinding
|
||||
|
||||
type HasKeybindings interface {
|
||||
GetKeybindings(opts KeybindingsOpts) []*Binding
|
||||
GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding
|
||||
}
|
||||
|
||||
type IController interface {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package gui
|
||||
|
||||
import "github.com/jesseduffield/gocui"
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
// A window refers to a place on the screen which can hold one or more views.
|
||||
// A view is a box that renders content, and within a window only one view will
|
||||
@ -17,28 +19,21 @@ func (gui *Gui) getViewNameForWindow(window string) string {
|
||||
return viewName
|
||||
}
|
||||
|
||||
func (gui *Gui) getWindowForView(view *gocui.View) string {
|
||||
if view == gui.Views.CommitFiles {
|
||||
return gui.State.Contexts.CommitFiles.GetWindowName()
|
||||
}
|
||||
|
||||
return view.Name()
|
||||
}
|
||||
|
||||
func (gui *Gui) setViewAsActiveForWindow(view *gocui.View) {
|
||||
// for now all we actually care about is the context's view so we're storing that
|
||||
func (gui *Gui) setWindowContext(c types.Context) {
|
||||
if gui.State.WindowViewNameMap == nil {
|
||||
gui.State.WindowViewNameMap = map[string]string{}
|
||||
}
|
||||
|
||||
gui.State.WindowViewNameMap[gui.getWindowForView(view)] = view.Name()
|
||||
gui.State.WindowViewNameMap[c.GetWindowName()] = c.GetViewName()
|
||||
}
|
||||
|
||||
func (gui *Gui) currentWindow() string {
|
||||
return gui.getWindowForView(gui.g.CurrentView())
|
||||
return gui.currentContext().GetWindowName()
|
||||
}
|
||||
|
||||
func (gui *Gui) resetWindowForView(view *gocui.View) {
|
||||
window := gui.getWindowForView(view)
|
||||
func (gui *Gui) resetWindowContext(c types.Context) {
|
||||
// we assume here that the window contains as its default view a view with the same name as the window
|
||||
gui.State.WindowViewNameMap[window] = window
|
||||
windowName := c.GetWindowName()
|
||||
gui.State.WindowViewNameMap[windowName] = windowName
|
||||
}
|
||||
|
133
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
133
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -69,6 +69,30 @@ type tabClickBinding struct {
|
||||
handler tabClickHandler
|
||||
}
|
||||
|
||||
type ViewMouseBinding struct {
|
||||
// the view that is clicked
|
||||
ViewName string
|
||||
|
||||
// the context we are in when the click occurs. Not necessarily the context
|
||||
// of the view we're clicking. If this is blank then it is a global binding.
|
||||
FromContext string
|
||||
|
||||
Handler func(ViewMouseBindingOpts) error
|
||||
|
||||
// must be a mouse key
|
||||
Key Key
|
||||
}
|
||||
|
||||
type ViewMouseBindingOpts struct {
|
||||
// cursor x/y
|
||||
Cx int
|
||||
Cy int
|
||||
|
||||
// origin x/y
|
||||
Ox int
|
||||
Oy int
|
||||
}
|
||||
|
||||
type GuiMutexes struct {
|
||||
// tickingMutex ensures we don't have two loops ticking. The point of 'ticking'
|
||||
// is to refresh the gui rapidly so that loader characters can be animated.
|
||||
@ -110,17 +134,18 @@ type Gui struct {
|
||||
PlayMode PlayMode
|
||||
StartTime time.Time
|
||||
|
||||
tabClickBindings []*tabClickBinding
|
||||
gEvents chan GocuiEvent
|
||||
userEvents chan userEvent
|
||||
views []*View
|
||||
currentView *View
|
||||
managers []Manager
|
||||
keybindings []*keybinding
|
||||
maxX, maxY int
|
||||
outputMode OutputMode
|
||||
stop chan struct{}
|
||||
blacklist []Key
|
||||
tabClickBindings []*tabClickBinding
|
||||
viewMouseBindings []*ViewMouseBinding
|
||||
gEvents chan GocuiEvent
|
||||
userEvents chan userEvent
|
||||
views []*View
|
||||
currentView *View
|
||||
managers []Manager
|
||||
keybindings []*keybinding
|
||||
maxX, maxY int
|
||||
outputMode OutputMode
|
||||
stop chan struct{}
|
||||
blacklist []Key
|
||||
|
||||
// BgColor and FgColor allow to configure the background and foreground
|
||||
// colors of the GUI.
|
||||
@ -162,6 +187,8 @@ type Gui struct {
|
||||
screen tcell.Screen
|
||||
suspendedMutex sync.Mutex
|
||||
suspended bool
|
||||
|
||||
currentContext string
|
||||
}
|
||||
|
||||
// NewGui returns a new Gui object with a given output mode.
|
||||
@ -237,6 +264,10 @@ func (g *Gui) Size() (x, y int) {
|
||||
return g.maxX, g.maxY
|
||||
}
|
||||
|
||||
func (g *Gui) SetCurrentContext(context string) {
|
||||
g.currentContext = context
|
||||
}
|
||||
|
||||
// SetRune writes a rune at the given point, relative to the top-left
|
||||
// corner of the terminal. It checks if the position is valid and applies
|
||||
// the given colors.
|
||||
@ -472,6 +503,7 @@ func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) e
|
||||
func (g *Gui) DeleteAllKeybindings() {
|
||||
g.keybindings = []*keybinding{}
|
||||
g.tabClickBindings = []*tabClickBinding{}
|
||||
g.viewMouseBindings = []*ViewMouseBinding{}
|
||||
}
|
||||
|
||||
// DeleteKeybindings deletes all keybindings of view.
|
||||
@ -495,6 +527,12 @@ func (g *Gui) SetTabClickBinding(viewName string, handler tabClickHandler) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gui) SetViewClickBinding(binding *ViewMouseBinding) error {
|
||||
g.viewMouseBindings = append(g.viewMouseBindings, binding)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlackListKeybinding adds a keybinding to the blacklist
|
||||
func (g *Gui) BlacklistKeybinding(k Key) error {
|
||||
for _, j := range g.blacklist {
|
||||
@ -1098,6 +1136,17 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if ev.Mod == ModNone && IsMouseKey(ev.Key) {
|
||||
opts := ViewMouseBindingOpts{Cx: newCx, Cy: newCy, Ox: v.ox, Oy: v.oy}
|
||||
matched, err := g.execMouseKeybindings(v.Name(), ev, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if matched {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := g.execKeybindings(v, ev); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1106,6 +1155,40 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gui) execMouseKeybindings(viewName string, ev *GocuiEvent, opts ViewMouseBindingOpts) (bool, error) {
|
||||
// first pass looks for ones that match both the view and the current context
|
||||
for _, binding := range g.viewMouseBindings {
|
||||
if binding.ViewName == viewName && binding.FromContext == g.currentContext && ev.Key == binding.Key {
|
||||
return true, binding.Handler(opts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, binding := range g.viewMouseBindings {
|
||||
if binding.ViewName == viewName && ev.Key == binding.Key {
|
||||
return true, binding.Handler(opts)
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func IsMouseKey(key interface{}) bool {
|
||||
switch key {
|
||||
case
|
||||
MouseLeft,
|
||||
MouseRight,
|
||||
MouseMiddle,
|
||||
MouseRelease,
|
||||
MouseWheelUp,
|
||||
MouseWheelDown,
|
||||
MouseWheelLeft,
|
||||
MouseWheelRight:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// execKeybindings executes the keybinding handlers that match the passed view
|
||||
// and event. The value of matched is true if there is a match and no errors.
|
||||
func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error) {
|
||||
@ -1136,10 +1219,10 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error)
|
||||
if !kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) {
|
||||
continue
|
||||
}
|
||||
if kb.matchView(v) {
|
||||
if g.matchView(v, kb) {
|
||||
return g.execKeybinding(v, kb)
|
||||
}
|
||||
if v != nil && kb.matchView(v.ParentView) {
|
||||
if v != nil && g.matchView(v.ParentView, kb) {
|
||||
matchingParentViewKb = kb
|
||||
}
|
||||
if globalKb == nil && kb.viewName == "" && ((v != nil && !v.Editable) || (kb.ch == 0 && kb.key != KeyCtrlU && kb.key != KeyCtrlA && kb.key != KeyCtrlE)) {
|
||||
@ -1340,3 +1423,27 @@ func (g *Gui) Resume() error {
|
||||
|
||||
return g.screen.Resume()
|
||||
}
|
||||
|
||||
// matchView returns if the keybinding matches the current view (and the view's context)
|
||||
func (g *Gui) matchView(v *View, kb *keybinding) bool {
|
||||
// if the user is typing in a field, ignore char keys
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
if v.Editable == true && kb.ch != 0 {
|
||||
return false
|
||||
}
|
||||
if kb.viewName != v.name {
|
||||
return false
|
||||
}
|
||||
// if the keybinding doesn't specify contexts, it applies for all contexts
|
||||
if len(kb.contexts) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, context := range kb.contexts {
|
||||
if context == g.currentContext {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
24
vendor/github.com/jesseduffield/gocui/keybinding.go
generated
vendored
24
vendor/github.com/jesseduffield/gocui/keybinding.go
generated
vendored
@ -124,30 +124,6 @@ func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
|
||||
return kb.key == key && kb.ch == ch && kb.mod == mod
|
||||
}
|
||||
|
||||
// matchView returns if the keybinding matches the current view (and the view's context)
|
||||
func (kb *keybinding) matchView(v *View) bool {
|
||||
// if the user is typing in a field, ignore char keys
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
if v.Editable == true && kb.ch != 0 {
|
||||
return false
|
||||
}
|
||||
if kb.viewName != v.name {
|
||||
return false
|
||||
}
|
||||
// if the keybinding doesn't specify contexts, it applies for all contexts
|
||||
if len(kb.contexts) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, context := range kb.contexts {
|
||||
if context == v.Context {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// translations for strings to keys
|
||||
var translate = map[string]Key{
|
||||
"F1": KeyF1,
|
||||
|
2
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
2
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -149,8 +149,6 @@ type View struct {
|
||||
// ParentView is the view which catches events bubbled up from the given view if there's no matching handler
|
||||
ParentView *View
|
||||
|
||||
Context string // this is for assigning keybindings to a view only in certain contexts
|
||||
|
||||
searcher *searcher
|
||||
|
||||
// KeybindOnEdit should be set to true when you want to execute keybindings even when the view is editable
|
||||
|
Loading…
x
Reference in New Issue
Block a user