diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2019-11-05 14:21:19 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2019-11-05 19:22:01 +1100 |
commit | 6d5d054c30050bc66c9c3e8697982c6c801a2a62 (patch) | |
tree | 58e08dbfadbfb0af55799e810b1f684e8e1d5527 /pkg/gui/staging_panel.go | |
parent | 234415537943c090a3f9c3fa3ad7889b6998f9d2 (diff) |
support line by line additions in staging and patch building contexts
Diffstat (limited to 'pkg/gui/staging_panel.go')
-rw-r--r-- | pkg/gui/staging_panel.go | 345 |
1 files changed, 36 insertions, 309 deletions
diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go index 47240d87e..55d38f282 100644 --- a/pkg/gui/staging_panel.go +++ b/pkg/gui/staging_panel.go @@ -1,329 +1,87 @@ package gui import ( + "strings" + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" ) -// these represent what select mode we're in -const ( - LINE = iota - RANGE - HUNK -) - func (gui *Gui) refreshStagingPanel() error { - state := gui.State.Panels.Staging - - // file, err := gui.getSelectedFile(gui.g) - // if err != nil { - // if err != gui.Errors.ErrNoFiles { - // return err - // } - // return gui.handleStagingEscape(gui.g, nil) - // } - gui.State.SplitMainPanel = true - secondaryFocused := false - if state != nil { - secondaryFocused = state.SecondaryFocused - } - - // if !file.HasUnstagedChanges && !file.HasStagedChanges { - // return gui.handleStagingEscape(gui.g, nil) - // } - - // if (secondaryFocused && !file.HasStagedChanges) || (!secondaryFocused && !file.HasUnstagedChanges) { - // secondaryFocused = !secondaryFocused - // } - - // getDiffs := func() (string, string) { - // // 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) - // secondaryColorDiff := gui.GitCommand.Diff(file, false, !secondaryFocused) - // return diff, secondaryColorDiff - // } - - // diff, secondaryColorDiff := getDiffs() - - // // if we have e.g. a deleted file with nothing else to the diff will have only - // // 4-5 lines in which case we'll swap panels - // if len(strings.Split(diff, "\n")) < 5 { - // if len(strings.Split(secondaryColorDiff, "\n")) < 5 { - // return gui.handleStagingEscape(gui.g, nil) - // } - // secondaryFocused = !secondaryFocused - // diff, secondaryColorDiff = getDiffs() - // } - - // get diff from commit file that's currently selected - commitFile := gui.getSelectedCommitFile(gui.g) - if commitFile == nil { - return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) - } - - diff, err := gui.GitCommand.ShowCommitFile(commitFile.Sha, commitFile.Name, true) - if err != nil { - return err - } + state := gui.State.Panels.LineByLine - secondaryColorDiff := gui.GitCommand.PatchManager.RenderPatchForFile(commitFile.Name, false, false, true) - if err != nil { - return err - } - - patchParser, err := commands.NewPatchParser(gui.Log, diff) + file, err := gui.getSelectedFile(gui.g) if err != nil { - return nil + if err != gui.Errors.ErrNoFiles { + return err + } + return gui.handleStagingEscape(gui.g, nil) } - if len(patchParser.StageableLines) == 0 { + if !file.HasUnstagedChanges && !file.HasStagedChanges { return gui.handleStagingEscape(gui.g, nil) } - var selectedLineIdx int - var firstLineIdx int - var lastLineIdx int - selectMode := LINE + secondaryFocused := false 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 - // finding the next stageable line, then getting its containing hunk - // in the new diff - selectMode = HUNK - prevNewHunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0) - selectedLineIdx = patchParser.GetNextStageableLineIndex(prevNewHunk.FirstLineIdx) - newHunk := patchParser.GetHunkContainingLine(selectedLineIdx, 0) - firstLineIdx, lastLineIdx = newHunk.FirstLineIdx, newHunk.LastLineIdx - } else { - selectedLineIdx = patchParser.GetNextStageableLineIndex(state.SelectedLineIdx) - firstLineIdx, lastLineIdx = selectedLineIdx, selectedLineIdx - } - } else { - selectedLineIdx = patchParser.StageableLines[0] - firstLineIdx, lastLineIdx = selectedLineIdx, selectedLineIdx + secondaryFocused = state.SecondaryFocused } - gui.State.Panels.Staging = &stagingPanelState{ - PatchParser: patchParser, - SelectedLineIdx: selectedLineIdx, - SelectMode: selectMode, - FirstLineIdx: firstLineIdx, - LastLineIdx: lastLineIdx, - Diff: diff, - SecondaryFocused: secondaryFocused, + if (secondaryFocused && !file.HasStagedChanges) || (!secondaryFocused && !file.HasUnstagedChanges) { + secondaryFocused = !secondaryFocused } - if err := gui.refreshView(); err != nil { - return err + // 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) + secondaryDiff := gui.GitCommand.Diff(file, true, !secondaryFocused) + + // if we have e.g. a deleted file with nothing else to the diff will have only + // 4-5 lines in which case we'll swap panels + if len(strings.Split(diff, "\n")) < 5 { + if len(strings.Split(secondaryDiff, "\n")) < 5 { + return gui.handleStagingEscape(gui.g, nil) + } + secondaryFocused = !secondaryFocused + diff, secondaryDiff = secondaryDiff, diff } - if err := gui.focusSelection(selectMode == HUNK); err != nil { + empty, err := gui.refreshLineByLinePanel(diff, secondaryDiff, secondaryFocused) + if err != nil { return err } - secondaryView := gui.getSecondaryView() - secondaryView.Highlight = true - secondaryView.Wrap = false - - gui.g.Update(func(*gocui.Gui) error { - return gui.setViewContent(gui.g, gui.getSecondaryView(), secondaryColorDiff) - }) + if empty { + return gui.handleStagingEscape(gui.g, nil) + } return nil } func (gui *Gui) handleTogglePanel(g *gocui.Gui, v *gocui.View) error { - state := gui.State.Panels.Staging + state := gui.State.Panels.LineByLine state.SecondaryFocused = !state.SecondaryFocused return gui.refreshStagingPanel() } func (gui *Gui) handleStagingEscape(g *gocui.Gui, v *gocui.View) error { - gui.State.Panels.Staging = nil - - return gui.switchFocus(gui.g, nil, gui.getCommitFilesView()) -} - -func (gui *Gui) handleStagingPrevLine(g *gocui.Gui, v *gocui.View) error { - return gui.handleCycleLine(-1) -} + gui.State.Panels.LineByLine = nil -func (gui *Gui) handleStagingNextLine(g *gocui.Gui, v *gocui.View) error { - return gui.handleCycleLine(1) -} - -func (gui *Gui) handleStagingPrevHunk(g *gocui.Gui, v *gocui.View) error { - return gui.handleCycleHunk(-1) -} - -func (gui *Gui) handleStagingNextHunk(g *gocui.Gui, v *gocui.View) error { - return gui.handleCycleHunk(1) -} - -func (gui *Gui) handleCycleHunk(change int) error { - state := gui.State.Panels.Staging - 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 - } else { - state.FirstLineIdx, state.LastLineIdx = state.SelectedLineIdx, state.SelectedLineIdx - } - - if err := gui.refreshView(); err != nil { - return err - } - - return gui.focusSelection(true) -} - -func (gui *Gui) handleCycleLine(change int) error { - state := gui.State.Panels.Staging - - if state.SelectMode == HUNK { - return gui.handleCycleHunk(change) - } - - newSelectedLineIdx := state.SelectedLineIdx + change - if newSelectedLineIdx < 0 { - newSelectedLineIdx = 0 - } else if newSelectedLineIdx > len(state.PatchParser.PatchLines)-1 { - newSelectedLineIdx = len(state.PatchParser.PatchLines) - 1 - } - - state.SelectedLineIdx = newSelectedLineIdx - - if state.SelectMode == RANGE { - if state.SelectedLineIdx < state.FirstLineIdx { - state.FirstLineIdx = state.SelectedLineIdx - } else { - state.LastLineIdx = state.SelectedLineIdx - } - } else { - state.LastLineIdx = state.SelectedLineIdx - state.FirstLineIdx = state.SelectedLineIdx - } - - if err := gui.refreshView(); err != nil { - return err - } - - return gui.focusSelection(false) -} - -func (gui *Gui) refreshView() error { - state := gui.State.Panels.Staging - - filename := gui.State.CommitFiles[gui.State.Panels.CommitFiles.SelectedLine].Name - - colorDiff := state.PatchParser.Render(state.FirstLineIdx, state.LastLineIdx, gui.GitCommand.PatchManager.GetFileIncLineIndices(filename)) - - mainView := gui.getMainView() - mainView.Highlight = true - mainView.Wrap = false - - gui.g.Update(func(*gocui.Gui) error { - return gui.setViewContent(gui.g, gui.getMainView(), colorDiff) - }) - - return nil -} - -// focusSelection works out the best focus for the staging panel given the -// selected line and size of the hunk -func (gui *Gui) focusSelection(includeCurrentHunk bool) error { - stagingView := gui.getMainView() - state := gui.State.Panels.Staging - - _, viewHeight := stagingView.Size() - bufferHeight := viewHeight - 1 - _, origin := stagingView.Origin() - - firstLineIdx := state.SelectedLineIdx - lastLineIdx := state.SelectedLineIdx - - if includeCurrentHunk { - hunk := state.PatchParser.GetHunkContainingLine(state.SelectedLineIdx, 0) - firstLineIdx = hunk.FirstLineIdx - lastLineIdx = hunk.LastLineIdx - } - - margin := 0 // we may want to have a margin in place to show context but right now I'm thinking we keep this at zero - - var newOrigin int - if firstLineIdx-origin < margin { - newOrigin = firstLineIdx - margin - } else if lastLineIdx-origin > bufferHeight-margin { - newOrigin = lastLineIdx - bufferHeight + margin - } else { - newOrigin = origin - } - - gui.g.Update(func(*gocui.Gui) error { - if err := stagingView.SetOrigin(0, newOrigin); err != nil { - return err - } - - return stagingView.SetCursor(0, state.SelectedLineIdx-newOrigin) - }) - - return nil + return gui.switchFocus(gui.g, nil, gui.getFilesView()) } func (gui *Gui) handleStageSelection(g *gocui.Gui, v *gocui.View) error { - state := gui.State.Panels.Staging - - // add range of lines to those set for the file - commitFile := gui.getSelectedCommitFile(gui.g) - if commitFile == nil { - return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) - } - - gui.GitCommand.PatchManager.AddFileLineRange(commitFile.Name, state.FirstLineIdx, state.LastLineIdx) - - if err := gui.refreshCommitFilesView(); err != nil { - return err - } - - if err := gui.refreshStagingPanel(); err != nil { - return err - } - - return nil - - // return gui.applySelection(false) + return gui.applySelection(false) } func (gui *Gui) handleResetSelection(g *gocui.Gui, v *gocui.View) error { - state := gui.State.Panels.Staging - - // add range of lines to those set for the file - commitFile := gui.getSelectedCommitFile(gui.g) - if commitFile == nil { - return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles")) - } - - gui.GitCommand.PatchManager.RemoveFileLineRange(commitFile.Name, state.FirstLineIdx, state.LastLineIdx) - - if err := gui.refreshCommitFilesView(); err != nil { - return err - } - - if err := gui.refreshStagingPanel(); err != nil { - return err - } - - return nil - - // return gui.applySelection(true) + return gui.applySelection(true) } func (gui *Gui) applySelection(reverse bool) error { - state := gui.State.Panels.Staging + state := gui.State.Panels.LineByLine if !reverse && state.SecondaryFocused { return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("CantStageStaged")) @@ -359,34 +117,3 @@ func (gui *Gui) applySelection(reverse bool) error { } return nil } - -func (gui *Gui) handleToggleSelectRange(g *gocui.Gui, v *gocui.View) error { - state := gui.State.Panels.Staging - if state.SelectMode == RANGE { - state.SelectMode = LINE - } else { - state.SelectMode = RANGE - } - state.FirstLineIdx, state.LastLineIdx = state.SelectedLineIdx, state.SelectedLineIdx - - return gui.refreshView() -} - -func (gui *Gui) handleToggleSelectHunk(g *gocui.Gui, v *gocui.View) error { - state := gui.State.Panels.Staging - - 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.refreshView(); err != nil { - return err - } - - return gui.focusSelection(state.SelectMode == HUNK) -} |