mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-21 00:30:00 +02:00
add mouse support
This commit is contained in:
@ -18,6 +18,7 @@
|
|||||||
- blue
|
- blue
|
||||||
commitLength:
|
commitLength:
|
||||||
show: true
|
show: true
|
||||||
|
mouseEvents: true
|
||||||
git:
|
git:
|
||||||
merging:
|
merging:
|
||||||
# only applicable to unix users
|
# only applicable to unix users
|
||||||
|
@ -242,7 +242,7 @@ func GetDefaultConfig() []byte {
|
|||||||
## stuff relating to the UI
|
## stuff relating to the UI
|
||||||
scrollHeight: 2
|
scrollHeight: 2
|
||||||
scrollPastBottom: true
|
scrollPastBottom: true
|
||||||
mouseEvents: false # will default to true when the feature is complete
|
mouseEvents: true
|
||||||
theme:
|
theme:
|
||||||
lightTheme: false
|
lightTheme: false
|
||||||
activeBorderColor:
|
activeBorderColor:
|
||||||
|
@ -19,6 +19,14 @@ func (gui *Gui) getSelectedBranch() *commands.Branch {
|
|||||||
return gui.State.Branches[selectedLine]
|
return gui.State.Branches[selectedLine]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleBranchesClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
itemCount := len(gui.State.Branches)
|
||||||
|
handleSelect := gui.handleBranchSelect
|
||||||
|
selectedLine := &gui.State.Panels.Branches.SelectedLine
|
||||||
|
|
||||||
|
return gui.handleClick(v, itemCount, selectedLine, handleSelect)
|
||||||
|
}
|
||||||
|
|
||||||
// may want to standardise how these select methods work
|
// may want to standardise how these select methods work
|
||||||
func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() {
|
if gui.popupPanelFocused() {
|
||||||
@ -30,6 +38,9 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.getMainView().Title = "Log"
|
||||||
|
|
||||||
// This really shouldn't happen: there should always be a master branch
|
// This really shouldn't happen: there should always be a master branch
|
||||||
if len(gui.State.Branches) == 0 {
|
if len(gui.State.Branches) == 0 {
|
||||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
|
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
|
||||||
|
@ -15,11 +15,21 @@ func (gui *Gui) getSelectedCommitFile(g *gocui.Gui) *commands.CommitFile {
|
|||||||
return gui.State.CommitFiles[selectedLine]
|
return gui.State.CommitFiles[selectedLine]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCommitFilesClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
itemCount := len(gui.State.CommitFiles)
|
||||||
|
handleSelect := gui.handleCommitFileSelect
|
||||||
|
selectedLine := &gui.State.Panels.CommitFiles.SelectedLine
|
||||||
|
|
||||||
|
return gui.handleClick(v, itemCount, selectedLine, handleSelect)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() {
|
if gui.popupPanelFocused() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.getMainView().Title = "Patch"
|
||||||
|
|
||||||
commitFile := gui.getSelectedCommitFile(g)
|
commitFile := gui.getSelectedCommitFile(g)
|
||||||
if commitFile == nil {
|
if commitFile == nil {
|
||||||
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
|
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
|
||||||
@ -96,7 +106,7 @@ func (gui *Gui) refreshCommitFilesView() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.refreshPatchBuildingPanel(); err != nil {
|
if err := gui.refreshPatchBuildingPanel(-1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,16 +187,20 @@ func (gui *Gui) startPatchManager() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleEnterCommitFile(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleEnterCommitFile(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gui.enterCommitFile(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
|
||||||
if ok, err := gui.validateNormalWorkingTreeState(); !ok {
|
if ok, err := gui.validateNormalWorkingTreeState(); !ok {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
commitFile := gui.getSelectedCommitFile(g)
|
commitFile := gui.getSelectedCommitFile(gui.g)
|
||||||
if commitFile == nil {
|
if commitFile == nil {
|
||||||
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
|
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
|
||||||
}
|
}
|
||||||
|
|
||||||
enterTheFile := func() error {
|
enterTheFile := func(selectedLineIdx int) error {
|
||||||
if !gui.GitCommand.PatchManager.CommitSelected() {
|
if !gui.GitCommand.PatchManager.CommitSelected() {
|
||||||
if err := gui.startPatchManager(); err != nil {
|
if err := gui.startPatchManager(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -196,18 +210,21 @@ func (gui *Gui) handleEnterCommitFile(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if err := gui.changeContext("main", "patch-building"); err != nil {
|
if err := gui.changeContext("main", "patch-building"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.switchFocus(g, v, gui.getMainView()); err != nil {
|
if err := gui.changeContext("secondary", "patch-building"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gui.refreshPatchBuildingPanel()
|
if err := gui.switchFocus(gui.g, gui.getCommitFilesView(), gui.getMainView()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gui.refreshPatchBuildingPanel(selectedLineIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha {
|
if gui.GitCommand.PatchManager.CommitSelected() && gui.GitCommand.PatchManager.CommitSha != commitFile.Sha {
|
||||||
return gui.createConfirmationPanel(g, v, false, gui.Tr.SLocalize("DiscardPatch"), gui.Tr.SLocalize("DiscardPatchConfirm"), func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.g, gui.getCommitFilesView(), false, gui.Tr.SLocalize("DiscardPatch"), gui.Tr.SLocalize("DiscardPatchConfirm"), func(g *gocui.Gui, v *gocui.View) error {
|
||||||
gui.GitCommand.PatchManager.Reset()
|
gui.GitCommand.PatchManager.Reset()
|
||||||
return enterTheFile()
|
return enterTheFile(selectedLineIdx)
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return enterTheFile()
|
return enterTheFile(selectedLineIdx)
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,14 @@ func (gui *Gui) getSelectedCommit(g *gocui.Gui) *commands.Commit {
|
|||||||
return gui.State.Commits[selectedLine]
|
return gui.State.Commits[selectedLine]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleCommitsClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
itemCount := len(gui.State.Commits)
|
||||||
|
handleSelect := gui.handleCommitSelect
|
||||||
|
selectedLine := &gui.State.Panels.Commits.SelectedLine
|
||||||
|
|
||||||
|
return gui.handleClick(v, itemCount, selectedLine, handleSelect)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() {
|
if gui.popupPanelFocused() {
|
||||||
return nil
|
return nil
|
||||||
@ -36,6 +44,10 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.getMainView().Title = "Patch"
|
||||||
|
gui.getSecondaryView().Title = "Custom Patch"
|
||||||
|
|
||||||
commit := gui.getSelectedCommit(g)
|
commit := gui.getSelectedCommit(g)
|
||||||
if commit == nil {
|
if commit == nil {
|
||||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
|
return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
|
||||||
@ -458,7 +470,7 @@ func (gui *Gui) handleSwitchToCommitFilesPanel(g *gocui.Gui, v *gocui.View) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.switchFocus(g, v, gui.getCommitFilesView())
|
return gui.switchFocus(g, gui.getCommitsView(), gui.getCommitFilesView())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleToggleDiffCommit(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleToggleDiffCommit(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
@ -1,44 +1,5 @@
|
|||||||
package gui
|
package gui
|
||||||
|
|
||||||
func (gui *Gui) titleMap() map[string]string {
|
|
||||||
return map[string]string{
|
|
||||||
"commits": gui.Tr.SLocalize("DiffTitle"),
|
|
||||||
"branches": gui.Tr.SLocalize("LogTitle"),
|
|
||||||
"files": gui.Tr.SLocalize("DiffTitle"),
|
|
||||||
"status": "",
|
|
||||||
"stash": gui.Tr.SLocalize("DiffTitle"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) contextTitleMap() map[string]map[string]string {
|
|
||||||
return map[string]map[string]string{
|
|
||||||
"main": {
|
|
||||||
"staging": gui.Tr.SLocalize("StagingMainTitle"),
|
|
||||||
"patch-building": gui.Tr.SLocalize("PatchBuildingMainTitle"),
|
|
||||||
"merging": gui.Tr.SLocalize("MergingMainTitle"),
|
|
||||||
"normal": "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) setMainTitle() error {
|
|
||||||
currentView := gui.g.CurrentView()
|
|
||||||
if currentView == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
currentViewName := currentView.Name()
|
|
||||||
var newTitle string
|
|
||||||
if context, ok := gui.State.Contexts[currentViewName]; ok {
|
|
||||||
newTitle = gui.contextTitleMap()[currentViewName][context]
|
|
||||||
} else if title, ok := gui.titleMap()[currentViewName]; ok {
|
|
||||||
newTitle = title
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
gui.getMainView().Title = newTitle
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) changeContext(viewName, context string) error {
|
func (gui *Gui) changeContext(viewName, context string) error {
|
||||||
if gui.State.Contexts[viewName] == context {
|
if gui.State.Contexts[viewName] == context {
|
||||||
return nil
|
return nil
|
||||||
@ -50,19 +11,20 @@ func (gui *Gui) changeContext(viewName, context string) error {
|
|||||||
|
|
||||||
bindings := contextMap[viewName][context]
|
bindings := contextMap[viewName][context]
|
||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
if err := gui.g.SetKeybinding(viewName, binding.Key, binding.Modifier, binding.Handler); err != nil {
|
if err := gui.g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, binding.Handler); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gui.State.Contexts[viewName] = context
|
gui.State.Contexts[viewName] = context
|
||||||
return gui.setMainTitle()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) setInitialContexts() error {
|
func (gui *Gui) setInitialContexts() error {
|
||||||
contextMap := gui.GetContextMap()
|
contextMap := gui.GetContextMap()
|
||||||
|
|
||||||
initialContexts := map[string]string{
|
initialContexts := map[string]string{
|
||||||
"main": "normal",
|
"main": "normal",
|
||||||
|
"secondary": "normal",
|
||||||
}
|
}
|
||||||
|
|
||||||
for viewName, context := range initialContexts {
|
for viewName, context := range initialContexts {
|
||||||
|
@ -27,24 +27,21 @@ func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
|
|||||||
return gui.State.Files[selectedLine], nil
|
return gui.State.Files[selectedLine], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleFilesFocus(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleFilesClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() {
|
if gui.popupPanelFocused() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cx, cy := v.Cursor()
|
prevSelectedLineIdx := gui.State.Panels.Files.SelectedLine
|
||||||
_, oy := v.Origin()
|
newSelectedLineIdx := v.SelectedLineIdx()
|
||||||
|
|
||||||
prevSelectedLine := gui.State.Panels.Files.SelectedLine
|
if newSelectedLineIdx > len(gui.State.Files)-1 {
|
||||||
newSelectedLine := cy - oy
|
|
||||||
|
|
||||||
if newSelectedLine > len(gui.State.Files)-1 || len(utils.Decolorise(gui.State.Files[newSelectedLine].DisplayString)) < cx {
|
|
||||||
return gui.handleFileSelect(gui.g, v, false)
|
return gui.handleFileSelect(gui.g, v, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.State.Panels.Files.SelectedLine = newSelectedLine
|
gui.State.Panels.Files.SelectedLine = newSelectedLineIdx
|
||||||
|
|
||||||
if prevSelectedLine == newSelectedLine && gui.currentViewName() == v.Name() {
|
if prevSelectedLineIdx == newSelectedLineIdx && gui.currentViewName() == v.Name() {
|
||||||
return gui.handleFilePress(gui.g, v)
|
return gui.handleFilePress(gui.g, v)
|
||||||
} else {
|
} else {
|
||||||
return gui.handleFileSelect(gui.g, v, true)
|
return gui.handleFileSelect(gui.g, v, true)
|
||||||
@ -77,12 +74,16 @@ func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View, alreadySelected bo
|
|||||||
leftContent := content
|
leftContent := content
|
||||||
if file.HasStagedChanges && file.HasUnstagedChanges {
|
if file.HasStagedChanges && file.HasUnstagedChanges {
|
||||||
gui.State.SplitMainPanel = true
|
gui.State.SplitMainPanel = true
|
||||||
|
gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
|
||||||
|
gui.getSecondaryView().Title = gui.Tr.SLocalize("StagedChanges")
|
||||||
} else {
|
} else {
|
||||||
gui.State.SplitMainPanel = false
|
gui.State.SplitMainPanel = false
|
||||||
if file.HasUnstagedChanges {
|
if file.HasUnstagedChanges {
|
||||||
leftContent = content
|
leftContent = content
|
||||||
|
gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
|
||||||
} else {
|
} else {
|
||||||
leftContent = contentCached
|
leftContent = contentCached
|
||||||
|
gui.getMainView().Title = gui.Tr.SLocalize("StagedChanges")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +190,11 @@ func (gui *Gui) stageSelectedFile(g *gocui.Gui) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleEnterFile(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleEnterFile(g *gocui.Gui, v *gocui.View) error {
|
||||||
file, err := gui.getSelectedFile(g)
|
return gui.enterFile(false, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error {
|
||||||
|
file, err := gui.getSelectedFile(gui.g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != gui.Errors.ErrNoFiles {
|
if err != gui.Errors.ErrNoFiles {
|
||||||
return err
|
return err
|
||||||
@ -197,18 +202,21 @@ func (gui *Gui) handleEnterFile(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if file.HasInlineMergeConflicts {
|
if file.HasInlineMergeConflicts {
|
||||||
return gui.handleSwitchToMerge(g, v)
|
return gui.handleSwitchToMerge(gui.g, gui.getFilesView())
|
||||||
}
|
}
|
||||||
if file.HasMergeConflicts {
|
if file.HasMergeConflicts {
|
||||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("FileStagingRequirements"))
|
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("FileStagingRequirements"))
|
||||||
}
|
}
|
||||||
if err := gui.changeContext("main", "staging"); err != nil {
|
if err := gui.changeContext("main", "staging"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.switchFocus(g, v, gui.getMainView()); err != nil {
|
if err := gui.changeContext("secondary", "staging"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gui.refreshStagingPanel()
|
if err := gui.switchFocus(gui.g, gui.getFilesView(), gui.getMainView()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
@ -118,12 +118,18 @@ type stashPanelState struct {
|
|||||||
|
|
||||||
type menuPanelState struct {
|
type menuPanelState struct {
|
||||||
SelectedLine int
|
SelectedLine int
|
||||||
|
OnPress func(g *gocui.Gui, v *gocui.View) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type commitFilesPanelState struct {
|
type commitFilesPanelState struct {
|
||||||
SelectedLine int
|
SelectedLine int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type statusPanelState struct {
|
||||||
|
pushables string
|
||||||
|
pullables string
|
||||||
|
}
|
||||||
|
|
||||||
type panelStates struct {
|
type panelStates struct {
|
||||||
Files *filePanelState
|
Files *filePanelState
|
||||||
Branches *branchPanelState
|
Branches *branchPanelState
|
||||||
@ -133,6 +139,7 @@ type panelStates struct {
|
|||||||
LineByLine *lineByLinePanelState
|
LineByLine *lineByLinePanelState
|
||||||
Merging *mergingPanelState
|
Merging *mergingPanelState
|
||||||
CommitFiles *commitFilesPanelState
|
CommitFiles *commitFilesPanelState
|
||||||
|
Status *statusPanelState
|
||||||
}
|
}
|
||||||
|
|
||||||
type guiState struct {
|
type guiState struct {
|
||||||
@ -179,6 +186,7 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
|
|||||||
Conflicts: []commands.Conflict{},
|
Conflicts: []commands.Conflict{},
|
||||||
EditHistory: stack.New(),
|
EditHistory: stack.New(),
|
||||||
},
|
},
|
||||||
|
Status: &statusPanelState{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +265,7 @@ func (gui *Gui) onFocusChange() error {
|
|||||||
for _, view := range gui.g.Views() {
|
for _, view := range gui.g.Views() {
|
||||||
view.Highlight = view == currentView
|
view.Highlight = view == currentView
|
||||||
}
|
}
|
||||||
return gui.setMainTitle()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
|
func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
|
||||||
@ -683,6 +691,8 @@ func (gui *Gui) Run() error {
|
|||||||
}
|
}
|
||||||
defer g.Close()
|
defer g.Close()
|
||||||
|
|
||||||
|
g.Log = gui.Log
|
||||||
|
|
||||||
if gui.Config.GetUserConfig().GetBool("gui.mouseEvents") {
|
if gui.Config.GetUserConfig().GetBool("gui.mouseEvents") {
|
||||||
g.Mouse = true
|
g.Mouse = true
|
||||||
}
|
}
|
||||||
@ -795,3 +805,31 @@ func (gui *Gui) setColorScheme() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseDownMain(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch g.CurrentView().Name() {
|
||||||
|
case "files":
|
||||||
|
return gui.enterFile(false, v.SelectedLineIdx())
|
||||||
|
case "commitFiles":
|
||||||
|
return gui.enterCommitFile(v.SelectedLineIdx())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseDownSecondary(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch g.CurrentView().Name() {
|
||||||
|
case "files":
|
||||||
|
return gui.enterFile(true, v.SelectedLineIdx())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -144,6 +144,11 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||||||
Key: 'x',
|
Key: 'x',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleCreateOptionsMenu,
|
Handler: gui.handleCreateOptionsMenu,
|
||||||
|
}, {
|
||||||
|
ViewName: "",
|
||||||
|
Key: gocui.MouseMiddle,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleCreateOptionsMenu,
|
||||||
}, {
|
}, {
|
||||||
ViewName: "",
|
ViewName: "",
|
||||||
Key: gocui.KeyCtrlP,
|
Key: gocui.KeyCtrlP,
|
||||||
@ -558,15 +563,15 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||||||
listPanelMap := map[string]struct {
|
listPanelMap := map[string]struct {
|
||||||
prevLine func(*gocui.Gui, *gocui.View) error
|
prevLine func(*gocui.Gui, *gocui.View) error
|
||||||
nextLine func(*gocui.Gui, *gocui.View) error
|
nextLine func(*gocui.Gui, *gocui.View) error
|
||||||
focus func(*gocui.Gui, *gocui.View) error
|
onClick func(*gocui.Gui, *gocui.View) error
|
||||||
}{
|
}{
|
||||||
"menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, focus: gui.handleMenuSelect},
|
"menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, onClick: gui.handleMenuClick},
|
||||||
"files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus},
|
"files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, onClick: gui.handleFilesClick},
|
||||||
"branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect},
|
"branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, onClick: gui.handleBranchesClick},
|
||||||
"commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect},
|
"commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, onClick: gui.handleCommitsClick},
|
||||||
"stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect},
|
"stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, onClick: gui.handleStashEntrySelect},
|
||||||
"status": {focus: gui.handleStatusSelect},
|
"status": {onClick: gui.handleStatusClick},
|
||||||
"commitFiles": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine, focus: gui.handleCommitFileSelect},
|
"commitFiles": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine, onClick: gui.handleCommitFilesClick},
|
||||||
}
|
}
|
||||||
|
|
||||||
for viewName, functions := range listPanelMap {
|
for viewName, functions := range listPanelMap {
|
||||||
@ -577,7 +582,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||||||
{ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: functions.nextLine},
|
{ViewName: viewName, Key: 'j', Modifier: gocui.ModNone, Handler: functions.nextLine},
|
||||||
{ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: functions.nextLine},
|
{ViewName: viewName, Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: functions.nextLine},
|
||||||
{ViewName: viewName, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: functions.nextLine},
|
{ViewName: viewName, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: functions.nextLine},
|
||||||
{ViewName: viewName, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: functions.focus},
|
{ViewName: viewName, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: functions.onClick},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,6 +615,24 @@ func (gui *Gui) keybindings(g *gocui.Gui) error {
|
|||||||
|
|
||||||
func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
||||||
return map[string]map[string][]*Binding{
|
return map[string]map[string][]*Binding{
|
||||||
|
"secondary": {
|
||||||
|
"normal": {
|
||||||
|
{
|
||||||
|
ViewName: "secondary",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseDownSecondary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"staging": {
|
||||||
|
{
|
||||||
|
ViewName: "secondary",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleTogglePanelClick,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"main": {
|
"main": {
|
||||||
"normal": {
|
"normal": {
|
||||||
{
|
{
|
||||||
@ -626,6 +649,11 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
|||||||
Handler: gui.scrollUpMain,
|
Handler: gui.scrollUpMain,
|
||||||
Description: gui.Tr.SLocalize("ScrollUp"),
|
Description: gui.Tr.SLocalize("ScrollUp"),
|
||||||
Alternative: "fn+down",
|
Alternative: "fn+down",
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseDownMain,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"staging": {
|
"staging": {
|
||||||
@ -657,16 +685,6 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
|||||||
Key: 'j',
|
Key: 'j',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleSelectNextLine,
|
Handler: gui.handleSelectNextLine,
|
||||||
}, {
|
|
||||||
ViewName: "main",
|
|
||||||
Key: gocui.MouseWheelUp,
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: gui.handleSelectPrevLine,
|
|
||||||
}, {
|
|
||||||
ViewName: "main",
|
|
||||||
Key: gocui.MouseWheelDown,
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: gui.handleSelectNextLine,
|
|
||||||
}, {
|
}, {
|
||||||
ViewName: "main",
|
ViewName: "main",
|
||||||
Key: gocui.KeyArrowLeft,
|
Key: gocui.KeyArrowLeft,
|
||||||
@ -719,6 +737,26 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
|||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleTogglePanel,
|
Handler: gui.handleTogglePanel,
|
||||||
Description: gui.Tr.SLocalize("TogglePanel"),
|
Description: gui.Tr.SLocalize("TogglePanel"),
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseDown,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModMotion,
|
||||||
|
Handler: gui.handleMouseDrag,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseWheelUp,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseScrollUp,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseWheelDown,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseScrollDown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch-building": {
|
"patch-building": {
|
||||||
@ -806,6 +844,26 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
|
|||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleToggleSelectHunk,
|
Handler: gui.handleToggleSelectHunk,
|
||||||
Description: gui.Tr.SLocalize("ToggleSelectHunk"),
|
Description: gui.Tr.SLocalize("ToggleSelectHunk"),
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseDown,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseLeft,
|
||||||
|
Modifier: gocui.ModMotion,
|
||||||
|
Handler: gui.handleMouseDrag,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseWheelUp,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseScrollUp,
|
||||||
|
}, {
|
||||||
|
ViewName: "main",
|
||||||
|
Key: gocui.MouseWheelDown,
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleMouseScrollDown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"merging": {
|
"merging": {
|
||||||
|
@ -21,7 +21,7 @@ const (
|
|||||||
|
|
||||||
// returns whether the patch is empty so caller can escape if necessary
|
// returns whether the patch is empty so caller can escape if necessary
|
||||||
// both diffs should be non-coloured because we'll parse them and colour them here
|
// both diffs should be non-coloured because we'll parse them and colour them here
|
||||||
func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, secondaryFocused bool) (bool, error) {
|
func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, secondaryFocused bool, selectedLineIdx int) (bool, error) {
|
||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
patchParser, err := commands.NewPatchParser(gui.Log, diff)
|
patchParser, err := commands.NewPatchParser(gui.Log, diff)
|
||||||
@ -33,11 +33,14 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedLineIdx int
|
|
||||||
var firstLineIdx int
|
var firstLineIdx int
|
||||||
var lastLineIdx int
|
var lastLineIdx int
|
||||||
selectMode := LINE
|
selectMode := LINE
|
||||||
if state != nil {
|
// if we have clicked from the outside to focus the main view we'll pass in a non-negative line index so that we can instantly select that line
|
||||||
|
if selectedLineIdx >= 0 {
|
||||||
|
selectMode = RANGE
|
||||||
|
firstLineIdx, lastLineIdx = selectedLineIdx, selectedLineIdx
|
||||||
|
} else if state != nil {
|
||||||
if state.SelectMode == HUNK {
|
if state.SelectMode == HUNK {
|
||||||
// this is tricky: we need to find out which hunk we just staged based on our old `state.PatchParser` (as opposed to the new `patchParser`)
|
// this is tricky: we need to find out which hunk we just staged based on our old `state.PatchParser` (as opposed to the new `patchParser`)
|
||||||
// we do this by getting the first line index of the original hunk, then
|
// we do this by getting the first line index of the original hunk, then
|
||||||
@ -96,20 +99,25 @@ func (gui *Gui) handleSelectPrevLine(g *gocui.Gui, v *gocui.View) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleSelectNextLine(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleSelectNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.handleCycleLine(1)
|
return gui.handleCycleLine(+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleSelectPrevHunk(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleSelectPrevHunk(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.handleCycleHunk(-1)
|
state := gui.State.Panels.LineByLine
|
||||||
|
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, -1)
|
||||||
|
|
||||||
|
return gui.selectNewHunk(newHunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleSelectNextHunk(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleSelectNextHunk(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.handleCycleHunk(1)
|
state := gui.State.Panels.LineByLine
|
||||||
|
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 1)
|
||||||
|
|
||||||
|
return gui.selectNewHunk(newHunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCycleHunk(change int) error {
|
func (gui *Gui) selectNewHunk(newHunk *commands.PatchHunk) error {
|
||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, change)
|
|
||||||
state.SelectedLineIdx = state.PatchParser.GetNextStageableLineIndex(newHunk.FirstLineIdx)
|
state.SelectedLineIdx = state.PatchParser.GetNextStageableLineIndex(newHunk.FirstLineIdx)
|
||||||
if state.SelectMode == HUNK {
|
if state.SelectMode == HUNK {
|
||||||
state.FirstLineIdx, state.LastLineIdx = newHunk.FirstLineIdx, newHunk.LastLineIdx
|
state.FirstLineIdx, state.LastLineIdx = newHunk.FirstLineIdx, newHunk.LastLineIdx
|
||||||
@ -128,10 +136,16 @@ func (gui *Gui) handleCycleLine(change int) error {
|
|||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
if state.SelectMode == HUNK {
|
if state.SelectMode == HUNK {
|
||||||
return gui.handleCycleHunk(change)
|
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, change)
|
||||||
|
return gui.selectNewHunk(newHunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
newSelectedLineIdx := state.SelectedLineIdx + change
|
return gui.handleSelectNewLine(state.SelectedLineIdx + change)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleSelectNewLine(newSelectedLineIdx int) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
if newSelectedLineIdx < 0 {
|
if newSelectedLineIdx < 0 {
|
||||||
newSelectedLineIdx = 0
|
newSelectedLineIdx = 0
|
||||||
} else if newSelectedLineIdx > len(state.PatchParser.PatchLines)-1 {
|
} else if newSelectedLineIdx > len(state.PatchParser.PatchLines)-1 {
|
||||||
@ -158,6 +172,54 @@ func (gui *Gui) handleCycleLine(change int) error {
|
|||||||
return gui.focusSelection(false)
|
return gui.focusSelection(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseDown(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newSelectedLineIdx := v.SelectedLineIdx()
|
||||||
|
state.FirstLineIdx = newSelectedLineIdx
|
||||||
|
state.LastLineIdx = newSelectedLineIdx
|
||||||
|
|
||||||
|
state.SelectMode = RANGE
|
||||||
|
|
||||||
|
return gui.handleSelectNewLine(newSelectedLineIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseDrag(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.handleSelectNewLine(v.SelectedLineIdx())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseScrollUp(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SelectMode = LINE
|
||||||
|
|
||||||
|
return gui.handleCycleLine(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseScrollDown(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
if gui.popupPanelFocused() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SelectMode = LINE
|
||||||
|
|
||||||
|
return gui.handleCycleLine(1)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) refreshMainView() error {
|
func (gui *Gui) refreshMainView() error {
|
||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
@ -82,7 +82,9 @@ func (gui *Gui) createMenu(title string, items interface{}, itemCount int, handl
|
|||||||
return gui.returnFocus(gui.g, menuView)
|
return gui.returnFocus(gui.g, menuView)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, key := range []gocui.Key{gocui.KeySpace, gocui.KeyEnter} {
|
gui.State.Panels.Menu.OnPress = wrappedHandlePress
|
||||||
|
|
||||||
|
for _, key := range []gocui.Key{gocui.KeySpace, gocui.KeyEnter, 'y'} {
|
||||||
_ = gui.g.DeleteKeybinding("menu", key, gocui.ModNone)
|
_ = gui.g.DeleteKeybinding("menu", key, gocui.ModNone)
|
||||||
|
|
||||||
if err := gui.g.SetKeybinding("menu", key, gocui.ModNone, wrappedHandlePress); err != nil {
|
if err := gui.g.SetKeybinding("menu", key, gocui.ModNone, wrappedHandlePress); err != nil {
|
||||||
@ -101,3 +103,15 @@ func (gui *Gui) createMenu(title string, items interface{}, itemCount int, handl
|
|||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMenuClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
itemCount := gui.State.MenuItemCount
|
||||||
|
handleSelect := gui.handleMenuSelect
|
||||||
|
selectedLine := &gui.State.Panels.Menu.SelectedLine
|
||||||
|
|
||||||
|
if err := gui.handleClick(v, itemCount, selectedLine, handleSelect); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.State.Panels.Menu.OnPress(g, v)
|
||||||
|
}
|
||||||
|
@ -4,13 +4,16 @@ import (
|
|||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (gui *Gui) refreshPatchBuildingPanel() error {
|
func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error {
|
||||||
if !gui.GitCommand.PatchManager.CommitSelected() {
|
if !gui.GitCommand.PatchManager.CommitSelected() {
|
||||||
return gui.handleEscapePatchBuildingPanel(gui.g, nil)
|
return gui.handleEscapePatchBuildingPanel(gui.g, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.State.SplitMainPanel = true
|
gui.State.SplitMainPanel = true
|
||||||
|
|
||||||
|
gui.getMainView().Title = "Patch"
|
||||||
|
gui.getSecondaryView().Title = "Custom Patch"
|
||||||
|
|
||||||
// get diff from commit file that's currently selected
|
// get diff from commit file that's currently selected
|
||||||
commitFile := gui.getSelectedCommitFile(gui.g)
|
commitFile := gui.getSelectedCommitFile(gui.g)
|
||||||
if commitFile == nil {
|
if commitFile == nil {
|
||||||
@ -27,7 +30,7 @@ func (gui *Gui) refreshPatchBuildingPanel() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, false)
|
empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, false, selectedLineIdx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -54,7 +57,7 @@ func (gui *Gui) handleAddSelectionToPatch(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.refreshPatchBuildingPanel(); err != nil {
|
if err := gui.refreshPatchBuildingPanel(-1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +79,7 @@ func (gui *Gui) handleRemoveSelectionFromPatch(g *gocui.Gui, v *gocui.View) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.refreshPatchBuildingPanel(); err != nil {
|
if err := gui.refreshPatchBuildingPanel(-1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,13 @@ func (gui *Gui) handleCreateRebaseOptionsMenu(g *gocui.Gui, v *gocui.View) error
|
|||||||
options = append(options, &option{value: "skip"})
|
options = append(options, &option{value: "skip"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options = append(options, &option{value: "cancel"})
|
||||||
|
|
||||||
handleMenuPress := func(index int) error {
|
handleMenuPress := func(index int) error {
|
||||||
command := options[index].value
|
command := options[index].value
|
||||||
|
if command == "cancel" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return gui.genericMergeCommand(command)
|
return gui.genericMergeCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (gui *Gui) refreshStagingPanel() error {
|
func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx int) error {
|
||||||
gui.State.SplitMainPanel = true
|
gui.State.SplitMainPanel = true
|
||||||
|
|
||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
@ -25,14 +25,26 @@ func (gui *Gui) refreshStagingPanel() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
secondaryFocused := false
|
secondaryFocused := false
|
||||||
if state != nil {
|
if forceSecondaryFocused {
|
||||||
secondaryFocused = state.SecondaryFocused
|
secondaryFocused = true
|
||||||
|
} else {
|
||||||
|
if state != nil {
|
||||||
|
secondaryFocused = state.SecondaryFocused
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secondaryFocused && !file.HasStagedChanges) || (!secondaryFocused && !file.HasUnstagedChanges) {
|
if (secondaryFocused && !file.HasStagedChanges) || (!secondaryFocused && !file.HasUnstagedChanges) {
|
||||||
secondaryFocused = !secondaryFocused
|
secondaryFocused = !secondaryFocused
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if secondaryFocused {
|
||||||
|
gui.getMainView().Title = gui.Tr.SLocalize("StagedChanges")
|
||||||
|
gui.getSecondaryView().Title = gui.Tr.SLocalize("UnstagedChanges")
|
||||||
|
} else {
|
||||||
|
gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
|
||||||
|
gui.getSecondaryView().Title = gui.Tr.SLocalize("StagedChanges")
|
||||||
|
}
|
||||||
|
|
||||||
// note for custom diffs, we'll need to send a flag here saying not to use the custom diff
|
// note for custom diffs, we'll need to send a flag here saying not to use the custom diff
|
||||||
diff := gui.GitCommand.Diff(file, true, secondaryFocused)
|
diff := gui.GitCommand.Diff(file, true, secondaryFocused)
|
||||||
secondaryDiff := gui.GitCommand.Diff(file, true, !secondaryFocused)
|
secondaryDiff := gui.GitCommand.Diff(file, true, !secondaryFocused)
|
||||||
@ -47,7 +59,7 @@ func (gui *Gui) refreshStagingPanel() error {
|
|||||||
diff, secondaryDiff = secondaryDiff, diff
|
diff, secondaryDiff = secondaryDiff, diff
|
||||||
}
|
}
|
||||||
|
|
||||||
empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, secondaryFocused)
|
empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, secondaryFocused, selectedLineIdx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -59,11 +71,19 @@ func (gui *Gui) refreshStagingPanel() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleTogglePanelClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
state.SecondaryFocused = !state.SecondaryFocused
|
||||||
|
|
||||||
|
return gui.refreshStagingPanel(false, v.SelectedLineIdx())
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleTogglePanel(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleTogglePanel(g *gocui.Gui, v *gocui.View) error {
|
||||||
state := gui.State.Panels.LineByLine
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
state.SecondaryFocused = !state.SecondaryFocused
|
state.SecondaryFocused = !state.SecondaryFocused
|
||||||
return gui.refreshStagingPanel()
|
return gui.refreshStagingPanel(false, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error {
|
||||||
@ -116,8 +136,16 @@ func (gui *Gui) applySelection(reverse bool) error {
|
|||||||
if err := gui.refreshFiles(); err != nil {
|
if err := gui.refreshFiles(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := gui.refreshStagingPanel(); err != nil {
|
if err := gui.refreshStagingPanel(false, -1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleMouseDownSecondaryWhileStaging(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.LineByLine
|
||||||
|
|
||||||
|
state.SecondaryFocused = !state.SecondaryFocused
|
||||||
|
|
||||||
|
return gui.refreshStagingPanel(false, -1)
|
||||||
|
}
|
||||||
|
@ -29,6 +29,9 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.getMainView().Title = "Stash"
|
||||||
|
|
||||||
stashEntry := gui.getSelectedStashEntry(v)
|
stashEntry := gui.getSelectedStashEntry(v)
|
||||||
if stashEntry == nil {
|
if stashEntry == nil {
|
||||||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries"))
|
return gui.renderString(g, "main", gui.Tr.SLocalize("NoStashEntries"))
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (gui *Gui) refreshStatus(g *gocui.Gui) error {
|
func (gui *Gui) refreshStatus(g *gocui.Gui) error {
|
||||||
|
state := gui.State.Panels.Status
|
||||||
|
|
||||||
v, err := g.View("status")
|
v, err := g.View("status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -19,34 +21,69 @@ func (gui *Gui) refreshStatus(g *gocui.Gui) error {
|
|||||||
// contents end up cleared
|
// contents end up cleared
|
||||||
g.Update(func(*gocui.Gui) error {
|
g.Update(func(*gocui.Gui) error {
|
||||||
v.Clear()
|
v.Clear()
|
||||||
pushables, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
|
state.pushables, state.pullables = gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
|
||||||
fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
|
|
||||||
branches := gui.State.Branches
|
|
||||||
if err := gui.updateWorkTreeState(); err != nil {
|
if err := gui.updateWorkTreeState(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
status := fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables)
|
||||||
|
branches := gui.State.Branches
|
||||||
|
|
||||||
if gui.State.WorkingTreeState != "normal" {
|
if gui.State.WorkingTreeState != "normal" {
|
||||||
fmt.Fprint(v, utils.ColoredString(fmt.Sprintf(" (%s)", gui.State.WorkingTreeState), color.FgYellow))
|
status += utils.ColoredString(fmt.Sprintf(" (%s)", gui.State.WorkingTreeState), color.FgYellow)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(branches) == 0 {
|
if len(branches) > 0 {
|
||||||
return nil
|
branch := branches[0]
|
||||||
|
name := utils.ColoredString(branch.Name, branch.GetColor())
|
||||||
|
repoName := utils.GetCurrentRepoName()
|
||||||
|
status += fmt.Sprintf(" %s → %s", repoName, name)
|
||||||
}
|
}
|
||||||
branch := branches[0]
|
|
||||||
name := utils.ColoredString(branch.Name, branch.GetColor())
|
fmt.Fprint(v, status)
|
||||||
repo := utils.GetCurrentRepoName()
|
|
||||||
fmt.Fprint(v, " "+repo+" → "+name)
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runeCount(str string) int {
|
||||||
|
return len([]rune(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
func cursorInSubstring(cx int, prefix string, substring string) bool {
|
||||||
|
return cx >= runeCount(prefix) && cx < runeCount(prefix+substring)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleCheckForUpdate(g *gocui.Gui, v *gocui.View) error {
|
||||||
gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true)
|
gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true)
|
||||||
return gui.createLoaderPanel(gui.g, v, gui.Tr.SLocalize("CheckingForUpdates"))
|
return gui.createLoaderPanel(gui.g, v, gui.Tr.SLocalize("CheckingForUpdates"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleStatusClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
state := gui.State.Panels.Status
|
||||||
|
|
||||||
|
cx, _ := v.Cursor()
|
||||||
|
upstreamStatus := fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables)
|
||||||
|
repoName := utils.GetCurrentRepoName()
|
||||||
|
gui.Log.Warn(gui.State.WorkingTreeState)
|
||||||
|
switch gui.State.WorkingTreeState {
|
||||||
|
case "rebasing", "merging":
|
||||||
|
workingTreeStatus := fmt.Sprintf("(%s)", gui.State.WorkingTreeState)
|
||||||
|
if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) {
|
||||||
|
return gui.handleCreateRebaseOptionsMenu(gui.g, v)
|
||||||
|
}
|
||||||
|
if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
|
||||||
|
return gui.handleCreateRecentReposMenu(gui.g, v)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if cursorInSubstring(cx, upstreamStatus+" ", repoName) {
|
||||||
|
return gui.handleCreateRecentReposMenu(gui.g, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.handleStatusSelect(gui.g, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() {
|
if gui.popupPanelFocused() {
|
||||||
return nil
|
return nil
|
||||||
@ -57,6 +94,9 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.getMainView().Title = ""
|
||||||
|
|
||||||
magenta := color.New(color.FgMagenta)
|
magenta := color.New(color.FgMagenta)
|
||||||
|
|
||||||
dashboardString := strings.Join(
|
dashboardString := strings.Join(
|
||||||
@ -67,7 +107,7 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
|||||||
"Config Options: https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md",
|
"Config Options: https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md",
|
||||||
"Tutorial: https://youtu.be/VDXvbHZYeKY",
|
"Tutorial: https://youtu.be/VDXvbHZYeKY",
|
||||||
"Raise an Issue: https://github.com/jesseduffield/lazygit/issues",
|
"Raise an Issue: https://github.com/jesseduffield/lazygit/issues",
|
||||||
magenta.Sprint("Buy Jesse a coffee: https://donorbox.org/lazygit"), // caffeine ain't free
|
magenta.Sprint("Become a sponsor (github is matching all donations for 12 months): https://github.com/sponsors/jesseduffield"), // caffeine ain't free
|
||||||
}, "\n\n")
|
}, "\n\n")
|
||||||
|
|
||||||
return gui.renderString(g, "main", dashboardString)
|
return gui.renderString(g, "main", dashboardString)
|
||||||
|
@ -425,3 +425,27 @@ func (gui *Gui) isPopupPanel(viewName string) bool {
|
|||||||
func (gui *Gui) popupPanelFocused() bool {
|
func (gui *Gui) popupPanelFocused() bool {
|
||||||
return gui.isPopupPanel(gui.currentViewName())
|
return gui.isPopupPanel(gui.currentViewName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleClick(v *gocui.View, itemCount int, selectedLine *int, handleSelect func(*gocui.Gui, *gocui.View) error) error {
|
||||||
|
if gui.popupPanelFocused() && v != nil && !gui.isPopupPanel(v.Name()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newSelectedLine := v.SelectedLineIdx()
|
||||||
|
|
||||||
|
if newSelectedLine < 0 {
|
||||||
|
newSelectedLine = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if newSelectedLine > itemCount-1 {
|
||||||
|
newSelectedLine = itemCount - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
*selectedLine = newSelectedLine
|
||||||
|
|
||||||
|
return handleSelect(gui.g, v)
|
||||||
|
}
|
||||||
|
@ -38,8 +38,11 @@ func addDutch(i18nObject *i18n.Bundle) error {
|
|||||||
ID: "StashTitle",
|
ID: "StashTitle",
|
||||||
Other: "Stash",
|
Other: "Stash",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "StagingMainTitle",
|
ID: "UnstagedChanges",
|
||||||
Other: `Stage Lines/Hunks`,
|
Other: `Unstaged Changes`,
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "StagedChanges",
|
||||||
|
Other: `Staged Changes`,
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "MergingMainTitle",
|
ID: "MergingMainTitle",
|
||||||
Other: "Resolve merge conflicts",
|
Other: "Resolve merge conflicts",
|
||||||
|
@ -46,8 +46,11 @@ func addEnglish(i18nObject *i18n.Bundle) error {
|
|||||||
ID: "StashTitle",
|
ID: "StashTitle",
|
||||||
Other: "Stash",
|
Other: "Stash",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "StagingMainTitle",
|
ID: "UnstagedChanges",
|
||||||
Other: `Stage Lines/Hunks`,
|
Other: `Unstaged Changes`,
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "StagedChanges",
|
||||||
|
Other: `Staged Changes`,
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "PatchBuildingMainTitle",
|
ID: "PatchBuildingMainTitle",
|
||||||
Other: `Add Lines/Hunks To Patch`,
|
Other: `Add Lines/Hunks To Patch`,
|
||||||
|
@ -36,8 +36,11 @@ func addPolish(i18nObject *i18n.Bundle) error {
|
|||||||
ID: "StashTitle",
|
ID: "StashTitle",
|
||||||
Other: "Schowek",
|
Other: "Schowek",
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "StagingMainTitle",
|
ID: "UnstagedChanges",
|
||||||
Other: `Stage Lines/Hunks`,
|
Other: `Unstaged Changes`,
|
||||||
|
}, &i18n.Message{
|
||||||
|
ID: "StagedChanges",
|
||||||
|
Other: `Staged Changes`,
|
||||||
}, &i18n.Message{
|
}, &i18n.Message{
|
||||||
ID: "MergingMainTitle",
|
ID: "MergingMainTitle",
|
||||||
Other: "Resolve merge conflicts",
|
Other: "Resolve merge conflicts",
|
||||||
|
Reference in New Issue
Block a user