summaryrefslogtreecommitdiffstats
path: root/pkg/gui/staging_panel.go
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2019-11-05 14:21:19 +1100
committerJesse Duffield <jessedduffield@gmail.com>2019-11-05 19:22:01 +1100
commit6d5d054c30050bc66c9c3e8697982c6c801a2a62 (patch)
tree58e08dbfadbfb0af55799e810b1f684e8e1d5527 /pkg/gui/staging_panel.go
parent234415537943c090a3f9c3fa3ad7889b6998f9d2 (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.go345
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)
-}