2018-08-14 11:05:26 +02:00
package gui
import (
// "io"
// "io/ioutil"
// "strings"
2018-09-12 10:23:25 +02:00
"fmt"
2018-08-14 11:05:26 +02:00
"strings"
2019-03-18 12:19:07 +02:00
"github.com/fatih/color"
2018-08-14 11:05:26 +02:00
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
2018-09-17 13:02:30 +02:00
"github.com/jesseduffield/lazygit/pkg/utils"
2018-08-14 11:05:26 +02:00
)
2018-12-06 13:18:17 +02:00
// list panel functions
func ( gui * Gui ) getSelectedFile ( g * gocui . Gui ) ( * commands . File , error ) {
selectedLine := gui . State . Panels . Files . SelectedLine
if selectedLine == - 1 {
return & commands . File { } , gui . Errors . ErrNoFiles
}
return gui . State . Files [ selectedLine ] , nil
}
2019-11-10 07:20:35 +02:00
func ( gui * Gui ) handleFilesClick ( g * gocui . Gui , v * gocui . View ) error {
2019-02-25 13:11:35 +02:00
if gui . popupPanelFocused ( ) {
return nil
}
2019-11-10 07:20:35 +02:00
prevSelectedLineIdx := gui . State . Panels . Files . SelectedLine
newSelectedLineIdx := v . SelectedLineIdx ( )
2019-02-25 13:11:35 +02:00
2019-11-10 07:20:35 +02:00
if newSelectedLineIdx > len ( gui . State . Files ) - 1 {
2019-11-16 05:00:27 +02:00
return gui . selectFile ( false )
2019-02-25 13:11:35 +02:00
}
2019-11-10 07:20:35 +02:00
gui . State . Panels . Files . SelectedLine = newSelectedLineIdx
2019-02-25 13:11:35 +02:00
2019-11-10 07:20:35 +02:00
if prevSelectedLineIdx == newSelectedLineIdx && gui . currentViewName ( ) == v . Name ( ) {
2019-02-25 13:11:35 +02:00
return gui . handleFilePress ( gui . g , v )
} else {
2019-11-16 05:00:27 +02:00
return gui . selectFile ( true )
2019-02-25 13:11:35 +02:00
}
}
2019-11-16 05:00:27 +02:00
func ( gui * Gui ) handleFileSelect ( g * gocui . Gui , v * gocui . View ) error {
return gui . selectFile ( false )
}
func ( gui * Gui ) selectFile ( alreadySelected bool ) error {
if _ , err := gui . g . SetCurrentView ( "files" ) ; err != nil {
2019-03-02 04:22:02 +02:00
return err
}
2019-11-16 05:00:27 +02:00
file , err := gui . getSelectedFile ( gui . g )
2018-12-06 13:18:17 +02:00
if err != nil {
if err != gui . Errors . ErrNoFiles {
return err
}
2019-11-16 05:00:27 +02:00
return gui . renderString ( gui . g , "main" , gui . Tr . SLocalize ( "NoChangedFiles" ) )
2018-12-06 13:18:17 +02:00
}
2019-11-16 05:00:27 +02:00
if err := gui . focusPoint ( 0 , gui . State . Panels . Files . SelectedLine , len ( gui . State . Files ) , gui . getFilesView ( ) ) ; err != nil {
2018-12-06 13:18:17 +02:00
return err
}
2019-03-03 06:55:19 +02:00
if file . HasInlineMergeConflicts {
2019-11-12 12:24:01 +02:00
gui . getMainView ( ) . Title = gui . Tr . SLocalize ( "MergeConflictsTitle" )
gui . State . SplitMainPanel = false
2019-02-16 03:07:27 +02:00
return gui . refreshMergePanel ( )
2018-12-08 07:54:54 +02:00
}
2019-10-30 11:23:25 +02:00
content := gui . GitCommand . Diff ( file , false , false )
contentCached := gui . GitCommand . Diff ( file , false , true )
leftContent := content
if file . HasStagedChanges && file . HasUnstagedChanges {
gui . State . SplitMainPanel = true
2019-11-10 07:20:35 +02:00
gui . getMainView ( ) . Title = gui . Tr . SLocalize ( "UnstagedChanges" )
gui . getSecondaryView ( ) . Title = gui . Tr . SLocalize ( "StagedChanges" )
2019-10-30 11:23:25 +02:00
} else {
gui . State . SplitMainPanel = false
if file . HasUnstagedChanges {
leftContent = content
2019-11-10 07:20:35 +02:00
gui . getMainView ( ) . Title = gui . Tr . SLocalize ( "UnstagedChanges" )
2019-10-30 11:23:25 +02:00
} else {
leftContent = contentCached
2019-11-10 07:20:35 +02:00
gui . getMainView ( ) . Title = gui . Tr . SLocalize ( "StagedChanges" )
2019-10-30 11:23:25 +02:00
}
}
2019-01-15 11:12:31 +02:00
if alreadySelected {
2019-11-16 05:00:27 +02:00
gui . g . Update ( func ( * gocui . Gui ) error {
2019-10-30 11:23:25 +02:00
if err := gui . setViewContent ( gui . g , gui . getSecondaryView ( ) , contentCached ) ; err != nil {
return err
}
return gui . setViewContent ( gui . g , gui . getMainView ( ) , leftContent )
2019-01-15 11:12:31 +02:00
} )
return nil
}
2019-11-16 05:00:27 +02:00
if err := gui . renderString ( gui . g , "secondary" , contentCached ) ; err != nil {
2019-10-30 11:23:25 +02:00
return err
}
2019-11-16 05:00:27 +02:00
return gui . renderString ( gui . g , "main" , leftContent )
2018-12-06 13:18:17 +02:00
}
2018-12-08 07:54:54 +02:00
func ( gui * Gui ) refreshFiles ( ) error {
2019-11-12 13:19:20 +02:00
gui . State . RefreshingFilesMutex . Lock ( )
gui . State . IsRefreshingFiles = true
defer func ( ) {
gui . State . IsRefreshingFiles = false
gui . State . RefreshingFilesMutex . Unlock ( )
} ( )
2019-01-15 11:12:31 +02:00
selectedFile , _ := gui . getSelectedFile ( gui . g )
2018-12-08 07:54:54 +02:00
filesView := gui . getFilesView ( )
2019-05-06 14:29:35 +02:00
if filesView == nil {
// if the filesView hasn't been instantiated yet we just return
return nil
}
2019-03-02 04:22:02 +02:00
if err := gui . refreshStateFiles ( ) ; err != nil {
return err
}
2018-12-06 13:18:17 +02:00
gui . g . Update ( func ( g * gocui . Gui ) error {
filesView . Clear ( )
2019-02-16 06:17:44 +02:00
isFocused := gui . g . CurrentView ( ) . Name ( ) == "files"
list , err := utils . RenderList ( gui . State . Files , isFocused )
2018-12-06 13:18:17 +02:00
if err != nil {
return err
}
fmt . Fprint ( filesView , list )
2019-11-12 13:19:20 +02:00
if g . CurrentView ( ) == filesView || ( g . CurrentView ( ) == gui . getMainView ( ) && gui . State . Context == "merging" ) {
2019-01-15 11:12:31 +02:00
newSelectedFile , _ := gui . getSelectedFile ( gui . g )
alreadySelected := newSelectedFile . Name == selectedFile . Name
2019-11-16 05:00:27 +02:00
return gui . selectFile ( alreadySelected )
2018-12-06 13:18:17 +02:00
}
return nil
} )
return nil
}
// specific functions
2018-09-17 13:02:30 +02:00
func ( gui * Gui ) stagedFiles ( ) [ ] * commands . File {
2018-08-14 11:05:26 +02:00
files := gui . State . Files
2018-09-17 13:02:30 +02:00
result := make ( [ ] * commands . File , 0 )
2018-08-14 11:05:26 +02:00
for _ , file := range files {
if file . HasStagedChanges {
result = append ( result , file )
}
}
return result
}
2018-09-17 13:02:30 +02:00
func ( gui * Gui ) trackedFiles ( ) [ ] * commands . File {
2018-08-14 11:05:26 +02:00
files := gui . State . Files
2018-09-17 13:02:30 +02:00
result := make ( [ ] * commands . File , 0 )
2018-08-14 11:05:26 +02:00
for _ , file := range files {
if file . Tracked {
result = append ( result , file )
}
}
return result
}
func ( gui * Gui ) stageSelectedFile ( g * gocui . Gui ) error {
file , err := gui . getSelectedFile ( g )
if err != nil {
return err
}
return gui . GitCommand . StageFile ( file . Name )
}
2018-12-05 13:30:10 +02:00
func ( gui * Gui ) handleEnterFile ( g * gocui . Gui , v * gocui . View ) error {
2019-11-10 07:20:35 +02:00
return gui . enterFile ( false , - 1 )
}
func ( gui * Gui ) enterFile ( forceSecondaryFocused bool , selectedLineIdx int ) error {
file , err := gui . getSelectedFile ( gui . g )
2018-12-02 10:57:01 +02:00
if err != nil {
if err != gui . Errors . ErrNoFiles {
return err
}
return nil
}
2019-03-03 06:55:19 +02:00
if file . HasInlineMergeConflicts {
2019-11-10 07:20:35 +02:00
return gui . handleSwitchToMerge ( gui . g , gui . getFilesView ( ) )
2018-12-05 13:30:10 +02:00
}
2019-10-30 11:23:25 +02:00
if file . HasMergeConflicts {
2019-11-10 07:20:35 +02:00
return gui . createErrorPanel ( gui . g , gui . Tr . SLocalize ( "FileStagingRequirements" ) )
2018-12-02 10:57:01 +02:00
}
2019-11-16 03:41:04 +02:00
if err := gui . changeMainViewsContext ( "staging" ) ; err != nil {
2019-11-10 07:20:35 +02:00
return err
}
if err := gui . switchFocus ( gui . g , gui . getFilesView ( ) , gui . getMainView ( ) ) ; err != nil {
2018-12-05 10:33:46 +02:00
return err
}
2019-11-10 07:20:35 +02:00
return gui . refreshStagingPanel ( forceSecondaryFocused , selectedLineIdx )
2018-12-02 10:57:01 +02:00
}
2018-08-14 11:05:26 +02:00
func ( gui * Gui ) handleFilePress ( g * gocui . Gui , v * gocui . View ) error {
file , err := gui . getSelectedFile ( g )
if err != nil {
2018-08-14 15:47:14 +02:00
if err == gui . Errors . ErrNoFiles {
2018-08-14 11:05:26 +02:00
return nil
}
return err
}
2019-03-03 06:55:19 +02:00
if file . HasInlineMergeConflicts {
2018-08-14 11:05:26 +02:00
return gui . handleSwitchToMerge ( g , v )
}
if file . HasUnstagedChanges {
gui . GitCommand . StageFile ( file . Name )
} else {
gui . GitCommand . UnStageFile ( file . Name , file . Tracked )
}
2018-12-08 07:54:54 +02:00
if err := gui . refreshFiles ( ) ; err != nil {
2018-08-14 11:05:26 +02:00
return err
}
2019-11-16 05:00:27 +02:00
return gui . selectFile ( true )
2018-08-14 11:05:26 +02:00
}
2018-08-25 00:51:47 +02:00
func ( gui * Gui ) allFilesStaged ( ) bool {
for _ , file := range gui . State . Files {
if file . HasUnstagedChanges {
return false
}
}
return true
}
func ( gui * Gui ) handleStageAll ( g * gocui . Gui , v * gocui . View ) error {
var err error
if gui . allFilesStaged ( ) {
err = gui . GitCommand . UnstageAll ( )
} else {
err = gui . GitCommand . StageAll ( )
}
if err != nil {
_ = gui . createErrorPanel ( g , err . Error ( ) )
}
2018-12-08 07:54:54 +02:00
if err := gui . refreshFiles ( ) ; err != nil {
2018-08-25 00:51:47 +02:00
return err
}
2019-11-16 05:00:27 +02:00
return gui . handleFileSelect ( gui . g , v )
2018-08-25 00:51:47 +02:00
}
2018-08-14 11:05:26 +02:00
func ( gui * Gui ) handleIgnoreFile ( g * gocui . Gui , v * gocui . View ) error {
file , err := gui . getSelectedFile ( g )
if err != nil {
return gui . createErrorPanel ( g , err . Error ( ) )
}
if file . Tracked {
2018-08-16 07:16:32 +02:00
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "CantIgnoreTrackFiles" ) )
2018-08-14 11:05:26 +02:00
}
2018-08-19 12:41:04 +02:00
if err := gui . GitCommand . Ignore ( file . Name ) ; err != nil {
return gui . createErrorPanel ( g , err . Error ( ) )
}
2018-12-08 07:54:54 +02:00
return gui . refreshFiles ( )
2018-08-14 11:05:26 +02:00
}
2019-04-13 05:56:31 +02:00
func ( gui * Gui ) handleWIPCommitPress ( g * gocui . Gui , filesView * gocui . View ) error {
skipHookPreifx := gui . Config . GetUserConfig ( ) . GetString ( "git.skipHookPrefix" )
if skipHookPreifx == "" {
return gui . createErrorPanel ( gui . g , gui . Tr . SLocalize ( "SkipHookPrefixNotConfigured" ) )
}
if err := gui . renderString ( g , "commitMessage" , skipHookPreifx ) ; err != nil {
return err
}
if err := gui . getCommitMessageView ( ) . SetCursor ( len ( skipHookPreifx ) , 0 ) ; err != nil {
return err
}
return gui . handleCommitPress ( g , filesView )
}
2018-08-14 11:05:26 +02:00
func ( gui * Gui ) handleCommitPress ( g * gocui . Gui , filesView * gocui . View ) error {
2018-12-05 13:30:10 +02:00
if len ( gui . stagedFiles ( ) ) == 0 && gui . State . WorkingTreeState == "normal" {
2018-08-16 07:16:32 +02:00
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "NoStagedFilesToCommit" ) )
2018-08-14 11:05:26 +02:00
}
2018-12-08 07:54:54 +02:00
commitMessageView := gui . getCommitMessageView ( )
2018-09-12 15:20:35 +02:00
g . Update ( func ( g * gocui . Gui ) error {
g . SetViewOnTop ( "commitMessage" )
gui . switchFocus ( g , filesView , commitMessageView )
gui . RenderCommitLength ( )
return nil
} )
return nil
}
func ( gui * Gui ) handleAmendCommitPress ( g * gocui . Gui , filesView * gocui . View ) error {
2018-12-05 13:30:10 +02:00
if len ( gui . stagedFiles ( ) ) == 0 && gui . State . WorkingTreeState == "normal" {
2018-09-12 15:20:35 +02:00
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "NoStagedFilesToCommit" ) )
}
2018-10-08 21:19:45 +02:00
if len ( gui . State . Commits ) == 0 {
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "NoCommitToAmend" ) )
}
2019-02-24 00:42:24 +02:00
title := strings . Title ( gui . Tr . SLocalize ( "AmendLastCommit" ) )
question := gui . Tr . SLocalize ( "SureToAmend" )
2019-11-05 06:19:43 +02:00
return gui . createConfirmationPanel ( g , filesView , true , title , question , func ( g * gocui . Gui , v * gocui . View ) error {
2019-03-23 03:16:55 +02:00
ok , err := gui . runSyncOrAsyncCommand ( gui . GitCommand . AmendHead ( ) )
if err != nil {
2019-02-24 00:42:24 +02:00
return err
2018-09-25 22:11:51 +02:00
}
2019-03-23 03:16:55 +02:00
if ! ok {
return nil
}
2018-09-12 15:20:35 +02:00
2018-10-06 07:40:12 +02:00
return gui . refreshSidePanels ( g )
2018-09-25 22:11:51 +02:00
} , nil )
2018-08-14 11:05:26 +02:00
}
// handleCommitEditorPress - handle when the user wants to commit changes via
// their editor rather than via the popup panel
func ( gui * Gui ) handleCommitEditorPress ( g * gocui . Gui , filesView * gocui . View ) error {
2018-12-05 13:30:10 +02:00
if len ( gui . stagedFiles ( ) ) == 0 && gui . State . WorkingTreeState == "normal" {
2018-08-16 07:16:32 +02:00
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "NoStagedFilesToCommit" ) )
2018-08-14 11:05:26 +02:00
}
gui . PrepareSubProcess ( g , "git" , "commit" )
return nil
}
// PrepareSubProcess - prepare a subprocess for execution and tell the gui to switch to it
2018-08-21 22:33:25 +02:00
func ( gui * Gui ) PrepareSubProcess ( g * gocui . Gui , commands ... string ) {
gui . SubProcess = gui . GitCommand . PrepareCommitSubProcess ( )
2018-08-14 11:05:26 +02:00
g . Update ( func ( g * gocui . Gui ) error {
2018-08-16 11:31:03 +02:00
return gui . Errors . ErrSubProcess
2018-08-14 11:05:26 +02:00
} )
}
2018-08-31 10:43:54 +02:00
func ( gui * Gui ) editFile ( filename string ) error {
2019-03-23 03:16:55 +02:00
_ , err := gui . runSyncOrAsyncCommand ( gui . OSCommand . EditFile ( filename ) )
return err
2018-08-14 11:05:26 +02:00
}
func ( gui * Gui ) handleFileEdit ( g * gocui . Gui , v * gocui . View ) error {
2018-08-18 06:52:01 +02:00
file , err := gui . getSelectedFile ( g )
if err != nil {
2019-03-16 03:48:09 +02:00
return gui . createErrorPanel ( gui . g , err . Error ( ) )
2018-08-18 06:52:01 +02:00
}
2018-08-31 10:43:54 +02:00
return gui . editFile ( file . Name )
2018-08-14 11:05:26 +02:00
}
func ( gui * Gui ) handleFileOpen ( g * gocui . Gui , v * gocui . View ) error {
2018-08-18 06:52:01 +02:00
file , err := gui . getSelectedFile ( g )
if err != nil {
2019-03-16 03:48:09 +02:00
return gui . createErrorPanel ( gui . g , err . Error ( ) )
2018-08-18 06:52:01 +02:00
}
2018-08-23 21:05:09 +02:00
return gui . openFile ( file . Name )
2018-08-14 11:05:26 +02:00
}
func ( gui * Gui ) handleRefreshFiles ( g * gocui . Gui , v * gocui . View ) error {
2018-12-08 07:54:54 +02:00
return gui . refreshFiles ( )
2018-08-14 11:05:26 +02:00
}
2019-03-02 04:22:02 +02:00
func ( gui * Gui ) refreshStateFiles ( ) error {
2018-08-14 11:05:26 +02:00
// get files to stage
files := gui . GitCommand . GetStatusFiles ( )
gui . State . Files = gui . GitCommand . MergeStatusFiles ( gui . State . Files , files )
2019-11-12 13:19:20 +02:00
if err := gui . addFilesToFileWatcher ( files ) ; err != nil {
return err
}
2018-12-04 10:50:11 +02:00
gui . refreshSelectedLine ( & gui . State . Panels . Files . SelectedLine , len ( gui . State . Files ) )
2019-03-02 04:22:02 +02:00
return gui . updateWorkTreeState ( )
2018-08-14 11:05:26 +02:00
}
func ( gui * Gui ) catSelectedFile ( g * gocui . Gui ) ( string , error ) {
item , err := gui . getSelectedFile ( g )
if err != nil {
2018-08-14 15:47:14 +02:00
if err != gui . Errors . ErrNoFiles {
2018-08-14 11:05:26 +02:00
return "" , err
}
2018-08-16 07:16:32 +02:00
return "" , gui . renderString ( g , "main" , gui . Tr . SLocalize ( "NoFilesDisplay" ) )
2018-08-14 11:05:26 +02:00
}
2018-08-28 11:12:35 +02:00
if item . Type != "file" {
return "" , gui . renderString ( g , "main" , gui . Tr . SLocalize ( "NotAFile" ) )
}
2018-08-14 11:05:26 +02:00
cat , err := gui . GitCommand . CatFile ( item . Name )
if err != nil {
2018-08-28 11:12:35 +02:00
gui . Log . Error ( err )
return "" , gui . renderString ( g , "main" , err . Error ( ) )
2018-08-14 11:05:26 +02:00
}
return cat , nil
}
2019-11-13 12:16:24 +02:00
func ( gui * Gui ) handlePullFiles ( g * gocui . Gui , v * gocui . View ) error {
// if we have no upstream branch we need to set that first
_ , pullables := gui . GitCommand . GetCurrentBranchUpstreamDifferenceCount ( )
currentBranchName , err := gui . GitCommand . CurrentBranchName ( )
if err != nil {
return err
}
if pullables == "?" {
return gui . createPromptPanel ( g , v , gui . Tr . SLocalize ( "EnterUpstream" ) , "origin/" + currentBranchName , func ( g * gocui . Gui , v * gocui . View ) error {
upstream := gui . trimmedContent ( v )
if err := gui . GitCommand . SetUpstreamBranch ( upstream ) ; err != nil {
errorMessage := err . Error ( )
if strings . Contains ( errorMessage , "does not exist" ) {
errorMessage = fmt . Sprintf ( "upstream branch %s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')" , upstream )
}
return gui . createErrorPanel ( gui . g , errorMessage )
}
return gui . pullFiles ( v )
} )
}
return gui . pullFiles ( v )
}
func ( gui * Gui ) pullFiles ( v * gocui . View ) error {
2019-02-16 03:03:22 +02:00
if err := gui . createLoaderPanel ( gui . g , v , gui . Tr . SLocalize ( "PullWait" ) ) ; err != nil {
2018-11-02 10:54:54 +02:00
return err
}
2019-02-16 03:03:22 +02:00
2018-08-14 11:05:26 +02:00
go func ( ) {
2018-11-02 10:54:54 +02:00
unamePassOpend := false
err := gui . GitCommand . Pull ( func ( passOrUname string ) string {
unamePassOpend = true
2019-11-13 12:16:24 +02:00
return gui . waitForPassUname ( gui . g , v , passOrUname )
2018-11-02 10:54:54 +02:00
} )
2019-11-13 12:16:24 +02:00
gui . HandleCredentialsPopup ( gui . g , unamePassOpend , err )
2018-08-14 11:05:26 +02:00
} ( )
2019-11-13 12:16:24 +02:00
2018-08-14 11:05:26 +02:00
return nil
}
2019-11-11 14:22:09 +02:00
func ( gui * Gui ) pushWithForceFlag ( g * gocui . Gui , v * gocui . View , force bool , upstream string ) error {
2019-02-16 03:03:22 +02:00
if err := gui . createLoaderPanel ( gui . g , v , gui . Tr . SLocalize ( "PushWait" ) ) ; err != nil {
2018-08-19 13:28:13 +02:00
return err
}
2018-08-14 11:05:26 +02:00
go func ( ) {
2018-11-02 10:54:54 +02:00
unamePassOpend := false
2018-08-14 11:05:26 +02:00
branchName := gui . State . Branches [ 0 ] . Name
2019-11-11 14:22:09 +02:00
err := gui . GitCommand . Push ( branchName , force , upstream , func ( passOrUname string ) string {
2018-11-02 10:54:54 +02:00
unamePassOpend = true
return gui . waitForPassUname ( g , v , passOrUname )
2018-10-17 21:12:33 +02:00
} )
2018-12-10 09:22:52 +02:00
gui . HandleCredentialsPopup ( g , unamePassOpend , err )
2018-08-14 11:05:26 +02:00
} ( )
return nil
}
2018-08-19 13:28:13 +02:00
func ( gui * Gui ) pushFiles ( g * gocui . Gui , v * gocui . View ) error {
// if we have pullables we'll ask if the user wants to force push
2018-12-07 09:52:31 +02:00
_ , pullables := gui . GitCommand . GetCurrentBranchUpstreamDifferenceCount ( )
2019-11-11 14:22:09 +02:00
currentBranchName , err := gui . GitCommand . CurrentBranchName ( )
if err != nil {
return err
}
if pullables == "?" {
return gui . createPromptPanel ( g , v , gui . Tr . SLocalize ( "EnterUpstream" ) , "origin " + currentBranchName , func ( g * gocui . Gui , v * gocui . View ) error {
return gui . pushWithForceFlag ( g , v , false , gui . trimmedContent ( v ) )
} )
} else if pullables == "0" {
return gui . pushWithForceFlag ( g , v , false , "" )
2018-08-19 13:28:13 +02:00
}
2019-11-11 14:22:09 +02:00
return gui . createConfirmationPanel ( g , nil , true , gui . Tr . SLocalize ( "ForcePush" ) , gui . Tr . SLocalize ( "ForcePushPrompt" ) , func ( g * gocui . Gui , v * gocui . View ) error {
return gui . pushWithForceFlag ( g , v , true , "" )
2018-08-19 13:28:13 +02:00
} , nil )
}
2018-08-14 11:05:26 +02:00
func ( gui * Gui ) handleSwitchToMerge ( g * gocui . Gui , v * gocui . View ) error {
file , err := gui . getSelectedFile ( g )
if err != nil {
2018-08-14 15:47:14 +02:00
if err != gui . Errors . ErrNoFiles {
2019-03-16 03:48:09 +02:00
return gui . createErrorPanel ( gui . g , err . Error ( ) )
2018-08-14 11:05:26 +02:00
}
return nil
}
2019-03-03 06:55:19 +02:00
if ! file . HasInlineMergeConflicts {
2018-08-16 07:16:32 +02:00
return gui . createErrorPanel ( g , gui . Tr . SLocalize ( "FileNoMergeCons" ) )
2018-08-14 11:05:26 +02:00
}
2019-11-16 03:41:04 +02:00
if err := gui . changeMainViewsContext ( "merging" ) ; err != nil {
2019-02-16 03:07:27 +02:00
return err
}
if err := gui . switchFocus ( g , v , gui . getMainView ( ) ) ; err != nil {
return err
}
return gui . refreshMergePanel ( )
2018-08-14 11:05:26 +02:00
}
func ( gui * Gui ) handleAbortMerge ( g * gocui . Gui , v * gocui . View ) error {
if err := gui . GitCommand . AbortMerge ( ) ; err != nil {
return gui . createErrorPanel ( g , err . Error ( ) )
}
2018-08-16 07:16:32 +02:00
gui . createMessagePanel ( g , v , "" , gui . Tr . SLocalize ( "MergeAborted" ) )
2018-08-14 11:05:26 +02:00
gui . refreshStatus ( g )
2018-12-08 07:54:54 +02:00
return gui . refreshFiles ( )
2018-08-14 11:05:26 +02:00
}
2018-08-23 21:05:09 +02:00
func ( gui * Gui ) openFile ( filename string ) error {
if err := gui . OSCommand . OpenFile ( filename ) ; err != nil {
return gui . createErrorPanel ( gui . g , err . Error ( ) )
}
return nil
}
2018-12-08 07:54:54 +02:00
func ( gui * Gui ) anyFilesWithMergeConflicts ( ) bool {
for _ , file := range gui . State . Files {
if file . HasMergeConflicts {
return true
}
}
return false
}
2019-02-19 14:36:29 +02:00
2019-03-18 11:44:33 +02:00
type discardOption struct {
handler func ( fileName * commands . File ) error
description string
}
2019-03-18 12:19:07 +02:00
type discardAllOption struct {
handler func ( ) error
description string
command string
}
2019-03-18 11:44:33 +02:00
// GetDisplayStrings is a function.
func ( r * discardOption ) GetDisplayStrings ( isFocused bool ) [ ] string {
return [ ] string { r . description }
}
2019-03-18 12:19:07 +02:00
// GetDisplayStrings is a function.
func ( r * discardAllOption ) GetDisplayStrings ( isFocused bool ) [ ] string {
return [ ] string { r . description , color . New ( color . FgRed ) . Sprint ( r . command ) }
}
2019-03-18 11:44:33 +02:00
func ( gui * Gui ) handleCreateDiscardMenu ( g * gocui . Gui , v * gocui . View ) error {
file , err := gui . getSelectedFile ( g )
if err != nil {
if err != gui . Errors . ErrNoFiles {
return err
}
return nil
}
options := [ ] * discardOption {
{
description : gui . Tr . SLocalize ( "discardAllChanges" ) ,
handler : func ( file * commands . File ) error {
2019-03-18 12:19:07 +02:00
return gui . GitCommand . DiscardAllFileChanges ( file )
2019-03-18 11:44:33 +02:00
} ,
} ,
{
description : gui . Tr . SLocalize ( "cancel" ) ,
handler : func ( file * commands . File ) error {
return nil
} ,
} ,
}
if file . HasStagedChanges && file . HasUnstagedChanges {
discardUnstagedChanges := & discardOption {
description : gui . Tr . SLocalize ( "discardUnstagedChanges" ) ,
handler : func ( file * commands . File ) error {
2019-03-18 12:19:07 +02:00
return gui . GitCommand . DiscardUnstagedFileChanges ( file )
2019-03-18 11:44:33 +02:00
} ,
}
options = append ( options [ : 1 ] , append ( [ ] * discardOption { discardUnstagedChanges } , options [ 1 : ] ... ) ... )
}
handleMenuPress := func ( index int ) error {
2019-03-23 03:34:24 +02:00
file , err := gui . getSelectedFile ( g )
if err != nil {
return err
}
2019-03-18 12:19:07 +02:00
if err := options [ index ] . handler ( file ) ; err != nil {
return err
}
return gui . refreshFiles ( )
2019-03-18 11:44:33 +02:00
}
2019-03-23 04:22:21 +02:00
return gui . createMenu ( file . Name , options , len ( options ) , handleMenuPress )
2019-03-18 11:44:33 +02:00
}
2019-03-18 12:19:07 +02:00
2019-03-18 12:40:32 +02:00
func ( gui * Gui ) handleCreateResetMenu ( g * gocui . Gui , v * gocui . View ) error {
2019-03-18 12:19:07 +02:00
options := [ ] * discardAllOption {
{
description : gui . Tr . SLocalize ( "discardAllChangesToAllFiles" ) ,
command : "reset --hard HEAD && git clean -fd" ,
handler : func ( ) error {
return gui . GitCommand . ResetAndClean ( )
} ,
} ,
{
description : gui . Tr . SLocalize ( "discardAnyUnstagedChanges" ) ,
command : "git checkout -- ." ,
handler : func ( ) error {
return gui . GitCommand . DiscardAnyUnstagedFileChanges ( )
} ,
} ,
{
description : gui . Tr . SLocalize ( "discardUntrackedFiles" ) ,
command : "git clean -fd" ,
handler : func ( ) error {
return gui . GitCommand . RemoveUntrackedFiles ( )
} ,
} ,
2019-03-18 12:40:32 +02:00
{
description : gui . Tr . SLocalize ( "softReset" ) ,
command : "git reset --soft HEAD" ,
handler : func ( ) error {
return gui . GitCommand . ResetSoftHead ( )
} ,
} ,
2019-03-18 12:19:07 +02:00
{
description : gui . Tr . SLocalize ( "hardReset" ) ,
command : "git reset --hard HEAD" ,
handler : func ( ) error {
return gui . GitCommand . ResetHardHead ( )
} ,
} ,
{
description : gui . Tr . SLocalize ( "cancel" ) ,
handler : func ( ) error {
return nil
} ,
} ,
}
handleMenuPress := func ( index int ) error {
if err := options [ index ] . handler ( ) ; err != nil {
return err
}
return gui . refreshFiles ( )
}
2019-03-23 04:22:21 +02:00
return gui . createMenu ( "" , options , len ( options ) , handleMenuPress )
2019-03-18 12:19:07 +02:00
}
2019-03-12 12:43:56 +02:00
func ( gui * Gui ) handleCustomCommand ( g * gocui . Gui , v * gocui . View ) error {
2019-11-11 14:22:09 +02:00
return gui . createPromptPanel ( g , v , gui . Tr . SLocalize ( "CustomCommand" ) , "" , func ( g * gocui . Gui , v * gocui . View ) error {
2019-03-12 12:43:56 +02:00
command := gui . trimmedContent ( v )
gui . SubProcess = gui . OSCommand . RunCustomCommand ( command )
return gui . Errors . ErrSubProcess
} )
}
2019-05-30 14:45:56 +02:00
type stashOption struct {
description string
handler func ( ) error
}
// GetDisplayStrings is a function.
func ( o * stashOption ) GetDisplayStrings ( isFocused bool ) [ ] string {
return [ ] string { o . description }
}
func ( gui * Gui ) handleCreateStashMenu ( g * gocui . Gui , v * gocui . View ) error {
options := [ ] * stashOption {
{
description : gui . Tr . SLocalize ( "stashAllChanges" ) ,
handler : func ( ) error {
return gui . handleStashSave ( gui . GitCommand . StashSave )
} ,
} ,
{
description : gui . Tr . SLocalize ( "stashStagedChanges" ) ,
handler : func ( ) error {
return gui . handleStashSave ( gui . GitCommand . StashSaveStagedChanges )
} ,
} ,
{
description : gui . Tr . SLocalize ( "cancel" ) ,
handler : func ( ) error {
return nil
} ,
} ,
}
handleMenuPress := func ( index int ) error {
return options [ index ] . handler ( )
}
return gui . createMenu ( gui . Tr . SLocalize ( "stashOptions" ) , options , len ( options ) , handleMenuPress )
}
func ( gui * Gui ) handleStashChanges ( g * gocui . Gui , v * gocui . View ) error {
return gui . handleStashSave ( gui . GitCommand . StashSave )
}