1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-19 21:28:28 +02:00

paging keybindings for line by line panel

support searching in line by line panel

move mutexes into their own struct

add line by line panel mutex

apply LBL panel mutex

bump gocui to prevent crashing when search item count decreases
This commit is contained in:
Jesse Duffield 2020-10-02 07:56:14 +10:00
parent 40c5cd4b4b
commit 2e05ac0c90
14 changed files with 292 additions and 165 deletions

View File

@ -15,7 +15,7 @@ func (gui *Gui) getSelectedCommitFile() *models.CommitFile {
}
func (gui *Gui) handleCommitFileSelect() error {
gui.handleEscapeLineByLinePanel()
gui.escapeLineByLinePanel()
commitFile := gui.getSelectedCommitFile()
if commitFile == nil {

View File

@ -31,7 +31,7 @@ func (gui *Gui) handleCommitSelect() error {
}()
}
gui.handleEscapeLineByLinePanel()
gui.escapeLineByLinePanel()
var task updateTask
commit := gui.getSelectedLocalCommit()
@ -110,8 +110,8 @@ func (gui *Gui) refreshCommits() error {
}
func (gui *Gui) refreshCommitsWithLimit() error {
gui.State.BranchCommitsMutex.Lock()
defer gui.State.BranchCommitsMutex.Unlock()
gui.State.Mutexes.BranchCommitsMutex.Lock()
defer gui.State.Mutexes.BranchCommitsMutex.Unlock()
builder := commands.NewCommitListBuilder(gui.Log, gui.GitCommand, gui.OSCommand, gui.Tr)
@ -132,8 +132,8 @@ func (gui *Gui) refreshCommitsWithLimit() error {
}
func (gui *Gui) refreshRebaseCommits() error {
gui.State.BranchCommitsMutex.Lock()
defer gui.State.BranchCommitsMutex.Unlock()
gui.State.Mutexes.BranchCommitsMutex.Lock()
defer gui.State.Mutexes.BranchCommitsMutex.Unlock()
builder := commands.NewCommitListBuilder(gui.Log, gui.GitCommand, gui.OSCommand, gui.Tr)

View File

@ -81,11 +81,11 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
}
func (gui *Gui) refreshFilesAndSubmodules() error {
gui.State.RefreshingFilesMutex.Lock()
gui.State.Mutexes.RefreshingFilesMutex.Lock()
gui.State.IsRefreshingFiles = true
defer func() {
gui.State.IsRefreshingFiles = false
gui.State.RefreshingFilesMutex.Unlock()
gui.State.Mutexes.RefreshingFilesMutex.Unlock()
}()
selectedFile := gui.getSelectedFile()
@ -517,8 +517,8 @@ func (gui *Gui) pullFiles(opts PullFilesOptions) error {
}
func (gui *Gui) pullWithMode(mode string, opts PullFilesOptions) error {
gui.State.FetchMutex.Lock()
defer gui.State.FetchMutex.Unlock()
gui.State.Mutexes.FetchMutex.Lock()
defer gui.State.Mutexes.FetchMutex.Unlock()
err := gui.GitCommand.Fetch(
commands.FetchOptions{

View File

@ -164,8 +164,8 @@ func (gui *Gui) handleInfoClick(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) fetch(canPromptForCredentials bool) (err error) {
gui.State.FetchMutex.Lock()
defer gui.State.FetchMutex.Unlock()
gui.State.Mutexes.FetchMutex.Lock()
defer gui.State.Mutexes.FetchMutex.Unlock()
fetchOpts := commands.FetchOptions{}
if canPromptForCredentials {

View File

@ -285,6 +285,14 @@ type Modes struct {
Diffing Diffing
}
type guiStateMutexes struct {
RefreshingFilesMutex sync.Mutex
RefreshingStatusMutex sync.Mutex
FetchMutex sync.Mutex
BranchCommitsMutex sync.Mutex
LineByLinePanelMutex sync.Mutex
}
type guiState struct {
Files []*models.File
Submodules []*models.SubmoduleConfig
@ -298,30 +306,27 @@ type guiState struct {
// ReflogCommits are the ones used by the branches panel to obtain recency values
// if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be
// one and the same
ReflogCommits []*models.Commit
SubCommits []*models.Commit
Remotes []*models.Remote
RemoteBranches []*models.RemoteBranch
Tags []*models.Tag
MenuItems []*menuItem
Updating bool
Panels *panelStates
MainContext string // used to keep the main and secondary views' contexts in sync
SplitMainPanel bool
RetainOriginalDir bool
IsRefreshingFiles bool
RefreshingFilesMutex sync.Mutex
RefreshingStatusMutex sync.Mutex
FetchMutex sync.Mutex
BranchCommitsMutex sync.Mutex
Searching searchingState
ScreenMode int
SideView *gocui.View
Ptmx *os.File
PrevMainWidth int
PrevMainHeight int
OldInformation string
StartupStage int // one of INITIAL and COMPLETE. Allows us to not load everything at once
ReflogCommits []*models.Commit
SubCommits []*models.Commit
Remotes []*models.Remote
RemoteBranches []*models.RemoteBranch
Tags []*models.Tag
MenuItems []*menuItem
Updating bool
Panels *panelStates
MainContext string // used to keep the main and secondary views' contexts in sync
SplitMainPanel bool
RetainOriginalDir bool
IsRefreshingFiles bool
Mutexes guiStateMutexes
Searching searchingState
ScreenMode int
SideView *gocui.View
Ptmx *os.File
PrevMainWidth int
PrevMainHeight int
OldInformation string
StartupStage int // one of INITIAL and COMPLETE. Allows us to not load everything at once
Modes Modes

View File

@ -1147,14 +1147,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.PrevItem),
Handler: gui.handleSelectPrevLine,
Handler: gui.wrappedHandler(gui.handleSelectPrevLine),
Description: gui.Tr.PrevLine,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextItem),
Handler: gui.handleSelectNextLine,
Handler: gui.wrappedHandler(gui.handleSelectNextLine),
Description: gui.Tr.NextLine,
},
{
@ -1162,56 +1162,56 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.PrevItemAlt),
Modifier: gocui.ModNone,
Handler: gui.handleSelectPrevLine,
Handler: gui.wrappedHandler(gui.handleSelectPrevLine),
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextItemAlt),
Modifier: gocui.ModNone,
Handler: gui.handleSelectNextLine,
Handler: gui.wrappedHandler(gui.handleSelectNextLine),
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gocui.MouseWheelUp,
Modifier: gocui.ModNone,
Handler: gui.handleSelectPrevLine,
Handler: gui.wrappedHandler(gui.handleSelectPrevLine),
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gocui.MouseWheelDown,
Modifier: gocui.ModNone,
Handler: gui.handleSelectNextLine,
Handler: gui.wrappedHandler(gui.handleSelectNextLine),
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.PrevBlock),
Handler: gui.handleSelectPrevHunk,
Handler: gui.wrappedHandler(gui.handleSelectPrevHunk),
Description: gui.Tr.PrevHunk,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextBlock),
Handler: gui.handleSelectNextHunk,
Description: gui.Tr.NextHunk,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.PrevBlockAlt),
Modifier: gocui.ModNone,
Handler: gui.handleSelectPrevHunk,
Handler: gui.wrappedHandler(gui.handleSelectPrevHunk),
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextBlock),
Handler: gui.wrappedHandler(gui.handleSelectNextHunk),
Description: gui.Tr.NextHunk,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextBlockAlt),
Modifier: gocui.ModNone,
Handler: gui.handleSelectNextHunk,
Handler: gui.wrappedHandler(gui.handleSelectNextHunk),
},
{
ViewName: "main",
@ -1227,6 +1227,50 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleFileOpen,
Description: gui.Tr.LcOpenFile,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.NextPage),
Modifier: gocui.ModNone,
Handler: gui.wrappedHandler(gui.handleLineByLineNextPage),
Description: gui.Tr.LcNextPage,
Tag: "navigation",
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.PrevPage),
Modifier: gocui.ModNone,
Handler: gui.wrappedHandler(gui.handleLineByLinePrevPage),
Description: gui.Tr.LcPrevPage,
Tag: "navigation",
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.GotoTop),
Modifier: gocui.ModNone,
Handler: gui.wrappedHandler(gui.handleLineByLineGotoTop),
Description: gui.Tr.LcGotoTop,
Tag: "navigation",
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.GotoBottom),
Modifier: gocui.ModNone,
Handler: gui.wrappedHandler(gui.handleLineByLineGotoBottom),
Description: gui.Tr.LcGotoBottom,
Tag: "navigation",
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Universal.StartSearch),
Handler: gui.handleOpenSearch,
Description: gui.Tr.LcStartSearch,
Tag: "navigation",
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY},
@ -1238,7 +1282,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Main.ToggleDragSelect),
Handler: gui.handleToggleSelectRange,
Handler: gui.wrappedHandler(gui.handleToggleSelectRange),
Description: gui.Tr.ToggleDragSelect,
},
// Alias 'V' -> 'v'
@ -1246,14 +1290,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Main.ToggleDragSelectAlt),
Handler: gui.handleToggleSelectRange,
Handler: gui.wrappedHandler(gui.handleToggleSelectRange),
Description: gui.Tr.ToggleDragSelect,
},
{
ViewName: "main",
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gui.getKey(config.Main.ToggleSelectHunk),
Handler: gui.handleToggleSelectHunk,
Handler: gui.wrappedHandler(gui.handleToggleSelectHunk),
Description: gui.Tr.ToggleSelectHunk,
},
{
@ -1261,7 +1305,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Contexts: []string{MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY},
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleMouseDown,
Handler: gui.handleLBLMouseDown,
},
{
ViewName: "main",

View File

@ -317,6 +317,8 @@ func (gui *Gui) layout(g *gocui.Gui) error {
listContextState.view.SetOnSelectItem(gui.onSelectItemWrapper(listContextState.listContext.onSearchSelect))
}
gui.getMainView().SetOnSelectItem(gui.onSelectItemWrapper(gui.handlelineByLineNavigateTo))
mainViewWidth, mainViewHeight := gui.getMainView().Size()
if mainViewWidth != gui.State.PrevMainWidth || mainViewHeight != gui.State.PrevMainHeight {
gui.State.PrevMainWidth = mainViewWidth

View File

@ -25,6 +25,9 @@ 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, selectedLineIdx int) (bool, error) {
gui.State.Mutexes.LineByLinePanelMutex.Lock()
defer gui.State.Mutexes.LineByLinePanelMutex.Unlock()
state := gui.State.Panels.LineByLine
patchParser, err := patch.NewPatchParser(gui.Log, diff)
@ -98,26 +101,32 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
return false, nil
}
func (gui *Gui) handleSelectPrevLine(g *gocui.Gui, v *gocui.View) error {
return gui.handleCycleLine(-1)
func (gui *Gui) handleSelectPrevLine() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
return gui.LBLCycleLine(-1)
})
}
func (gui *Gui) handleSelectNextLine(g *gocui.Gui, v *gocui.View) error {
return gui.handleCycleLine(+1)
func (gui *Gui) handleSelectNextLine() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
return gui.LBLCycleLine(+1)
})
}
func (gui *Gui) handleSelectPrevHunk(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, -1)
func (gui *Gui) handleSelectPrevHunk() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, -1)
return gui.selectNewHunk(newHunk)
return gui.selectNewHunk(newHunk)
})
}
func (gui *Gui) handleSelectNextHunk(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 1)
func (gui *Gui) handleSelectNextHunk() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
newHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 1)
return gui.selectNewHunk(newHunk)
return gui.selectNewHunk(newHunk)
})
}
func (gui *Gui) selectNewHunk(newHunk *patch.PatchHunk) error {
@ -136,7 +145,7 @@ func (gui *Gui) selectNewHunk(newHunk *patch.PatchHunk) error {
return gui.focusSelection(true)
}
func (gui *Gui) handleCycleLine(change int) error {
func (gui *Gui) LBLCycleLine(change int) error {
state := gui.State.Panels.LineByLine
if state.SelectMode == HUNK {
@ -144,10 +153,10 @@ func (gui *Gui) handleCycleLine(change int) error {
return gui.selectNewHunk(newHunk)
}
return gui.handleSelectNewLine(state.SelectedLineIdx + change)
return gui.LBLSelectLine(state.SelectedLineIdx + change)
}
func (gui *Gui) handleSelectNewLine(newSelectedLineIdx int) error {
func (gui *Gui) LBLSelectLine(newSelectedLineIdx int) error {
state := gui.State.Panels.LineByLine
if newSelectedLineIdx < 0 {
@ -176,52 +185,54 @@ func (gui *Gui) handleSelectNewLine(newSelectedLineIdx int) error {
return gui.focusSelection(false)
}
func (gui *Gui) handleMouseDown(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
func (gui *Gui) handleLBLMouseDown(g *gocui.Gui, v *gocui.View) error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
if gui.popupPanelFocused() {
return nil
}
if gui.popupPanelFocused() {
return nil
}
newSelectedLineIdx := v.SelectedLineIdx()
state.FirstLineIdx = newSelectedLineIdx
state.LastLineIdx = newSelectedLineIdx
newSelectedLineIdx := v.SelectedLineIdx()
state.FirstLineIdx = newSelectedLineIdx
state.LastLineIdx = newSelectedLineIdx
state.SelectMode = RANGE
state.SelectMode = RANGE
return gui.handleSelectNewLine(newSelectedLineIdx)
return gui.LBLSelectLine(newSelectedLineIdx)
})
}
func (gui *Gui) handleMouseDrag(g *gocui.Gui, v *gocui.View) error {
if gui.popupPanelFocused() {
return nil
}
return gui.withLBLActiveCheck(func(*lineByLinePanelState) error {
if gui.popupPanelFocused() {
return nil
}
return gui.handleSelectNewLine(v.SelectedLineIdx())
return gui.LBLSelectLine(v.SelectedLineIdx())
})
}
func (gui *Gui) handleMouseScrollUp(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
if gui.popupPanelFocused() {
return nil
}
if gui.popupPanelFocused() {
return nil
}
state.SelectMode = LINE
state.SelectMode = LINE
return gui.handleCycleLine(-1)
return gui.LBLCycleLine(-1)
})
}
func (gui *Gui) handleMouseScrollDown(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
if gui.popupPanelFocused() {
return nil
}
if gui.popupPanelFocused() {
return nil
}
state.SelectMode = LINE
state.SelectMode = LINE
return gui.handleCycleLine(1)
return gui.LBLCycleLine(1)
})
}
func (gui *Gui) getSelectedCommitFileName() string {
@ -297,65 +308,123 @@ func (gui *Gui) focusSelection(includeCurrentHunk bool) error {
return nil
}
func (gui *Gui) handleToggleSelectRange(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
if state.SelectMode == RANGE {
state.SelectMode = LINE
} else {
state.SelectMode = RANGE
}
state.FirstLineIdx, state.LastLineIdx = state.SelectedLineIdx, state.SelectedLineIdx
return gui.refreshMainViewForLineByLine()
}
func (gui *Gui) handleToggleSelectHunk(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
if state.SelectMode == HUNK {
state.SelectMode = LINE
func (gui *Gui) handleToggleSelectRange() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
if state.SelectMode == RANGE {
state.SelectMode = LINE
} else {
state.SelectMode = RANGE
}
state.FirstLineIdx, state.LastLineIdx = state.SelectedLineIdx, state.SelectedLineIdx
} else {
state.SelectMode = HUNK
selectedHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0)
state.FirstLineIdx, state.LastLineIdx = selectedHunk.FirstLineIdx, selectedHunk.LastLineIdx()
}
if err := gui.refreshMainViewForLineByLine(); err != nil {
return err
}
return gui.focusSelection(state.SelectMode == HUNK)
return gui.refreshMainViewForLineByLine()
})
}
func (gui *Gui) handleEscapeLineByLinePanel() {
gui.State.Panels.LineByLine = nil
func (gui *Gui) handleToggleSelectHunk() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
if state.SelectMode == HUNK {
state.SelectMode = LINE
state.FirstLineIdx, state.LastLineIdx = state.SelectedLineIdx, state.SelectedLineIdx
} else {
state.SelectMode = HUNK
selectedHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0)
state.FirstLineIdx, state.LastLineIdx = selectedHunk.FirstLineIdx, selectedHunk.LastLineIdx()
}
if err := gui.refreshMainViewForLineByLine(); err != nil {
return err
}
return gui.focusSelection(state.SelectMode == HUNK)
})
}
func (gui *Gui) escapeLineByLinePanel() {
gui.withLBLActiveCheck(func(*lineByLinePanelState) error {
gui.State.Panels.LineByLine = nil
return nil
})
}
func (gui *Gui) handleOpenFileAtLine() error {
// again, would be good to use inheritance here (or maybe even composition)
var filename string
switch gui.State.MainContext {
case gui.Contexts.PatchBuilding.Context.GetKey():
filename = gui.getSelectedCommitFileName()
case gui.Contexts.Staging.Context.GetKey():
file := gui.getSelectedFile()
if file == nil {
return nil
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
// again, would be good to use inheritance here (or maybe even composition)
var filename string
switch gui.State.MainContext {
case gui.Contexts.PatchBuilding.Context.GetKey():
filename = gui.getSelectedCommitFileName()
case gui.Contexts.Staging.Context.GetKey():
file := gui.getSelectedFile()
if file == nil {
return nil
}
filename = file.Name
default:
return errors.Errorf("unknown main context: %s", gui.State.MainContext)
}
filename = file.Name
default:
return errors.Errorf("unknown main context: %s", gui.State.MainContext)
}
// need to look at current index, then work out what my hunk's header information is, and see how far my line is away from the hunk header
selectedHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0)
lineNumber := selectedHunk.LineNumberOfLine(state.SelectedLineIdx)
filenameWithLineNum := fmt.Sprintf("%s:%d", filename, lineNumber)
if err := gui.OSCommand.OpenFile(filenameWithLineNum); err != nil {
return err
}
return nil
})
}
func (gui *Gui) handleLineByLineNextPage() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
newSelectedLineIdx := state.SelectedLineIdx + gui.pageDelta(gui.getMainView())
return gui.lineByLineNavigateTo(newSelectedLineIdx)
})
}
func (gui *Gui) handleLineByLinePrevPage() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
newSelectedLineIdx := state.SelectedLineIdx - gui.pageDelta(gui.getMainView())
return gui.lineByLineNavigateTo(newSelectedLineIdx)
})
}
func (gui *Gui) handleLineByLineGotoBottom() error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
newSelectedLineIdx := len(state.PatchParser.PatchLines) - 1
return gui.lineByLineNavigateTo(newSelectedLineIdx)
})
}
func (gui *Gui) handleLineByLineGotoTop() error {
return gui.lineByLineNavigateTo(0)
}
func (gui *Gui) handlelineByLineNavigateTo(selectedLineIdx int) error {
return gui.withLBLActiveCheck(func(state *lineByLinePanelState) error {
return gui.lineByLineNavigateTo(selectedLineIdx)
})
}
func (gui *Gui) lineByLineNavigateTo(selectedLineIdx int) error {
state := gui.State.Panels.LineByLine
state.SelectMode = LINE
return gui.LBLSelectLine(selectedLineIdx)
}
func (gui *Gui) withLBLActiveCheck(f func(*lineByLinePanelState) error) error {
gui.State.Mutexes.LineByLinePanelMutex.Lock()
defer gui.State.Mutexes.LineByLinePanelMutex.Unlock()
state := gui.State.Panels.LineByLine
// need to look at current index, then work out what my hunk's header information is, and see how far my line is away from the hunk header
selectedHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0)
lineNumber := selectedHunk.LineNumberOfLine(state.SelectedLineIdx)
filenameWithLineNum := fmt.Sprintf("%s:%d", filename, lineNumber)
if err := gui.OSCommand.OpenFile(filenameWithLineNum); err != nil {
return err
if state == nil {
return nil
}
return nil
return f(state)
}

View File

@ -186,11 +186,8 @@ func (lc *ListContext) handleNextPage(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return nil
}
_, height := view.Size()
delta := height - 1
if delta == 0 {
delta = 1
}
delta := lc.Gui.pageDelta(view)
return lc.handleLineChange(delta)
}
@ -207,11 +204,9 @@ func (lc *ListContext) handlePrevPage(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return nil
}
_, height := view.Size()
delta := height - 1
if delta == 0 {
delta = 1
}
delta := lc.Gui.pageDelta(view)
return lc.handleLineChange(-delta)
}

View File

@ -92,7 +92,7 @@ func (gui *Gui) handleToggleSelectionForPatch(g *gocui.Gui, v *gocui.View) error
}
func (gui *Gui) handleEscapePatchBuildingPanel() error {
gui.handleEscapeLineByLinePanel()
gui.escapeLineByLinePanel()
if gui.GitCommand.PatchManager.IsEmpty() {
gui.GitCommand.PatchManager.Reset()

View File

@ -158,8 +158,8 @@ func (gui *Gui) handleFetchRemote(g *gocui.Gui, v *gocui.View) error {
}
return gui.WithWaitingStatus(gui.Tr.FetchingRemoteStatus, func() error {
gui.State.FetchMutex.Lock()
defer gui.State.FetchMutex.Unlock()
gui.State.Mutexes.FetchMutex.Lock()
defer gui.State.Mutexes.FetchMutex.Unlock()
// TODO: test this
err := gui.GitCommand.FetchRemote(remote.Name, gui.promptUserForCredential)

View File

@ -84,7 +84,7 @@ func (gui *Gui) handleTogglePanel(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleStagingEscape() error {
gui.handleEscapeLineByLinePanel()
gui.escapeLineByLinePanel()
return gui.switchContext(gui.Contexts.Files.Context)
}

View File

@ -12,8 +12,8 @@ import (
// never call this on its own, it should only be called from within refreshCommits()
func (gui *Gui) refreshStatus() {
gui.State.RefreshingStatusMutex.Lock()
defer gui.State.RefreshingStatusMutex.Unlock()
gui.State.Mutexes.RefreshingStatusMutex.Lock()
defer gui.State.Mutexes.RefreshingStatusMutex.Unlock()
currentBranch := gui.currentBranch()
if currentBranch == nil {

View File

@ -433,3 +433,15 @@ func (gui *Gui) handlePrevTab(g *gocui.Gui, v *gocui.View) error {
utils.ModuloWithWrap(v.TabIndex-1, len(v.Tabs)),
)
}
// this is the distance we will move the cursor when paging up or down in a view
func (gui *Gui) pageDelta(view *gocui.View) int {
_, height := view.Size()
delta := height - 1
if delta == 0 {
return 1
}
return delta
}