diff options
-rw-r--r-- | docs/Config.md | 1 | ||||
-rw-r--r-- | pkg/config/app_config.go | 2 | ||||
-rw-r--r-- | pkg/gui/branches_panel.go | 11 | ||||
-rw-r--r-- | pkg/gui/commit_files_panel.go | 35 | ||||
-rw-r--r-- | pkg/gui/commits_panel.go | 14 | ||||
-rw-r--r-- | pkg/gui/context.go | 46 | ||||
-rw-r--r-- | pkg/gui/files_panel.go | 36 | ||||
-rw-r--r-- | pkg/gui/gui.go | 40 | ||||
-rw-r--r-- | pkg/gui/keybindings.go | 96 | ||||
-rw-r--r-- | pkg/gui/line_by_line_panel.go | 82 | ||||
-rw-r--r-- | pkg/gui/menu_panel.go | 16 | ||||
-rw-r--r-- | pkg/gui/patch_building_panel.go | 11 | ||||
-rw-r--r-- | pkg/gui/rebase_options_panel.go | 5 | ||||
-rw-r--r-- | pkg/gui/staging_panel.go | 40 | ||||
-rw-r--r-- | pkg/gui/stash_panel.go | 3 | ||||
-rw-r--r-- | pkg/gui/status_panel.go | 62 | ||||
-rw-r--r-- | pkg/gui/view_helpers.go | 24 | ||||
-rw-r--r-- | pkg/i18n/dutch.go | 7 | ||||
-rw-r--r-- | pkg/i18n/english.go | 7 | ||||
-rw-r--r-- | pkg/i18n/polish.go | 7 |
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 { |