Repository: jesseduffield/lazygit
File: pkg/gui/commit_files_panel.go (Go)

Code before:
				if err := gui.GitCommand.WithSpan(gui.Tr.Spans.DiscardOldFileChange).DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil {
					if err := gui.handleGenericMergeCommandResult(err); err != nil {
						return err
					}
				}

				return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI})
			})
		},
	})
}

func (gui *Gui) refreshCommitFilesView() error {
	currentSideContext := gui.currentSideContext()
	if currentSideContext.GetKey() == COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == BRANCH_COMMITS_CONTEXT_KEY {
		if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil {
			return err
		}
	}

	to := gui.State.Panels.CommitFiles.refName
	from, reverse := gui.getFromAndReverseArgsForDiff(to)

	files, err := gui.GitCommand.GetFilesInDiff(from, to, reverse)
	if err != nil && strings.HasPrefix(err.Error(), "fatal: bad revision") {
		gui.State.Modes.Diffing.Ref = commands.EmptyTreeCommitHash
		from, reverse := gui.getFromAndReverseArgsForDiff(to)
		files, err = gui.GitCommand.GetFilesInDiff(from, to, reverse)
	}
	if err != nil {
		return gui.surfaceError(err)
	}
	gui.State.CommitFileManager.SetFiles(files, to)

	return gui.postRefreshUpdate(gui.State.Contexts.CommitFiles)
}

func (gui *Gui) handleOpenOldCommitFile() error {
	node := gui.getSelectedCommitFileNode()
	if node == nil {
		return nil
	}

	return gui.openFile(node.GetPath())
}

func (gui *Gui) handleEditCommitFile() error {
	node := gui.getSelectedCommitFileNode()
	if node == nil {
		return nil
	}

Review comment (performance):
we're kind of cheating here by setting this Ref field. We may not actually be in diff mode, and now by pressing enter on the initial commit, we end up in diff mode, because diff mode is defined to be active when `Ref != ""`.

Something like this might be preferable:
```go
func (gui *Gui) getFromAndReverseArgsForInitialCommitDiff(to string) (string, bool) {
	from := EmptyTreeCommitHash
	reverse := false

	if gui.State.Modes.Diffing.Active() {
		reverse = gui.State.Modes.Diffing.Reverse
	}

	return from, reverse
}
```

But I actually feel like we could do better than checking for the `"fatal: bad revision"` error. We currently store an array of a commit's parents in `pkg/commands/models/commit.go` so we should be able to know ahead of time whether we're dealing with an initial commit: it'll be the one with no parents. Testing locally looks like for the initial commit we store it as `parents: []string{""}` but I would go and change that place in `pkg/commands/loading_commits.go:82` to just have an empty array in that situation.

That means we just need an efficient way of checking whether a given commit SHA is referring to the initial commit. If we don't have easy-access to the commit that the SHA is from, I think it makes sense to build a map of SHA's to commits when we build our list of commits, for the sake of easy lookup. But I also wonder if we can just check if we're dealing with the initial commit when we hit enter in the first place, given we should have access to the commit at that point in time.

Lemme know your thoughts :)

Code after:
package gui

import (
	"github.com/jesseduffield/lazygit/pkg/gui/controllers"
)

// TODO: do we need this?
func (gui *Gui) onCommitFileFocus() error {
	gui.escapeLineByLinePanel()
	return nil
}

func (gui *Gui) commitFilesRenderToMain() error {
	node := gui.State.Contexts.CommitFiles.GetSelected()
	if node == nil {
		return nil
	}

	ref := gui.State.Contexts.CommitFiles.GetRef()
	to := ref.RefName()
	from, reverse := gui.State.Modes.Diffing.GetFromAndReverseArgsForDiff(ref.ParentRefName())

	cmdObj := gui.git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false)
	task := NewRunPtyTask(cmdObj.GetCmd())

	mainContext := gui.State.Contexts.Normal
	if node.File != nil {
		mainContext = gui.State.Contexts.PatchBuilding
	}

	return gui.refreshMainViews(refreshMainOpts{
		main: &viewUpdateOpts{
			title:   "Patch",
			task:    task,
			context: mainContext,
		},
		secondary: gui.secondaryPatchPanelUpdateOpts(),
	})
}

func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error {
	gui.State.Contexts.CommitFiles.SetSelectedLineIdx(0)
	gui.State.Contexts.CommitFiles.SetRef(opts.Ref)
	gui.State.Contexts.CommitFiles.SetTitleRef(opts.Ref.Description())
	gui.State.Contexts.CommitFiles.SetCanRebase(opts.CanRebase)
	gui.State.Contexts.CommitFiles.SetParentContext(opts.Context)
	gui.State.Contexts.CommitFiles.SetWindowName(opts.Context.GetWindowName())

	if err := gui.refreshCommitFilesContext(); err != nil {
		return err
	}

	return gui.c.PushContext(gui.State.Contexts.CommitFiles)
}

func (gui *Gui) refreshCommitFilesContext() error {
	ref := gui.State.Contexts.CommitFiles.GetRef()
	to := ref.RefName()
	from, reverse := gui.State.Modes.Diffing.GetFromAndReverseArgsForDiff(ref.ParentRefName())

	files, err := gui.git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse)
	if err != nil {
		return gui.c.Error(err)
	}
	gui.State.Model.CommitFiles = files
	gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.SetTree()

	return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles)
}

func (gui *Gui) getSelectedCommitFileName() string {
	node := gui.State.Contexts.CommitFiles.GetSelected()
	if node == nil {
		return ""
	}

	return node.Path
}