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

Code before:
		return err
	}
	if applied {
		return nil
	}

	return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
		self.c.LogAction(self.c.Tr.Actions.EditCommit)
		err := self.c.Git().Rebase.EditRebase(commit.Sha)
		return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
			err,
			types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() {
				_, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
					return c.Sha == commit.Sha
				})
				if ok {
					self.context().SetSelectedLineIdx(index)
				}
			}})
	})
}

func (self *LocalCommitsController) quickStartInteractiveRebase() error {
	if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
		return self.c.ErrorMsg(self.c.Tr.AlreadyRebasing)
	}

	commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
		return c.IsMerge() || c.Status == models.StatusMerged
	})

	if !ok || index == 0 {
		return self.c.ErrorMsg(self.c.Tr.CouldNotQuickStartInteractiveRebase)
	}

	return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
		self.c.LogAction(self.c.Tr.Actions.EditCommit)
		err := self.c.Git().Rebase.EditRebase(commit.Sha)
		return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
			err,
			types.RefreshOptions{Mode: types.BLOCK_UI},
		)
	})
}

func (self *LocalCommitsController) pick(commit *models.Commit) error {
	applied, err := self.handleMidRebaseCommand(todo.Pick, commit)
	if err != nil {
		return err
	}
	if applied {

Review comment (suggestion):
I'd prefer this to be a DisabledReason, like we do for amendTo and squashAllFixupsAbove. (We are not super consistent with this, some other commands only check it in the handler, but for new ones it would be good to use DisabledReasons rather more than less.)

More thoughts on this: `Status.WorkingTreeState()` is reasonably cheap, but it still needs to hit the file system, so we may not want to use it for DisabledReasons. Maybe we should switch to `Model.WorkingTreeStateAtLastCommitRefresh` for that, but then we should check `Status.WorkingTreeState()` again in the handler just to be sure. I guess.

Code after:
}

func (self *LocalCommitsController) edit(commit *models.Commit) error {
	applied, err := self.handleMidRebaseCommand(todo.Edit, commit)
	if err != nil {
		return err
	}
	if applied {
		return nil
	}

	return self.startInteractiveRebaseWithEdit(commit, commit)
}

func (self *LocalCommitsController) quickStartInteractiveRebase(selectedCommit *models.Commit) error {
	commitToEdit, err := self.findCommitForQuickStartInteractiveRebase()
	if err != nil {
		return self.c.Error(err)
	}

	return self.startInteractiveRebaseWithEdit(commitToEdit, selectedCommit)
}

func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
	commitToEdit *models.Commit,
	selectedCommit *models.Commit,
) error {
	return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
		self.c.LogAction(self.c.Tr.Actions.EditCommit)
		err := self.c.Git().Rebase.EditRebase(commitToEdit.Sha)
		return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
			err,
			types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() {
				// We need to select the same commit again because after starting a rebase,
				// new lines can be added for update-ref commands in the TODO file, due to
				// stacked branches. So the commit may be in a different position in the list.
				_, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
					return c.Sha == selectedCommit.Sha
				})
				if ok {
					self.context().SetSelectedLineIdx(index)
				}
			}})
	})
}

func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (*models.Commit, error) {
	commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
		return c.IsMerge() || c.Status == models.StatusMerged
	})