mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Replace merge-tool with merge options menu that allows resolving all conflicts for selected files as ours, theirs, or union, while still providing access to the merge tool.
		
			
				
	
	
		
			444 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			444 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package gui
 | |
| 
 | |
| import (
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/jesseduffield/gocui"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/commands/models"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/gui/controllers"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/gui/services/custom_commands"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/gui/status"
 | |
| 	"github.com/jesseduffield/lazygit/pkg/gui/types"
 | |
| )
 | |
| 
 | |
| func (gui *Gui) Helpers() *helpers.Helpers {
 | |
| 	return gui.helpers
 | |
| }
 | |
| 
 | |
| // Note, the order of controllers determines the order in which keybindings appear
 | |
| // in the keybinding menu: the earlier that the controller is attached to a context,
 | |
| // the lower in the list the keybindings will appear.
 | |
| func (gui *Gui) resetHelpersAndControllers() {
 | |
| 	for _, context := range gui.Contexts().Flatten() {
 | |
| 		context.ClearAllAttachedControllerFunctions()
 | |
| 	}
 | |
| 
 | |
| 	helperCommon := gui.c
 | |
| 	recordDirectoryHelper := helpers.NewRecordDirectoryHelper(helperCommon)
 | |
| 	reposHelper := helpers.NewRecentReposHelper(helperCommon, recordDirectoryHelper, gui.onNewRepo)
 | |
| 	rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon)
 | |
| 	refsHelper := helpers.NewRefsHelper(helperCommon, rebaseHelper)
 | |
| 	suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon)
 | |
| 	worktreeHelper := helpers.NewWorktreeHelper(helperCommon, reposHelper, refsHelper, suggestionsHelper)
 | |
| 
 | |
| 	setCommitSummary := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage })
 | |
| 	setCommitDescription := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitDescription })
 | |
| 	getCommitSummary := func() string {
 | |
| 		return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent())
 | |
| 	}
 | |
| 
 | |
| 	getCommitDescription := func() string {
 | |
| 		return strings.TrimSpace(gui.Views.CommitDescription.TextArea.GetContent())
 | |
| 	}
 | |
| 	getUnwrappedCommitDescription := func() string {
 | |
| 		return strings.TrimSpace(gui.Views.CommitDescription.TextArea.GetUnwrappedContent())
 | |
| 	}
 | |
| 	commitsHelper := helpers.NewCommitsHelper(helperCommon,
 | |
| 		getCommitSummary,
 | |
| 		setCommitSummary,
 | |
| 		getCommitDescription,
 | |
| 		getUnwrappedCommitDescription,
 | |
| 		setCommitDescription,
 | |
| 	)
 | |
| 
 | |
| 	gpgHelper := helpers.NewGpgHelper(helperCommon)
 | |
| 	viewHelper := helpers.NewViewHelper(helperCommon, gui.State.Contexts)
 | |
| 	patchBuildingHelper := helpers.NewPatchBuildingHelper(helperCommon)
 | |
| 	stagingHelper := helpers.NewStagingHelper(helperCommon)
 | |
| 	mergeConflictsHelper := helpers.NewMergeConflictsHelper(helperCommon)
 | |
| 	searchHelper := helpers.NewSearchHelper(helperCommon)
 | |
| 
 | |
| 	refreshHelper := helpers.NewRefreshHelper(
 | |
| 		helperCommon,
 | |
| 		refsHelper,
 | |
| 		rebaseHelper,
 | |
| 		patchBuildingHelper,
 | |
| 		stagingHelper,
 | |
| 		mergeConflictsHelper,
 | |
| 		worktreeHelper,
 | |
| 		searchHelper,
 | |
| 	)
 | |
| 	diffHelper := helpers.NewDiffHelper(helperCommon)
 | |
| 	cherryPickHelper := helpers.NewCherryPickHelper(
 | |
| 		helperCommon,
 | |
| 		rebaseHelper,
 | |
| 	)
 | |
| 	bisectHelper := helpers.NewBisectHelper(helperCommon)
 | |
| 	windowHelper := helpers.NewWindowHelper(helperCommon, viewHelper)
 | |
| 	modeHelper := helpers.NewModeHelper(
 | |
| 		helperCommon,
 | |
| 		diffHelper,
 | |
| 		patchBuildingHelper,
 | |
| 		cherryPickHelper,
 | |
| 		rebaseHelper,
 | |
| 		bisectHelper,
 | |
| 	)
 | |
| 	appStatusHelper := helpers.NewAppStatusHelper(
 | |
| 		helperCommon,
 | |
| 		func() *status.StatusManager { return gui.statusManager },
 | |
| 		modeHelper,
 | |
| 	)
 | |
| 
 | |
| 	gui.helpers = &helpers.Helpers{
 | |
| 		Refs:            refsHelper,
 | |
| 		Host:            helpers.NewHostHelper(helperCommon),
 | |
| 		PatchBuilding:   patchBuildingHelper,
 | |
| 		Staging:         stagingHelper,
 | |
| 		Bisect:          bisectHelper,
 | |
| 		Suggestions:     suggestionsHelper,
 | |
| 		Files:           helpers.NewFilesHelper(helperCommon),
 | |
| 		WorkingTree:     helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper, rebaseHelper),
 | |
| 		Tags:            helpers.NewTagsHelper(helperCommon, commitsHelper, gpgHelper),
 | |
| 		BranchesHelper:  helpers.NewBranchesHelper(helperCommon, worktreeHelper),
 | |
| 		GPG:             helpers.NewGpgHelper(helperCommon),
 | |
| 		MergeAndRebase:  rebaseHelper,
 | |
| 		MergeConflicts:  mergeConflictsHelper,
 | |
| 		CherryPick:      cherryPickHelper,
 | |
| 		Upstream:        helpers.NewUpstreamHelper(helperCommon, suggestionsHelper.GetRemoteBranchesSuggestionsFunc),
 | |
| 		AmendHelper:     helpers.NewAmendHelper(helperCommon, gpgHelper),
 | |
| 		FixupHelper:     helpers.NewFixupHelper(helperCommon),
 | |
| 		Commits:         commitsHelper,
 | |
| 		SuspendResume:   helpers.NewSuspendResumeHelper(helperCommon),
 | |
| 		Snake:           helpers.NewSnakeHelper(helperCommon),
 | |
| 		Diff:            diffHelper,
 | |
| 		Repos:           reposHelper,
 | |
| 		RecordDirectory: recordDirectoryHelper,
 | |
| 		Update:          helpers.NewUpdateHelper(helperCommon, gui.Updater),
 | |
| 		Window:          windowHelper,
 | |
| 		View:            viewHelper,
 | |
| 		Refresh:         refreshHelper,
 | |
| 		Confirmation:    helpers.NewConfirmationHelper(helperCommon),
 | |
| 		Mode:            modeHelper,
 | |
| 		AppStatus:       appStatusHelper,
 | |
| 		InlineStatus:    helpers.NewInlineStatusHelper(helperCommon, windowHelper),
 | |
| 		WindowArrangement: helpers.NewWindowArrangementHelper(
 | |
| 			gui.c,
 | |
| 			windowHelper,
 | |
| 			modeHelper,
 | |
| 			appStatusHelper,
 | |
| 		),
 | |
| 		Search:     searchHelper,
 | |
| 		Worktree:   worktreeHelper,
 | |
| 		SubCommits: helpers.NewSubCommitsHelper(helperCommon, refreshHelper),
 | |
| 	}
 | |
| 
 | |
| 	gui.CustomCommandsClient = custom_commands.NewClient(
 | |
| 		helperCommon,
 | |
| 		gui.helpers,
 | |
| 	)
 | |
| 
 | |
| 	common := controllers.NewControllerCommon(helperCommon, gui)
 | |
| 
 | |
| 	syncController := controllers.NewSyncController(
 | |
| 		common,
 | |
| 	)
 | |
| 
 | |
| 	submodulesController := controllers.NewSubmodulesController(common)
 | |
| 
 | |
| 	bisectController := controllers.NewBisectController(common)
 | |
| 
 | |
| 	commitMessageController := controllers.NewCommitMessageController(
 | |
| 		common,
 | |
| 	)
 | |
| 
 | |
| 	commitDescriptionController := controllers.NewCommitDescriptionController(
 | |
| 		common,
 | |
| 	)
 | |
| 
 | |
| 	remoteBranchesController := controllers.NewRemoteBranchesController(common)
 | |
| 
 | |
| 	menuController := controllers.NewMenuController(common)
 | |
| 	localCommitsController := controllers.NewLocalCommitsController(common, syncController.HandlePull)
 | |
| 	tagsController := controllers.NewTagsController(common)
 | |
| 	filesController := controllers.NewFilesController(
 | |
| 		common,
 | |
| 	)
 | |
| 	mergeConflictsController := controllers.NewMergeConflictsController(common)
 | |
| 	remotesController := controllers.NewRemotesController(
 | |
| 		common,
 | |
| 		func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches },
 | |
| 	)
 | |
| 	worktreesController := controllers.NewWorktreesController(common)
 | |
| 	undoController := controllers.NewUndoController(common)
 | |
| 	globalController := controllers.NewGlobalController(common)
 | |
| 	contextLinesController := controllers.NewContextLinesController(common)
 | |
| 	renameSimilarityThresholdController := controllers.NewRenameSimilarityThresholdController(common)
 | |
| 	verticalScrollControllerFactory := controllers.NewVerticalScrollControllerFactory(common)
 | |
| 	viewSelectionControllerFactory := controllers.NewViewSelectionControllerFactory(common)
 | |
| 
 | |
| 	branchesController := controllers.NewBranchesController(common)
 | |
| 	gitFlowController := controllers.NewGitFlowController(common)
 | |
| 	stashController := controllers.NewStashController(common)
 | |
| 	commitFilesController := controllers.NewCommitFilesController(common)
 | |
| 	patchExplorerControllerFactory := controllers.NewPatchExplorerControllerFactory(common)
 | |
| 	stagingController := controllers.NewStagingController(common, gui.State.Contexts.Staging, gui.State.Contexts.StagingSecondary, false)
 | |
| 	stagingSecondaryController := controllers.NewStagingController(common, gui.State.Contexts.StagingSecondary, gui.State.Contexts.Staging, true)
 | |
| 	mainViewController := controllers.NewMainViewController(common, gui.State.Contexts.Normal, gui.State.Contexts.NormalSecondary)
 | |
| 	secondaryViewController := controllers.NewMainViewController(common, gui.State.Contexts.NormalSecondary, gui.State.Contexts.Normal)
 | |
| 	patchBuildingController := controllers.NewPatchBuildingController(common)
 | |
| 	snakeController := controllers.NewSnakeController(common)
 | |
| 	reflogCommitsController := controllers.NewReflogCommitsController(common)
 | |
| 	subCommitsController := controllers.NewSubCommitsController(common)
 | |
| 	statusController := controllers.NewStatusController(common)
 | |
| 	commandLogController := controllers.NewCommandLogController(common)
 | |
| 	confirmationController := controllers.NewConfirmationController(common)
 | |
| 	promptController := controllers.NewPromptController(common)
 | |
| 	suggestionsController := controllers.NewSuggestionsController(common)
 | |
| 	jumpToSideWindowController := controllers.NewJumpToSideWindowController(common, gui.handleNextTab)
 | |
| 
 | |
| 	sideWindowControllerFactory := controllers.NewSideWindowControllerFactory(common)
 | |
| 
 | |
| 	filterControllerFactory := controllers.NewFilterControllerFactory(common)
 | |
| 	for _, context := range gui.c.Context().AllFilterable() {
 | |
| 		controllers.AttachControllers(context, filterControllerFactory.Create(context))
 | |
| 	}
 | |
| 
 | |
| 	searchControllerFactory := controllers.NewSearchControllerFactory(common)
 | |
| 	for _, context := range gui.c.Context().AllSearchable() {
 | |
| 		controllers.AttachControllers(context, searchControllerFactory.Create(context))
 | |
| 	}
 | |
| 
 | |
| 	for _, context := range []controllers.CanViewWorktreeOptions{
 | |
| 		gui.State.Contexts.LocalCommits,
 | |
| 		gui.State.Contexts.ReflogCommits,
 | |
| 		gui.State.Contexts.SubCommits,
 | |
| 		gui.State.Contexts.Stash,
 | |
| 		gui.State.Contexts.Branches,
 | |
| 		gui.State.Contexts.RemoteBranches,
 | |
| 		gui.State.Contexts.Tags,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, controllers.NewWorktreeOptionsController(common, context))
 | |
| 	}
 | |
| 
 | |
| 	// allow for navigating between side window contexts
 | |
| 	for _, context := range []types.Context{
 | |
| 		gui.State.Contexts.Status,
 | |
| 		gui.State.Contexts.Remotes,
 | |
| 		gui.State.Contexts.Worktrees,
 | |
| 		gui.State.Contexts.Tags,
 | |
| 		gui.State.Contexts.Branches,
 | |
| 		gui.State.Contexts.RemoteBranches,
 | |
| 		gui.State.Contexts.Files,
 | |
| 		gui.State.Contexts.Submodules,
 | |
| 		gui.State.Contexts.ReflogCommits,
 | |
| 		gui.State.Contexts.LocalCommits,
 | |
| 		gui.State.Contexts.CommitFiles,
 | |
| 		gui.State.Contexts.SubCommits,
 | |
| 		gui.State.Contexts.Stash,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, sideWindowControllerFactory.Create(context))
 | |
| 	}
 | |
| 
 | |
| 	for _, context := range []controllers.CanSwitchToSubCommits{
 | |
| 		gui.State.Contexts.Branches,
 | |
| 		gui.State.Contexts.RemoteBranches,
 | |
| 		gui.State.Contexts.Tags,
 | |
| 		gui.State.Contexts.ReflogCommits,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, controllers.NewSwitchToSubCommitsController(
 | |
| 			common, context,
 | |
| 		))
 | |
| 	}
 | |
| 
 | |
| 	for _, context := range []controllers.CanSwitchToDiffFiles{
 | |
| 		gui.State.Contexts.LocalCommits,
 | |
| 		gui.State.Contexts.SubCommits,
 | |
| 		gui.State.Contexts.Stash,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, controllers.NewSwitchToDiffFilesController(
 | |
| 			common, context,
 | |
| 		))
 | |
| 	}
 | |
| 
 | |
| 	for _, context := range []types.Context{
 | |
| 		gui.State.Contexts.Status,
 | |
| 		gui.State.Contexts.Files,
 | |
| 		gui.State.Contexts.Branches,
 | |
| 		gui.State.Contexts.RemoteBranches,
 | |
| 		gui.State.Contexts.Tags,
 | |
| 		gui.State.Contexts.LocalCommits,
 | |
| 		gui.State.Contexts.ReflogCommits,
 | |
| 		gui.State.Contexts.SubCommits,
 | |
| 		gui.State.Contexts.CommitFiles,
 | |
| 		gui.State.Contexts.Stash,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, controllers.NewSwitchToFocusedMainViewController(
 | |
| 			common, context,
 | |
| 		))
 | |
| 	}
 | |
| 
 | |
| 	for _, context := range []controllers.ContainsCommits{
 | |
| 		gui.State.Contexts.LocalCommits,
 | |
| 		gui.State.Contexts.ReflogCommits,
 | |
| 		gui.State.Contexts.SubCommits,
 | |
| 	} {
 | |
| 		controllers.AttachControllers(context, controllers.NewBasicCommitsController(common, context))
 | |
| 	}
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.ReflogCommits,
 | |
| 		reflogCommitsController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.SubCommits,
 | |
| 		subCommitsController,
 | |
| 	)
 | |
| 
 | |
| 	// TODO: add scroll controllers for main panels (need to bring some more functionality across for that e.g. reading more from the currently displayed git command)
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Staging,
 | |
| 		stagingController,
 | |
| 		patchExplorerControllerFactory.Create(gui.State.Contexts.Staging),
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.Staging),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.StagingSecondary,
 | |
| 		stagingSecondaryController,
 | |
| 		patchExplorerControllerFactory.Create(gui.State.Contexts.StagingSecondary),
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.StagingSecondary),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CustomPatchBuilder,
 | |
| 		patchBuildingController,
 | |
| 		patchExplorerControllerFactory.Create(gui.State.Contexts.CustomPatchBuilder),
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.CustomPatchBuilder),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CustomPatchBuilderSecondary,
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.CustomPatchBuilderSecondary),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.MergeConflicts,
 | |
| 		mergeConflictsController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Normal,
 | |
| 		mainViewController,
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.Normal),
 | |
| 		viewSelectionControllerFactory.Create(gui.State.Contexts.Normal),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.NormalSecondary,
 | |
| 		secondaryViewController,
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.NormalSecondary),
 | |
| 		viewSelectionControllerFactory.Create(gui.State.Contexts.NormalSecondary),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Files,
 | |
| 		filesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Tags,
 | |
| 		tagsController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Submodules,
 | |
| 		submodulesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Branches,
 | |
| 		branchesController,
 | |
| 		gitFlowController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.LocalCommits,
 | |
| 		localCommitsController,
 | |
| 		bisectController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CommitFiles,
 | |
| 		commitFilesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Remotes,
 | |
| 		remotesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Worktrees,
 | |
| 		worktreesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Stash,
 | |
| 		stashController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Menu,
 | |
| 		menuController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CommitMessage,
 | |
| 		commitMessageController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CommitDescription,
 | |
| 		commitDescriptionController,
 | |
| 		verticalScrollControllerFactory.Create(gui.State.Contexts.CommitDescription),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.RemoteBranches,
 | |
| 		remoteBranchesController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Status,
 | |
| 		statusController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.CommandLog,
 | |
| 		commandLogController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Confirmation,
 | |
| 		confirmationController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Prompt,
 | |
| 		promptController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Suggestions,
 | |
| 		suggestionsController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Search,
 | |
| 		controllers.NewSearchPromptController(common),
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Global,
 | |
| 		undoController,
 | |
| 		globalController,
 | |
| 		contextLinesController,
 | |
| 		renameSimilarityThresholdController,
 | |
| 		jumpToSideWindowController,
 | |
| 		syncController,
 | |
| 	)
 | |
| 
 | |
| 	controllers.AttachControllers(gui.State.Contexts.Snake,
 | |
| 		snakeController,
 | |
| 	)
 | |
| 
 | |
| 	// this must come last so that we've got our click handlers defined against the context
 | |
| 	listControllerFactory := controllers.NewListControllerFactory(common)
 | |
| 	for _, context := range gui.c.Context().AllList() {
 | |
| 		controllers.AttachControllers(context, listControllerFactory.Create(context))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (gui *Gui) getCommitMessageSetTextareaTextFn(getView func() *gocui.View) func(string) {
 | |
| 	return func(text string) {
 | |
| 		// using a getView function so that we don't need to worry about when the view is created
 | |
| 		view := getView()
 | |
| 		view.ClearTextArea()
 | |
| 		view.TextArea.TypeString(text)
 | |
| 		view.RenderTextArea()
 | |
| 	}
 | |
| }
 |