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

Code before:
		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 {
		return nil
	}

	// at this point we aren't actually rebasing so we will interpret this as an
	// attempt to pull. We might revoke this later after enabling configurable keybindings
	return self.pullFiles()
}

func (self *LocalCommitsController) interactiveRebase(action todo.TodoCommand) error {
	err := self.c.Git().Rebase.InteractiveRebase(self.c.Model().Commits, self.context().GetSelectedLineIdx(), action)
	return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
}

// handleMidRebaseCommand sees if the selected commit is in fact a rebasing
// commit meaning you are trying to edit the todo file rather than actually
// begin a rebase. It then updates the todo file with that action
func (self *LocalCommitsController) handleMidRebaseCommand(action todo.TodoCommand, commit *models.Commit) (bool, error) {
	if !commit.IsTODO() {
		return false, nil
	}

	self.c.LogAction("Update rebase TODO")

	msg := utils.ResolvePlaceholderString(

Review comment (suggestion):
This should also be a DisabledReason. Maybe not using the FindIndexOf; I guess checking the merge state of `Commits[0]` should be enough for that.

Code after:
	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
	})

	if !ok || index == 0 {
		errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{
			"editKey": keybindings.Label(self.c.UserConfig.Keybinding.Universal.Edit),
		})

		return nil, errors.New(errorMsg)
	}

	return commit, nil
}

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

	// at this point we aren't actually rebasing so we will interpret this as an
	// attempt to pull. We might revoke this later after enabling configurable keybindings
	return self.pullFiles()
}