summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2019-11-10 16:20:35 +1100
committerJesse Duffield <jessedduffield@gmail.com>2019-11-10 22:32:13 +1100
commite85310c0a92a89167530241bdc3fc5f66a48706d (patch)
treef7989a8b002d2d5aa847460cae112aac9f64b669
parentcd17b46b55e312b3ba4e3ab9d3d96a8eeb20fded (diff)
add mouse support
-rw-r--r--docs/Config.md1
-rw-r--r--pkg/config/app_config.go2
-rw-r--r--pkg/gui/branches_panel.go11
-rw-r--r--pkg/gui/commit_files_panel.go35
-rw-r--r--pkg/gui/commits_panel.go14
-rw-r--r--pkg/gui/context.go46
-rw-r--r--pkg/gui/files_panel.go36
-rw-r--r--pkg/gui/gui.go40
-rw-r--r--pkg/gui/keybindings.go96
-rw-r--r--pkg/gui/line_by_line_panel.go82
-rw-r--r--pkg/gui/menu_panel.go16
-rw-r--r--pkg/gui/patch_building_panel.go11
-rw-r--r--pkg/gui/rebase_options_panel.go5
-rw-r--r--pkg/gui/staging_panel.go40
-rw-r--r--pkg/gui/stash_panel.go3
-rw-r--r--pkg/gui/status_panel.go62
-rw-r--r--pkg/gui/view_helpers.go24
-rw-r--r--pkg/i18n/dutch.go7
-rw-r--r--pkg/i18n/english.go7
-rw-r--r--pkg/i18n/polish.go7
20 files changed, 420 insertions, 125 deletions
diff --git a/docs/Config.md b/docs/Config.md
index a48eb4a44..63a7beea8 100644
--- a/docs/Config.md
+++ b/docs/Config.md
@@ -18,6 +18,7 @@
- blue
commitLength:
show: true
+ mouseEvents: true
git:
merging:
# only applicable to unix users
diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go
index ca17efd3d..50690c8c5 100644
--- a/pkg/config/app_config.go
+++ b/pkg/config/app_config.go
@@ -242,7 +242,7 @@ func GetDefaultConfig() []byte {
## stuff relating to the UI
scrollHeight: 2
scrollPastBottom: true
- mouseEvents: false # will default to true when the feature is complete
+ mouseEvents: true
theme:
lightTheme: false
activeBorderColor:
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index 063fc330c..5cf440909 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -19,6 +19,14 @@ func (gui *Gui) getSelectedBranch() *commands.Branch {
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
func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
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 {
return err
}
+
+ gui.getMainView().Title = "Log"
+
// This really shouldn't happen: there should always be a master branch
if len(gui.State.Branches) == 0 {
return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go
index 845f7b02d..ab7b56ae7 100644
--- a/pkg/gui/commit_files_panel.go
+++ b/pkg/gui/commit_files_panel.go
@@ -15,11 +15,21 @@ func (gui *Gui) getSelectedCommitFile(g *gocui.Gui) *commands.CommitFile {
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 {
if gui.popupPanelFocused() {
return nil
}
+ gui.getMainView().Title = "Patch"
+
commitFile := gui.getSelectedCommitFile(g)
if commitFile == nil {
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
@@ -96,7 +106,7 @@ func (gui *Gui) refreshCommitFilesView() error {
return err
}
- if err := gui.refreshPatchBuildingPanel(); err != nil {
+ if err := gui.refreshPatchBuildingPanel(-1); err != nil {
return err
}
@@ -177,16 +187,20 @@ func (gui *Gui) startPatchManager() 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 {
return err
}
- commitFile := gui.getSelectedCommitFile(g)
+ commitFile := gui.getSelectedCommitFile(gui.g)
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 err := gui.startPatchManager(); err != nil {
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 {
return err
}
- if err := gui.switchFocus(g, v, gui.getMainView()); err != nil {
+ if err := gui.changeContext("secondary", "patch-building"); err != nil {
+ return err
+ }
+ if err := gui.switchFocus(gui.g, gui.getCommitFilesView(), gui.getMainView()); err != nil {
return err
}
- return gui.refreshPatchBuildingPanel()
+ return gui.refreshPatchBuildingPanel(selectedLineIdx)
}
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()
- return enterTheFile()
+ return enterTheFile(selectedLineIdx)
}, nil)
}
- return enterTheFile()
+ return enterTheFile(selectedLineIdx)
}
diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go
index ee4841aab..ecc1a95ef 100644
--- a/pkg/gui/commits_panel.go
+++ b/pkg/gui/commits_panel.go
@@ -23,6 +23,14 @@ func (gui *Gui) getSelectedCommit(g *gocui.Gui) *commands.Commit {
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 {
if gui.popupPanelFocused() {
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 {
return err
}
+
+ gui.getMainView().Title = "Patch"
+ gui.getSecondaryView().Title = "Custom Patch"
+
commit := gui.getSelectedCommit(g)
if commit == nil {
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 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 {
diff --git a/pkg/gui/context.go b/pkg/gui/context.go
index 38bf7c225..fd8877ba0 100644
--- a/pkg/gui/context.go
+++ b/pkg/gui/context.go
@@ -1,44 +1,5 @@
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 {
if gui.State.Contexts[viewName] == context {
return nil
@@ -50,19 +11,20 @@ func (gui *Gui) changeContext(viewName, context string) error {
bindings := contextMap[viewName][context]
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
}
}
gui.State.Contexts[viewName] = context
- return gui.setMainTitle()
+ return nil
}
func (gui *Gui) setInitialContexts() error {
contextMap := gui.GetContextMap()
initialContexts := map[string]string{
- "main": "normal",
+ "main": "normal",
+ "secondary": "normal",
}
for viewName, context := range initialContexts {
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index f73d84cdb..6b8847e8c 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -27,24 +27,21 @@ func (gui *Gui) getSelectedFile(g *gocui.Gui) (*commands.File, error) {
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() {
return nil
}
- cx, cy := v.Cursor()
- _, oy := v.Origin()
+ prevSelectedLineIdx := gui.State.Panels.Files.SelectedLine
+ newSelectedLineIdx := v.SelectedLineIdx()
- prevSelectedLine := gui.State.Panels.Files.SelectedLine
- newSelectedLine := cy - oy
-
- if newSelectedLine > len(gui.State.Files)-1 || len(utils.Decolorise(gui.State.Files[newSelectedLine].DisplayString)) < cx {
+ if newSelectedLineIdx > len(gui.State.Files)-1 {
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)
} else {
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
if file.HasStagedChanges && file.HasUnstagedChanges {
gui.State.SplitMainPanel = true
+ gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
+ gui.getSecondaryView().Title = gui.Tr.SLocalize("StagedChanges")
} else {
gui.State.SplitMainPanel = false
if file.HasUnstagedChanges {
leftContent = content
+ gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
} else {
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 {
- 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 != gui.Errors.ErrNoFiles {
return err
@@ -197,18 +202,21 @@ func (gui *Gui) handleEnterFile(g *gocui.Gui, v *gocui.View) error {
return nil
}
if file.HasInlineMergeConflicts {
- return gui.handleSwitchToMerge(g, v)
+ return gui.handleSwitchToMerge(gui.g, gui.getFilesView())
}
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 {
return err
}
- if err := gui.switchFocus(g, v, gui.getMainView()); err != nil {
+ if err := gui.changeContext("secondary", "staging"); err != nil {
+ return err
+ }
+ if err := gui.switchFocus(gui.g, gui.getFilesView(), gui.getMainView()); err != nil {
return err
}
- return gui.refreshStagingPanel()
+ return gui.refreshStagingPanel(forceSecondaryFocused, selectedLineIdx)
}
func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 8a14fde36..b69b30965 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -118,12 +118,18 @@ type stashPanelState struct {
type menuPanelState struct {
SelectedLine int
+ OnPress func(g *gocui.Gui, v *gocui.View) error
}
type commitFilesPanelState struct {
SelectedLine int
}
+type statusPanelState struct {
+ pushables string
+ pullables string
+}
+
type panelStates struct {
Files *filePanelState
Branches *branchPanelState
@@ -133,6 +139,7 @@ type panelStates struct {
LineByLine *lineByLinePanelState
Merging *mergingPanelState
CommitFiles *commitFilesPanelState
+ Status *statusPanelState
}
type guiState struct {
@@ -179,6 +186,7 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
Conflicts: []commands.Conflict{},
EditHistory: stack.New(),
},
+ Status: &statusPanelState{},
},
}
@@ -257,7 +265,7 @@ func (gui *Gui) onFocusChange() error {
for _, view := range gui.g.Views() {
view.Highlight = view == currentView
}
- return gui.setMainTitle()
+ return nil
}
func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
@@ -683,6 +691,8 @@ func (gui *Gui) Run() error {
}
defer g.Close()
+ g.Log = gui.Log
+
if gui.Config.GetUserConfig().GetBool("gui.mouseEvents") {
g.Mouse = true
}
@@ -795,3 +805,31 @@ func (gui *Gui) setColorScheme() error {
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
+}
diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go
index 4bd28c74c..c0d9fc52c 100644
--- a/pkg/gui/keybindings.go
+++ b/pkg/gui/keybindings.go
@@ -146,6 +146,11 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleCreateOptionsMenu,
}, {
ViewName: "",
+ Key: gocui.MouseMiddle,
+ Modifier: gocui.ModNone,
+ Handler: gui.handleCreateOptionsMenu,
+ }, {
+ ViewName: "",
Key: gocui.KeyCtrlP,
Modifier: gocui.ModNone,
Handler: gui.handleCreatePatchOptionsMenu,
@@ -558,15 +563,15 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
listPanelMap := map[string]struct {
prevLine 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},
- "files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, focus: gui.handleFilesFocus},
- "branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, focus: gui.handleBranchSelect},
- "commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, focus: gui.handleCommitSelect},
- "stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, focus: gui.handleStashEntrySelect},
- "status": {focus: gui.handleStatusSelect},
- "commitFiles": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine, focus: gui.handleCommitFileSelect},
+ "menu": {prevLine: gui.handleMenuPrevLine, nextLine: gui.handleMenuNextLine, onClick: gui.handleMenuClick},
+ "files": {prevLine: gui.handleFilesPrevLine, nextLine: gui.handleFilesNextLine, onClick: gui.handleFilesClick},
+ "branches": {prevLine: gui.handleBranchesPrevLine, nextLine: gui.handleBranchesNextLine, onClick: gui.handleBranchesClick},
+ "commits": {prevLine: gui.handleCommitsPrevLine, nextLine: gui.handleCommitsNextLine, onClick: gui.handleCommitsClick},
+ "stash": {prevLine: gui.handleStashPrevLine, nextLine: gui.handleStashNextLine, onClick: gui.handleStashEntrySelect},
+ "status": {onClick: gui.handleStatusClick},
+ "commitFiles": {prevLine: gui.handleCommitFilesPrevLine, nextLine: gui.handleCommitFilesNextLine, onClick: gui.handleCommitFilesClick},
}
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: gocui.KeyArrowDown, 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 {
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": {
"normal": {
{
@@ -626,6 +649,11 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
Handler: gui.scrollUpMain,
Description: gui.Tr.SLocalize("ScrollUp"),
Alternative: "fn+down",
+ }, {
+ ViewName: "main",
+ Key: gocui.MouseLeft,
+ Modifier: gocui.ModNone,
+ Handler: gui.handleMouseDownMain,
},
},
"staging": {
@@ -658,16 +686,6 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
Modifier: gocui.ModNone,
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",
Key: gocui.KeyArrowLeft,
Modifier: gocui.ModNone,
@@ -719,6 +737,26 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleTogglePanel,
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": {
@@ -806,6 +844,26 @@ func (gui *Gui) GetContextMap() map[string]map[string][]*Binding {
Modifier: gocui.ModNone,
Handler: gui.handleToggleSelectHunk,
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": {
diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go
index f36441823..3ad105b0c 100644
--- a/pkg/gui/line_by_line_panel.go
+++ b/pkg/gui/line_by_line_panel.go
@@ -21,7 +21,7 @@ const (
// 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
-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
patchParser, err := commands.NewPatchParser(gui.Log, diff)
@@ -33,11 +33,14 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
return true, nil
}
- var selectedLineIdx int
var firstLineIdx int
var lastLineIdx int
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 {
// 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
@@ -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 {
- return gui.handleCycleLine(1)
+ return gui.handleCycleLine(+1)
}
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 {
- 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
- newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, change)
state.SelectedLineIdx = state.PatchParser.GetNextStageableLineIndex(newHunk.FirstLineIdx)
if state.SelectMode == HUNK {
state.FirstLineIdx, state.LastLineIdx = newHunk.FirstLineIdx, newHunk.LastLineIdx
@@ -128,10 +136,16 @@ func (gui *Gui) handleCycleLine(change int) error {
state := gui.State.Panels.LineByLine
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 {
newSelectedLineIdx = 0
} else if newSelectedLineIdx > len(state.PatchParser.PatchLines)-1 {
@@ -158,6 +172,54 @@ func (gui *Gui) handleCycleLine(change int) error {
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 {
state := gui.State.Panels.LineByLine
diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go
index 2d08a010b..f15b99d76 100644
--- a/pkg/gui/menu_panel.go
+++ b/pkg/gui/menu_panel.go
@@ -82,7 +82,9 @@ func (gui *Gui) createMenu(title string, items interface{}, itemCount int, handl
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)
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
}
+
+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)
+}
diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go
index 5667b45da..a4b4de3eb 100644
--- a/pkg/gui/patch_building_panel.go
+++ b/pkg/gui/patch_building_panel.go
@@ -4,13 +4,16 @@ import (
"github.com/jesseduffield/gocui"
)
-func (gui *Gui) refreshPatchBuildingPanel() error {
+func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error {
if !gui.GitCommand.PatchManager.CommitSelected() {
return gui.handleEscapePatchBuildingPanel(gui.g, nil)
}
gui.State.SplitMainPanel = true
+ gui.getMainView().Title = "Patch"
+ gui.getSecondaryView().Title = "Custom Patch"
+
// get diff from commit file that's currently selected
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
@@ -27,7 +30,7 @@ func (gui *Gui) refreshPatchBuildingPanel() error {
return err
}
- empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, false)
+ empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, false, selectedLineIdx)
if err != nil {
return err
}
@@ -54,7 +57,7 @@ func (gui *Gui) handleAddSelectionToPatch(g *gocui.Gui, v *gocui.View) error {
return err
}
- if err := gui.refreshPatchBuildingPanel(); err != nil {
+ if err := gui.refreshPatchBuildingPanel(-1); err != nil {
return err
}
@@ -76,7 +79,7 @@ func (gui *Gui) handleRemoveSelectionFromPatch(g *gocui.Gui, v *gocui.View) erro
return err
}
- if err := gui.refreshPatchBuildingPanel(); err != nil {
+ if err := gui.refreshPatchBuildingPanel(-1); err != nil {
return err
}
diff --git a/pkg/gui/rebase_options_panel.go b/pkg/gui/rebase_options_panel.go
index bc3dd13f0..bf29d19c3 100644
--- a/pkg/gui/rebase_options_panel.go
+++ b/pkg/gui/rebase_options_panel.go