2019-11-16 05:00:27 +02:00
package gui
import "github.com/jesseduffield/gocui"
2020-08-17 13:58:30 +02:00
type ListContext struct {
2020-08-16 02:05:45 +02:00
ViewName string
2020-08-16 06:16:28 +02:00
ContextKey string
2020-08-16 02:05:45 +02:00
GetItemsLength func ( ) int
GetSelectedLineIdxPtr func ( ) * int
OnFocus func ( ) error
2020-08-16 05:58:29 +02:00
OnFocusLost func ( ) error
2020-08-16 02:05:45 +02:00
OnItemSelect func ( ) error
OnClickSelectedItem func ( ) error
2020-08-19 10:06:51 +02:00
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
OnRender func ( ) error
Gui * Gui
RendersToMainView bool
Kind int
2019-11-16 05:00:27 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) GetKey ( ) string {
return lc . ContextKey
2020-08-16 05:58:29 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) GetKind ( ) int {
return lc . Kind
2020-08-16 05:58:29 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) GetViewName ( ) string {
return lc . ViewName
2020-08-16 05:58:29 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) HandleFocusLost ( ) error {
if lc . OnFocusLost != nil {
return lc . OnFocusLost ( )
2020-08-16 05:58:29 +02:00
}
return nil
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) HandleFocus ( ) error {
return lc . OnFocus ( )
2020-08-16 05:58:29 +02:00
}
2020-08-19 10:06:51 +02:00
func ( lc * ListContext ) HandleRender ( ) error {
return lc . OnRender ( )
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handlePrevLine ( g * gocui . Gui , v * gocui . View ) error {
return lc . handleLineChange ( - 1 )
2019-11-16 05:00:27 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleNextLine ( g * gocui . Gui , v * gocui . View ) error {
return lc . handleLineChange ( 1 )
2019-11-16 05:00:27 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleLineChange ( change int ) error {
if ! lc . Gui . isPopupPanel ( lc . ViewName ) && lc . Gui . popupPanelFocused ( ) {
2019-11-16 05:00:27 +02:00
return nil
}
2020-08-17 13:58:30 +02:00
view , err := lc . Gui . g . View ( lc . ViewName )
2020-08-16 01:18:57 +02:00
if err != nil {
return err
}
2020-08-17 13:58:30 +02:00
lc . Gui . changeSelectedLine ( lc . GetSelectedLineIdxPtr ( ) , lc . GetItemsLength ( ) , change )
view . FocusPoint ( 0 , * lc . GetSelectedLineIdxPtr ( ) )
2019-11-16 05:00:27 +02:00
2020-08-17 13:58:30 +02:00
if lc . RendersToMainView {
if err := lc . Gui . resetOrigin ( lc . Gui . getMainView ( ) ) ; err != nil {
2019-11-16 05:00:27 +02:00
return err
}
2020-08-17 13:58:30 +02:00
if err := lc . Gui . resetOrigin ( lc . Gui . getSecondaryView ( ) ) ; err != nil {
2020-08-16 01:18:57 +02:00
return err
}
2019-11-16 05:00:27 +02:00
}
2020-01-12 04:39:48 +02:00
2020-08-17 13:58:30 +02:00
if lc . OnItemSelect != nil {
return lc . OnItemSelect ( )
2020-08-16 01:18:57 +02:00
}
return nil
2019-11-16 05:00:27 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleNextPage ( g * gocui . Gui , v * gocui . View ) error {
view , err := lc . Gui . g . View ( lc . ViewName )
2020-03-28 04:44:20 +02:00
if err != nil {
return nil
}
_ , height := view . Size ( )
delta := height - 1
if delta == 0 {
delta = 1
}
2020-08-17 13:58:30 +02:00
return lc . handleLineChange ( delta )
2020-03-28 04:44:20 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleGotoTop ( g * gocui . Gui , v * gocui . View ) error {
return lc . handleLineChange ( - lc . GetItemsLength ( ) )
2020-03-28 04:44:20 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleGotoBottom ( g * gocui . Gui , v * gocui . View ) error {
return lc . handleLineChange ( lc . GetItemsLength ( ) )
2020-03-28 04:44:20 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handlePrevPage ( g * gocui . Gui , v * gocui . View ) error {
view , err := lc . Gui . g . View ( lc . ViewName )
2020-03-28 04:44:20 +02:00
if err != nil {
return nil
}
_ , height := view . Size ( )
delta := height - 1
if delta == 0 {
delta = 1
}
2020-08-17 13:58:30 +02:00
return lc . handleLineChange ( - delta )
2020-03-28 04:44:20 +02:00
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) handleClick ( g * gocui . Gui , v * gocui . View ) error {
if ! lc . Gui . isPopupPanel ( lc . ViewName ) && lc . Gui . popupPanelFocused ( ) {
2019-11-17 08:23:06 +02:00
return nil
}
2020-08-17 13:58:30 +02:00
selectedLineIdxPtr := lc . GetSelectedLineIdxPtr ( )
2019-11-17 08:23:06 +02:00
prevSelectedLineIdx := * selectedLineIdxPtr
newSelectedLineIdx := v . SelectedLineIdx ( )
2020-08-16 01:18:57 +02:00
// we need to focus the view
2020-08-17 13:58:30 +02:00
if err := lc . Gui . switchContext ( lc ) ; err != nil {
2020-08-16 01:18:57 +02:00
return err
}
2020-08-17 13:58:30 +02:00
if newSelectedLineIdx > lc . GetItemsLength ( ) - 1 {
2020-08-16 05:58:29 +02:00
return nil
2019-11-17 08:23:06 +02:00
}
* selectedLineIdxPtr = newSelectedLineIdx
2020-08-17 13:58:30 +02:00
prevViewName := lc . Gui . currentViewName ( )
if prevSelectedLineIdx == newSelectedLineIdx && prevViewName == lc . ViewName && lc . OnClickSelectedItem != nil {
return lc . OnClickSelectedItem ( )
2019-11-17 08:23:06 +02:00
}
2020-08-17 13:58:30 +02:00
if lc . OnItemSelect != nil {
return lc . OnItemSelect ( )
2020-08-16 01:18:57 +02:00
}
return nil
}
2020-08-17 13:58:30 +02:00
func ( lc * ListContext ) onSearchSelect ( selectedLineIdx int ) error {
* lc . GetSelectedLineIdxPtr ( ) = selectedLineIdx
if lc . OnItemSelect != nil {
return lc . OnItemSelect ( )
2020-08-16 01:18:57 +02:00
}
return nil
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) menuListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "menu" ,
2020-08-16 06:16:28 +02:00
ContextKey : "menu" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return gui . getMenuView ( ) . LinesHeight ( ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Menu . SelectedLine } ,
OnFocus : gui . handleMenuSelect ,
OnItemSelect : gui . handleMenuSelect ,
2020-08-19 10:41:57 +02:00
// rendering the menu happens on creation
OnRender : func ( ) error { return nil } ,
2020-08-16 01:18:57 +02:00
// need to add a layer of indirection here because the callback changes during runtime
2020-08-16 02:05:45 +02:00
OnClickSelectedItem : func ( ) error { return gui . State . Panels . Menu . OnPress ( gui . g , nil ) } ,
Gui : gui ,
RendersToMainView : false ,
2020-08-16 05:58:29 +02:00
Kind : PERSISTENT_POPUP ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) filesListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "files" ,
2020-08-16 06:16:28 +02:00
ContextKey : "files" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . Files ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Files . SelectedLine } ,
OnFocus : gui . focusAndSelectFile ,
OnItemSelect : gui . focusAndSelectFile ,
OnClickSelectedItem : gui . handleFilePress ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderFiles ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : false ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) branchesListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "branches" ,
2020-08-16 06:16:28 +02:00
ContextKey : "local-branches" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . Branches ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Branches . SelectedLine } ,
OnFocus : gui . handleBranchSelect ,
OnItemSelect : gui . handleBranchSelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderLocalBranchesWithSelection ,
Gui : gui ,
RendersToMainView : true ,
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) remotesListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "branches" ,
2020-08-16 06:16:28 +02:00
ContextKey : "remotes" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . Remotes ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Remotes . SelectedLine } ,
OnFocus : gui . renderRemotesWithSelection ,
OnItemSelect : gui . handleRemoteSelect ,
OnClickSelectedItem : gui . handleRemoteEnter ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderRemotesWithSelection ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) remoteBranchesListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "branches" ,
2020-08-16 06:16:28 +02:00
ContextKey : "remote-branches" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . RemoteBranches ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . RemoteBranches . SelectedLine } ,
OnFocus : gui . handleRemoteBranchSelect ,
OnItemSelect : gui . handleRemoteBranchSelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderRemoteBranchesWithSelection ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) tagsListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "branches" ,
2020-08-16 06:16:28 +02:00
ContextKey : "tags" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . Tags ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Tags . SelectedLine } ,
OnFocus : gui . handleTagSelect ,
OnItemSelect : gui . handleTagSelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderTagsWithSelection ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) branchCommitsListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "commits" ,
2020-08-16 06:16:28 +02:00
ContextKey : "branch-commits" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . Commits ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Commits . SelectedLine } ,
OnFocus : gui . handleCommitSelect ,
OnItemSelect : gui . handleCommitSelect ,
OnClickSelectedItem : gui . handleSwitchToCommitFilesPanel ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderBranchCommitsWithSelection ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) reflogCommitsListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "commits" ,
2020-08-16 06:16:28 +02:00
ContextKey : "reflog-commits" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . FilteredReflogCommits ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . ReflogCommits . SelectedLine } ,
OnFocus : gui . handleReflogCommitSelect ,
OnItemSelect : gui . handleReflogCommitSelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderReflogCommitsWithSelection ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) stashListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "stash" ,
2020-08-16 06:16:28 +02:00
ContextKey : "stash" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . StashEntries ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . Stash . SelectedLine } ,
OnFocus : gui . handleStashEntrySelect ,
OnItemSelect : gui . handleStashEntrySelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderStash ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) commitFilesListContext ( ) * ListContext {
return & ListContext {
2020-08-16 02:05:45 +02:00
ViewName : "commitFiles" ,
2020-08-16 06:16:28 +02:00
ContextKey : "commitFiles" ,
2020-08-16 02:05:45 +02:00
GetItemsLength : func ( ) int { return len ( gui . State . CommitFiles ) } ,
GetSelectedLineIdxPtr : func ( ) * int { return & gui . State . Panels . CommitFiles . SelectedLine } ,
OnFocus : gui . handleCommitFileSelect ,
OnItemSelect : gui . handleCommitFileSelect ,
2020-08-19 10:41:57 +02:00
OnRender : gui . renderCommitFiles ,
2020-08-16 02:05:45 +02:00
Gui : gui ,
RendersToMainView : true ,
2020-08-16 05:58:29 +02:00
Kind : SIDE_CONTEXT ,
2020-08-16 01:18:57 +02:00
}
2019-11-17 08:23:06 +02:00
}
2020-08-17 13:58:30 +02:00
func ( gui * Gui ) getListContexts ( ) [ ] * ListContext {
return [ ] * ListContext {
gui . menuListContext ( ) ,
gui . filesListContext ( ) ,
gui . branchesListContext ( ) ,
gui . remotesListContext ( ) ,
gui . remoteBranchesListContext ( ) ,
gui . tagsListContext ( ) ,
gui . branchCommitsListContext ( ) ,
gui . reflogCommitsListContext ( ) ,
gui . stashListContext ( ) ,
gui . commitFilesListContext ( ) ,
2019-11-16 05:00:27 +02:00
}
}
2020-08-17 14:05:15 +02:00
func ( gui * Gui ) getListContextKeyBindings ( ) [ ] * Binding {
bindings := make ( [ ] * Binding , 0 )
for _ , listContext := range gui . getListContexts ( ) {
bindings = append ( bindings , [ ] * Binding {
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.prevItem-alt" ) , Modifier : gocui . ModNone , Handler : listContext . handlePrevLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.prevItem" ) , Modifier : gocui . ModNone , Handler : listContext . handlePrevLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gocui . MouseWheelUp , Modifier : gocui . ModNone , Handler : listContext . handlePrevLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.nextItem-alt" ) , Modifier : gocui . ModNone , Handler : listContext . handleNextLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.nextItem" ) , Modifier : gocui . ModNone , Handler : listContext . handleNextLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.prevPage" ) , Modifier : gocui . ModNone , Handler : listContext . handlePrevPage , Description : gui . Tr . SLocalize ( "prevPage" ) } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.nextPage" ) , Modifier : gocui . ModNone , Handler : listContext . handleNextPage , Description : gui . Tr . SLocalize ( "nextPage" ) } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gui . getKey ( "universal.gotoTop" ) , Modifier : gocui . ModNone , Handler : listContext . handleGotoTop , Description : gui . Tr . SLocalize ( "gotoTop" ) } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gocui . MouseWheelDown , Modifier : gocui . ModNone , Handler : listContext . handleNextLine } ,
{ ViewName : listContext . ViewName , Contexts : [ ] string { listContext . ContextKey } , Key : gocui . MouseLeft , Modifier : gocui . ModNone , Handler : listContext . handleClick } ,
} ... )
// the commits panel needs to lazyload things so it has a couple of its own handlers
openSearchHandler := gui . handleOpenSearch
gotoBottomHandler := listContext . handleGotoBottom
if listContext . ViewName == "commits" {
openSearchHandler = gui . handleOpenSearchForCommitsPanel
gotoBottomHandler = gui . handleGotoBottomForCommitsPanel
}
bindings = append ( bindings , [ ] * Binding {
{
ViewName : listContext . ViewName ,
Contexts : [ ] string { listContext . ContextKey } ,
Key : gui . getKey ( "universal.startSearch" ) ,
Handler : openSearchHandler ,
Description : gui . Tr . SLocalize ( "startSearch" ) ,
} ,
{
ViewName : listContext . ViewName ,
Contexts : [ ] string { listContext . ContextKey } ,
Key : gui . getKey ( "universal.gotoBottom" ) ,
Handler : gotoBottomHandler ,
Description : gui . Tr . SLocalize ( "gotoBottom" ) ,
} ,
} ... )
}
return bindings
}