1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-31 14:24:25 +03:00
This commit is contained in:
Jesse Duffield
2020-08-18 22:02:35 +10:00
parent 3c87ff4eff
commit f5b22d94d9
14 changed files with 259 additions and 152 deletions

View File

@ -34,28 +34,24 @@ func (gui *Gui) handleBranchSelect() error {
return gui.renderDiff()
}
refreshOpts := refreshMainOpts{
main: &viewUpdateOpts{
title: "Log",
task: {
kind: RENDER_STRING,
str: gui.Tr.SLocalize("NoBranchesThisRepo"),
},
},
}
var task updateTask
branch := gui.getSelectedBranch()
if branch == nil {
refreshOpts.main.task = func() error { return gui.newStringTask("main", gui.Tr.SLocalize("NoBranchesThisRepo")) }
task = gui.createRenderStringTask(gui.Tr.SLocalize("NoBranchesThisRepo"))
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(branch.Name),
)
refreshOpts.main.task = func() error { return gui.newPtyTask("main", cmd) }
task = gui.createRunPtyTask(cmd)
}
return gui.refreshMain(refreshOpts)
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Log",
task: task,
},
})
}
// gui.refreshStatus is called at the end of this because that's when we can

View File

@ -21,29 +21,29 @@ func (gui *Gui) handleCommitFileSelect() error {
return nil
}
gui.getMainView().Title = "Patch"
if gui.currentViewName() == "commitFiles" {
gui.handleEscapeLineByLinePanel()
}
commitFile := gui.getSelectedCommitFile()
if commitFile == nil {
// TODO: consider making it so that we can also render strings to our own view through some common interface, or just render this to the main view for consistency
gui.renderString("commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
if err := gui.refreshSecondaryPatchPanel(); err != nil {
return err
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCommitFileCmdStr(commitFile.Sha, commitFile.Name, false),
)
if err := gui.newPtyTask("main", cmd); err != nil {
gui.Log.Error(err)
}
task := gui.createRunPtyTask(cmd)
return nil
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Patch",
task: task,
},
secondary: gui.secondaryPatchPanelUpdateOpts(),
})
}
func (gui *Gui) handleSwitchToCommitsPanel(g *gocui.Gui, v *gocui.View) error {

View File

@ -26,9 +26,8 @@ func (gui *Gui) handleCommitSelect() error {
return nil
}
// this probably belongs in an 'onFocus' function than a 'commit selected' function
if err := gui.refreshSecondaryPatchPanel(); err != nil {
return err
if gui.inDiffMode() {
return gui.renderDiff()
}
state := gui.State.Panels.Commits
@ -41,27 +40,26 @@ func (gui *Gui) handleCommitSelect() error {
}()
}
gui.getMainView().Title = "Patch"
gui.getSecondaryView().Title = "Custom Patch"
gui.handleEscapeLineByLinePanel()
var task updateTask
commit := gui.getSelectedCommit()
if commit == nil {
return gui.newStringTask("main", gui.Tr.SLocalize("NoCommitsThisBranch"))
task = gui.createRenderStringTask(gui.Tr.SLocalize("NoCommitsThisBranch"))
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.FilterPath),
)
task = gui.createRunPtyTask(cmd)
}
if gui.inDiffMode() {
return gui.renderDiff()
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.FilterPath),
)
if err := gui.newPtyTask("main", cmd); err != nil {
gui.Log.Error(err)
}
return nil
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Patch",
task: task,
},
secondary: gui.secondaryPatchPanelUpdateOpts(),
})
}
// during startup, the bottleneck is fetching the reflog entries. We need these

View File

@ -18,20 +18,21 @@ func (gui *Gui) exitDiffMode() error {
}
func (gui *Gui) renderDiff() error {
filterArg := ""
if gui.inFilterMode() {
filterArg = fmt.Sprintf(" -- %s", gui.State.FilterPath)
}
cmd := gui.OSCommand.ExecutableFromString(
fmt.Sprintf("git diff --color %s %s", gui.diffStr(), filterArg),
)
task := gui.createRunPtyTask(cmd)
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Diff",
task: func() error {
filterArg := ""
if gui.inFilterMode() {
filterArg = fmt.Sprintf(" -- %s", gui.State.FilterPath)
}
cmd := gui.OSCommand.ExecutableFromString(
fmt.Sprintf("git diff --color %s %s", gui.diffStr(), filterArg),
)
return gui.newPtyTask("main", cmd)
},
task: task,
},
})
}

View File

@ -37,12 +37,16 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
file := gui.getSelectedFile()
if file == nil {
gui.splitMainPanel(false)
gui.getMainView().Title = ""
return gui.newStringTask("main", gui.Tr.SLocalize("NoChangedFiles"))
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "",
task: gui.createRenderStringTask(gui.Tr.SLocalize("NoChangedFiles")),
},
})
}
if !alreadySelected {
// TODO: pull into update task interface
if err := gui.resetOrigin(gui.getMainView()); err != nil {
return err
}
@ -52,36 +56,30 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
}
if file.HasInlineMergeConflicts {
gui.getMainView().Title = gui.Tr.SLocalize("MergeConflictsTitle")
gui.splitMainPanel(false)
return gui.refreshMergePanel()
}
if file.HasStagedChanges && file.HasUnstagedChanges {
gui.splitMainPanel(true)
gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
gui.getSecondaryView().Title = gui.Tr.SLocalize("StagedChanges")
cmdStr := gui.GitCommand.DiffCmdStr(file, false, true)
cmd := gui.OSCommand.ExecutableFromString(cmdStr)
if err := gui.newPtyTask("secondary", cmd); err != nil {
return err
}
} else {
gui.splitMainPanel(false)
if file.HasUnstagedChanges {
gui.getMainView().Title = gui.Tr.SLocalize("UnstagedChanges")
} else {
gui.getMainView().Title = gui.Tr.SLocalize("StagedChanges")
}
}
cmdStr := gui.GitCommand.DiffCmdStr(file, false, !file.HasUnstagedChanges && file.HasStagedChanges)
cmd := gui.OSCommand.ExecutableFromString(cmdStr)
if err := gui.newPtyTask("main", cmd); err != nil {
return err
refreshOpts := refreshMainOpts{main: &viewUpdateOpts{
title: gui.Tr.SLocalize("UnstagedChanges"),
task: gui.createRunPtyTask(cmd),
}}
if file.HasStagedChanges && file.HasUnstagedChanges {
cmdStr := gui.GitCommand.DiffCmdStr(file, false, true)
cmd := gui.OSCommand.ExecutableFromString(cmdStr)
refreshOpts.secondary = &viewUpdateOpts{
title: gui.Tr.SLocalize("StagedChanges"),
task: gui.createRunPtyTask(cmd),
}
} else if !file.HasUnstagedChanges {
refreshOpts.main.title = gui.Tr.SLocalize("StagedChanges")
}
return nil
return gui.refreshMain(refreshOpts)
}
func (gui *Gui) refreshFiles() error {

View File

@ -4,7 +4,14 @@ import "os/exec"
type viewUpdateOpts struct {
title string
task func() error
// awkwardly calling this noWrap because of how hard Go makes it to have
// a boolean option that defaults to true
noWrap bool
highlight bool
task updateTask
}
type refreshMainOpts struct {
@ -15,19 +22,100 @@ type refreshMainOpts struct {
// constants for updateTask's kind field
const (
RENDER_STRING = iota
RENDER_STRING_WITHOUT_SCROLL
RUN_FUNCTION
RUN_COMMAND
RUN_PTY
)
type updateTask struct {
kind int
str string
f func(chan struct{}) error
cmd *exec.Cmd
type updateTask interface {
GetKind() int
}
func (gui *Gui) createRenderStringTask(str string) {
type renderStringTask struct {
str string
}
func (t *renderStringTask) GetKind() int {
return RENDER_STRING
}
func (gui *Gui) createRenderStringTask(str string) *renderStringTask {
return &renderStringTask{str: str}
}
type renderStringWithoutScrollTask struct {
str string
}
func (t *renderStringWithoutScrollTask) GetKind() int {
return RENDER_STRING_WITHOUT_SCROLL
}
func (gui *Gui) createRenderStringWithoutScrollTask(str string) *renderStringWithoutScrollTask {
return &renderStringWithoutScrollTask{str: str}
}
type runCommandTask struct {
cmd *exec.Cmd
}
func (t *runCommandTask) GetKind() int {
return RUN_COMMAND
}
func (gui *Gui) createRunCommandTask(cmd *exec.Cmd) *runCommandTask {
return &runCommandTask{cmd: cmd}
}
type runPtyTask struct {
cmd *exec.Cmd
}
func (t *runPtyTask) GetKind() int {
return RUN_PTY
}
func (gui *Gui) createRunPtyTask(cmd *exec.Cmd) *runPtyTask {
return &runPtyTask{cmd: cmd}
}
type runFunctionTask struct {
f func(chan struct{}) error
}
func (t *runFunctionTask) GetKind() int {
return RUN_FUNCTION
}
func (gui *Gui) createRunFunctionTask(f func(chan struct{}) error) *runFunctionTask {
return &runFunctionTask{f: f}
}
func (gui *Gui) runTaskForView(viewName string, task updateTask) error {
switch task.GetKind() {
case RENDER_STRING:
specificTask := task.(*renderStringTask)
return gui.newStringTask(viewName, specificTask.str)
case RENDER_STRING_WITHOUT_SCROLL:
specificTask := task.(*renderStringWithoutScrollTask)
return gui.newStringTaskWithoutScroll(viewName, specificTask.str)
case RUN_FUNCTION:
specificTask := task.(*runFunctionTask)
return gui.newTask(viewName, specificTask.f)
case RUN_COMMAND:
specificTask := task.(*runCommandTask)
return gui.newCmdTask(viewName, specificTask.cmd)
case RUN_PTY:
specificTask := task.(*runPtyTask)
return gui.newPtyTask(viewName, specificTask.cmd)
}
return nil
}
func (gui *Gui) refreshMain(opts refreshMainOpts) error {
@ -36,7 +124,10 @@ func (gui *Gui) refreshMain(opts refreshMainOpts) error {
if opts.main != nil {
mainView.Title = opts.main.title
if err := opts.main.task(); err != nil {
mainView.Wrap = !opts.main.noWrap
mainView.Highlight = opts.main.highlight // TODO: see what the default should be
if err := gui.runTaskForView("main", opts.main.task); err != nil {
gui.Log.Error(err)
return nil
}
@ -46,7 +137,9 @@ func (gui *Gui) refreshMain(opts refreshMainOpts) error {
if opts.secondary != nil {
secondaryView.Title = opts.secondary.title
if err := opts.secondary.task(); err != nil {
secondaryView.Wrap = !opts.secondary.noWrap
mainView.Highlight = opts.main.highlight // TODO: see what the default should be
if err := gui.runTaskForView("secondary", opts.secondary.task); err != nil {
gui.Log.Error(err)
return nil
}

View File

@ -238,14 +238,13 @@ func (gui *Gui) refreshMergePanel() error {
return err
}
mainView := gui.getMainView()
mainView.Wrap = false
if err := gui.newStringTaskWithoutScroll("main", content); err != nil {
return err
}
return nil
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: gui.Tr.SLocalize("MergeConflictsTitle"),
task: gui.createRenderStringWithoutScrollTask(content),
noWrap: true,
},
})
}
func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {

View File

@ -80,13 +80,14 @@ func (gui *Gui) handleEscapePatchBuildingPanel() error {
if gui.GitCommand.PatchManager.IsEmpty() {
gui.GitCommand.PatchManager.Reset()
gui.splitMainPanel(false)
}
return gui.switchContext(gui.Contexts.BranchCommits.Files.Context)
}
func (gui *Gui) refreshSecondaryPatchPanel() error {
// TODO: swap out for secondaryPatchPanelUpdateOpts
if gui.GitCommand.PatchManager.CommitSelected() {
gui.splitMainPanel(true)
secondaryView := gui.getSecondaryView()
@ -103,3 +104,18 @@ func (gui *Gui) refreshSecondaryPatchPanel() error {
return nil
}
func (gui *Gui) secondaryPatchPanelUpdateOpts() *viewUpdateOpts {
if gui.GitCommand.PatchManager.CommitSelected() {
patch := gui.GitCommand.PatchManager.RenderAggregatedPatchColored(false)
return &viewUpdateOpts{
title: "Custom Patch",
noWrap: true,
highlight: true,
task: gui.createRenderStringWithoutScrollTask(patch),
}
}
return nil
}

View File

@ -23,24 +23,24 @@ func (gui *Gui) handleReflogCommitSelect() error {
return gui.renderDiff()
}
refreshOpts := refreshMainOpts{
main: &viewUpdateOpts{
title: "Reflog Entry",
},
}
commit := gui.getSelectedReflogCommit()
var task updateTask
if commit == nil {
refreshOpts.main.task = func() error { return gui.newStringTask("main", "No reflog history") }
task = gui.createRenderStringTask("No reflog history")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha, gui.State.FilterPath),
)
refreshOpts.main.task = func() error { return gui.newPtyTask("main", cmd) }
task = gui.createRunPtyTask(cmd)
}
return gui.refreshMain(refreshOpts)
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Reflog Entry",
task: task,
},
})
}
// the reflogs panel is the only panel where we cache data, in that we only

View File

@ -24,27 +24,27 @@ func (gui *Gui) handleRemoteBranchSelect() error {
return nil
}
gui.splitMainPanel(false)
gui.getMainView().Title = "Remote Branch"
remoteBranch := gui.getSelectedRemoteBranch()
if remoteBranch == nil {
return gui.newStringTask("main", "No branches for this remote")
}
if gui.inDiffMode() {
return gui.renderDiff()
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(remoteBranch.FullName()),
)
if err := gui.newCmdTask("main", cmd); err != nil {
gui.Log.Error(err)
var task updateTask
remoteBranch := gui.getSelectedRemoteBranch()
if remoteBranch == nil {
task = gui.createRenderStringTask("No branches for this remote")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(remoteBranch.FullName()),
)
task = gui.createRunCommandTask(cmd)
}
return nil
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Remote Branch",
task: task,
},
})
}
func (gui *Gui) handleRemoteBranchesEscape(g *gocui.Gui, v *gocui.View) error {

View File

@ -27,19 +27,24 @@ func (gui *Gui) handleRemoteSelect() error {
return nil
}
gui.splitMainPanel(false)
gui.getMainView().Title = "Remote"
remote := gui.getSelectedRemote()
if remote == nil {
return gui.newStringTask("main", "No remotes")
}
if gui.inDiffMode() {
return gui.renderDiff()
}
return gui.newStringTask("main", fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
var task updateTask
remote := gui.getSelectedRemote()
if remote == nil {
task = gui.createRenderStringTask("No remotes")
} else {
task = gui.createRenderStringTask(fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
}
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Remote",
task: task,
},
})
}
func (gui *Gui) refreshRemotes() error {

View File

@ -22,6 +22,10 @@ func (gui *Gui) handleStashEntrySelect() error {
return nil
}
if gui.inDiffMode() {
return gui.renderDiff()
}
gui.splitMainPanel(false)
gui.getMainView().Title = "Stash"
@ -31,10 +35,6 @@ func (gui *Gui) handleStashEntrySelect() error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoStashEntries"))
}
if gui.inDiffMode() {
return gui.renderDiff()
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowStashEntryCmdStr(stashEntry.Index),
)

View File

@ -93,10 +93,6 @@ func (gui *Gui) handleStatusSelect() error {
return nil
}
gui.splitMainPanel(false)
gui.getMainView().Title = ""
if gui.inDiffMode() {
return gui.renderDiff()
}
@ -114,7 +110,12 @@ func (gui *Gui) handleStatusSelect() error {
magenta.Sprint("Become a sponsor (github is matching all donations for 12 months): https://github.com/sponsors/jesseduffield"), // caffeine ain't free
}, "\n\n")
return gui.newStringTask("main", dashboardString)
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "",
task: gui.createRenderStringTask(dashboardString),
},
})
}
func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {

View File

@ -22,27 +22,27 @@ func (gui *Gui) handleTagSelect() error {
return nil
}
gui.splitMainPanel(false)
gui.getMainView().Title = "Tag"
tag := gui.getSelectedTag()
if tag == nil {
return gui.newStringTask("main", "No tags")
}
if gui.inDiffMode() {
return gui.renderDiff()
}
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
)
if err := gui.newCmdTask("main", cmd); err != nil {
gui.Log.Error(err)
var task updateTask
tag := gui.getSelectedTag()
if tag == nil {
task = gui.createRenderStringTask("No tags")
} else {
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
)
task = gui.createRunCommandTask(cmd)
}
return nil
return gui.refreshMain(refreshMainOpts{
main: &viewUpdateOpts{
title: "Tag",
task: task,
},
})
}
func (gui *Gui) refreshTags() error {