2022-08-12 09:19:39 +10:00
package components
2022-08-09 20:27:44 +10:00
import (
"fmt"
"strings"
"time"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
)
2022-08-11 21:04:10 +10:00
type Input struct {
2022-08-13 12:56:04 +10:00
gui integrationTypes . GuiDriver
2022-08-09 20:27:44 +10:00
keys config . KeybindingConfig
2022-08-09 21:27:12 +10:00
assert * Assert
2022-08-09 20:27:44 +10:00
pushKeyDelay int
}
2022-08-13 12:56:04 +10:00
func NewInput ( gui integrationTypes . GuiDriver , keys config . KeybindingConfig , assert * Assert , pushKeyDelay int ) * Input {
2022-08-11 21:04:10 +10:00
return & Input {
2022-08-09 20:27:44 +10:00
gui : gui ,
keys : keys ,
assert : assert ,
pushKeyDelay : pushKeyDelay ,
}
}
2022-08-09 21:27:12 +10:00
// key is something like 'w' or '<space>'. It's best not to pass a direct value,
// but instead to go through the default user config to get a more meaningful key name
2022-12-24 17:48:57 +11:00
func ( self * Input ) Press ( keyStrs ... string ) {
2022-08-09 20:27:44 +10:00
for _ , keyStr := range keyStrs {
2022-12-24 17:48:57 +11:00
self . press ( keyStr )
2022-08-09 20:27:44 +10:00
}
}
2022-12-24 17:48:57 +11:00
func ( self * Input ) press ( keyStr string ) {
2022-08-09 20:27:44 +10:00
self . Wait ( self . pushKeyDelay )
self . gui . PressKey ( keyStr )
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) SwitchToStatusWindow ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . JumpToBlock [ 0 ] )
2022-09-09 21:11:05 -07:00
self . assert . CurrentWindowName ( "status" )
2022-08-09 20:27:44 +10:00
}
2022-12-26 16:49:54 +11:00
// switch to status window and assert that the status view is on top
func ( self * Input ) SwitchToStatusView ( ) {
self . SwitchToStatusWindow ( )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . Name ( "status" )
2022-12-26 16:49:54 +11:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) SwitchToFilesWindow ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . JumpToBlock [ 1 ] )
2022-09-09 21:11:05 -07:00
self . assert . CurrentWindowName ( "files" )
2022-08-09 20:27:44 +10:00
}
2022-12-26 16:49:54 +11:00
// switch to files window and assert that the files view is on top
func ( self * Input ) SwitchToFilesView ( ) {
self . SwitchToFilesWindow ( )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . Name ( "files" )
2022-12-26 16:49:54 +11:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) SwitchToBranchesWindow ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . JumpToBlock [ 2 ] )
2022-09-09 21:11:05 -07:00
self . assert . CurrentWindowName ( "localBranches" )
2022-08-09 20:27:44 +10:00
}
2022-12-26 16:49:54 +11:00
// switch to branches window and assert that the branches view is on top
func ( self * Input ) SwitchToBranchesView ( ) {
self . SwitchToBranchesWindow ( )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . Name ( "localBranches" )
2022-12-26 16:49:54 +11:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) SwitchToCommitsWindow ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . JumpToBlock [ 3 ] )
2022-09-09 21:11:05 -07:00
self . assert . CurrentWindowName ( "commits" )
2022-08-09 20:27:44 +10:00
}
2022-12-26 16:49:54 +11:00
// switch to commits window and assert that the commits view is on top
func ( self * Input ) SwitchToCommitsView ( ) {
self . SwitchToCommitsWindow ( )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . Name ( "commits" )
2022-12-26 16:49:54 +11:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) SwitchToStashWindow ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . JumpToBlock [ 4 ] )
2022-09-09 21:11:05 -07:00
self . assert . CurrentWindowName ( "stash" )
2022-08-09 20:27:44 +10:00
}
2022-12-26 16:49:54 +11:00
// switch to stash window and assert that the stash view is on top
func ( self * Input ) SwitchToStashView ( ) {
self . SwitchToStashWindow ( )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . Name ( "stash" )
2022-12-26 16:49:54 +11:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) Type ( content string ) {
2022-08-09 20:27:44 +10:00
for _ , char := range content {
2022-12-24 17:48:57 +11:00
self . press ( string ( char ) )
2022-08-09 20:27:44 +10:00
}
}
2022-08-09 21:27:12 +10:00
// i.e. pressing enter
2022-08-11 21:04:10 +10:00
func ( self * Input ) Confirm ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . Confirm )
2022-09-17 11:58:24 -07:00
}
2022-09-16 22:15:02 -07:00
// i.e. same as Confirm
func ( self * Input ) Enter ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . Confirm )
2022-09-16 22:15:02 -07:00
}
2022-08-09 21:27:12 +10:00
// i.e. pressing escape
2022-08-11 21:04:10 +10:00
func ( self * Input ) Cancel ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . Return )
2022-08-09 20:27:44 +10:00
}
2022-08-09 21:27:12 +10:00
// i.e. pressing space
2022-08-14 20:47:09 +10:00
func ( self * Input ) PrimaryAction ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . Select )
2022-08-09 20:27:44 +10:00
}
2022-08-09 21:27:12 +10:00
// i.e. pressing down arrow
2022-08-11 21:04:10 +10:00
func ( self * Input ) NextItem ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . NextItem )
2022-08-09 20:27:44 +10:00
}
2022-08-09 21:27:12 +10:00
// i.e. pressing up arrow
2022-08-11 21:04:10 +10:00
func ( self * Input ) PreviousItem ( ) {
2022-12-24 17:48:57 +11:00
self . press ( self . keys . Universal . PrevItem )
2022-08-09 20:27:44 +10:00
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) ContinueMerge ( ) {
2022-12-24 17:48:57 +11:00
self . Press ( self . keys . Universal . CreateRebaseOptionsMenu )
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . SelectedLine ( Contains ( "continue" ) )
2022-08-09 20:27:44 +10:00
self . Confirm ( )
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) ContinueRebase ( ) {
2022-08-09 20:27:44 +10:00
self . ContinueMerge ( )
}
2022-08-09 21:27:12 +10:00
// for when you want to allow lazygit to process something before continuing
2022-08-11 21:04:10 +10:00
func ( self * Input ) Wait ( milliseconds int ) {
2022-08-09 20:27:44 +10:00
time . Sleep ( time . Duration ( milliseconds ) * time . Millisecond )
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) LogUI ( message string ) {
2022-08-09 20:27:44 +10:00
self . gui . LogUI ( message )
}
2022-08-11 21:04:10 +10:00
func ( self * Input ) Log ( message string ) {
2022-08-09 20:27:44 +10:00
self . gui . LogUI ( message )
}
2022-08-09 21:27:12 +10:00
// this will look for a list item in the current panel and if it finds it, it will
// enter the keypresses required to navigate to it.
// The test will fail if:
2022-08-12 09:24:39 +10:00
// - the user is not in a list item
// - no list item is found containing the given text
// - multiple list items are found containing the given text in the initial page of items
2022-08-09 21:27:12 +10:00
//
2022-08-09 20:27:44 +10:00
// NOTE: this currently assumes that ViewBufferLines returns all the lines that can be accessed.
// If this changes in future, we'll need to update this code to first attempt to find the item
// in the current page and failing that, jump to the top of the view and iterate through all of it,
// looking for the item.
2022-12-24 17:48:57 +11:00
func ( self * Input ) NavigateToListItem ( matcher * matcher ) {
2022-08-09 20:27:44 +10:00
self . assert . InListContext ( )
currentContext := self . gui . CurrentContext ( ) . ( types . IListContext )
view := currentContext . GetView ( )
2022-09-09 21:11:05 -07:00
var matchIndex int
self . assert . assertWithRetries ( func ( ) ( bool , string ) {
matchIndex = - 1
2022-12-24 17:48:57 +11:00
var matches [ ] string
2022-12-26 17:15:33 +11:00
lines := view . ViewBufferLines ( )
2022-09-09 21:11:05 -07:00
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
2022-12-26 17:15:33 +11:00
for i , line := range lines {
2022-12-24 17:48:57 +11:00
ok , _ := matcher . test ( line )
if ok {
matches = append ( matches , line )
2022-09-09 21:11:05 -07:00
matchIndex = i
}
2022-08-09 20:27:44 +10:00
}
2022-12-24 17:48:57 +11:00
if len ( matches ) > 1 {
2022-12-26 17:15:33 +11:00
return false , fmt . Sprintf ( "Found %d matches for `%s`, expected only a single match. Matching lines:\n%s" , len ( matches ) , matcher . name ( ) , strings . Join ( matches , "\n" ) )
2022-12-24 17:48:57 +11:00
} else if len ( matches ) == 0 {
2022-12-26 17:15:33 +11:00
return false , fmt . Sprintf ( "Could not find item matching: %s. Lines:\n%s" , matcher . name ( ) , strings . Join ( lines , "\n" ) )
2022-09-09 21:11:05 -07:00
} else {
return true , ""
}
} )
selectedLineIdx := view . SelectedLineIdx ( )
if selectedLineIdx == matchIndex {
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . SelectedLine ( matcher )
2022-09-09 21:11:05 -07:00
return
2022-08-09 20:27:44 +10:00
}
2022-09-09 21:11:05 -07:00
if selectedLineIdx < matchIndex {
for i := selectedLineIdx ; i < matchIndex ; i ++ {
self . NextItem ( )
2022-08-09 20:27:44 +10:00
}
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . SelectedLine ( matcher )
2022-09-09 21:11:05 -07:00
return
} else {
for i := selectedLineIdx ; i > matchIndex ; i -- {
self . PreviousItem ( )
2022-08-09 20:27:44 +10:00
}
2022-12-27 15:07:11 +11:00
self . assert . Views ( ) . Current ( ) . SelectedLine ( matcher )
2022-09-09 21:11:05 -07:00
return
2022-08-09 20:27:44 +10:00
}
}
2022-12-24 17:48:57 +11:00
2022-12-27 11:21:44 +11:00
func ( self * Input ) Confirmation ( ) * ConfirmationAsserter {
2022-12-24 17:48:57 +11:00
self . assert . InConfirm ( )
2022-12-27 10:50:00 +11:00
return & ConfirmationAsserter { assert : self . assert , input : self }
2022-12-24 17:48:57 +11:00
}
2022-12-27 11:21:44 +11:00
func ( self * Input ) Prompt ( ) * PromptAsserter {
2022-12-24 17:48:57 +11:00
self . assert . InPrompt ( )
2022-12-27 11:21:44 +11:00
return & PromptAsserter { assert : self . assert , input : self }
2022-12-24 17:48:57 +11:00
}
2022-12-27 11:34:41 +11:00
func ( self * Input ) Alert ( ) * AlertAsserter {
self . assert . InAlert ( )
return & AlertAsserter { assert : self . assert , input : self }
2022-12-24 17:48:57 +11:00
}
2022-12-27 11:34:41 +11:00
func ( self * Input ) Menu ( ) * MenuAsserter {
2022-12-24 17:48:57 +11:00
self . assert . InMenu ( )
2022-12-27 11:34:41 +11:00
return & MenuAsserter { assert : self . assert , input : self }
2022-12-24 17:48:57 +11:00
}
2022-12-27 11:55:30 +11:00
func ( self * Input ) CommitMessagePanel ( ) * CommitMessagePanelAsserter {
self . assert . InCommitMessagePanel ( )
return & CommitMessagePanelAsserter { assert : self . assert , input : self }
}