diff --git a/pkg/commands/models/file.go b/pkg/commands/models/file.go index 561399820..e48696a4f 100644 --- a/pkg/commands/models/file.go +++ b/pkg/commands/models/file.go @@ -1,6 +1,7 @@ package models import ( + "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" ) @@ -101,6 +102,22 @@ func (f *File) GetIsFile() bool { return true } +func (f *File) GetMergeStateDescription(tr *i18n.TranslationSet) string { + m := map[string]string{ + "DD": tr.MergeConflictDescription_DD, + "AU": tr.MergeConflictDescription_AU, + "UA": tr.MergeConflictDescription_UA, + "DU": tr.MergeConflictDescription_DU, + "UD": tr.MergeConflictDescription_UD, + } + + if description, ok := m[f.ShortStatus]; ok { + return description + } + + panic("should only be called if there's a merge conflict") +} + type StatusFields struct { HasStagedChanges bool HasUnstagedChanges bool diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index f8e6061b3..cf3d0475e 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -268,6 +268,38 @@ func (self *FilesController) GetOnRenderToMain() func() { self.c.Helpers().MergeConflicts.Render() return } + } else if node.File != nil && node.File.HasMergeConflicts { + opts := types.RefreshMainOpts{ + Pair: self.c.MainViewPairs().Normal, + Main: &types.ViewUpdateOpts{ + Title: self.c.Tr.DiffTitle, + SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(), + }, + } + message := node.File.GetMergeStateDescription(self.c.Tr) + message += "\n\n" + fmt.Sprintf(self.c.Tr.MergeConflictPressEnterToResolve, + self.c.UserConfig().Keybinding.Universal.GoInto) + if self.c.Views().Main.InnerWidth() > 70 { + // If the main view is very wide, wrap the message to increase readability + lines, _, _ := utils.WrapViewLinesToWidth(true, false, message, 70, 4) + message = strings.Join(lines, "\n") + } + if node.File.ShortStatus == "DU" || node.File.ShortStatus == "UD" { + cmdObj := self.c.Git().Diff.DiffCmdObj([]string{"--base", "--", node.GetPath()}) + task := types.NewRunPtyTask(cmdObj.GetCmd()) + task.Prefix = message + "\n\n" + if node.File.ShortStatus == "DU" { + task.Prefix += self.c.Tr.MergeConflictIncomingDiff + } else { + task.Prefix += self.c.Tr.MergeConflictCurrentDiff + } + task.Prefix += "\n\n" + opts.Main.Task = task + } else { + opts.Main.Task = types.NewRenderStringTask(message) + } + self.c.RenderToMainViews(opts) + return } self.c.Helpers().MergeConflicts.ResetMergeState() diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 0478b114a..eeaf4f2e9 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -99,6 +99,14 @@ type TranslationSet struct { FilterLabelUntrackedFiles string FilterLabelConflictingFiles string MergeConflictsTitle string + MergeConflictDescription_DD string + MergeConflictDescription_AU string + MergeConflictDescription_UA string + MergeConflictDescription_DU string + MergeConflictDescription_UD string + MergeConflictIncomingDiff string + MergeConflictCurrentDiff string + MergeConflictPressEnterToResolve string Checkout string CheckoutTooltip string CantCheckoutBranchWhilePulling string @@ -1112,6 +1120,14 @@ func EnglishTranslationSet() *TranslationSet { PullTooltip: "Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch.", Scroll: "Scroll", MergeConflictsTitle: "Merge conflicts", + MergeConflictDescription_DD: "Conflict: this file was moved or renamed both in the current and the incoming changes, but to different destinations. I don't know which ones, but they should both show up as conflicts too (marked 'AU' and 'UA', respectively). The most likely resolution is to delete this file, and pick one of the destinations and delete the other.", + MergeConflictDescription_AU: "Conflict: this file is the destination of a move or rename in the current changes, but was moved or renamed to a different destination in the incoming changes. That other destination should also show up as a conflict (marked 'UA'), as well as the file that both were renamed from (marked 'DD').", + MergeConflictDescription_UA: "Conflict: this file is the destination of a move or rename in the incoming changes, but was moved or renamed to a different destination in the current changes. That other destination should also show up as a conflict (marked 'AU'), as well as the file that both were renamed from (marked 'DD').", + MergeConflictDescription_DU: "Conflict: this file was deleted in the current changes and modified in the incoming changes.\n\nThe most likely resolution is to delete the file after applying the incoming modifications manually to some other place in the code.", + MergeConflictDescription_UD: "Conflict: this file was modified in the current changes and deleted in incoming changes.\n\nThe most likely resolution is to delete the file after applying the current modifications manually to some other place in the code.", + MergeConflictIncomingDiff: "Incoming changes:", + MergeConflictCurrentDiff: "Current changes:", + MergeConflictPressEnterToResolve: "Press %s to resolve.", Checkout: "Checkout", CheckoutTooltip: "Checkout selected item.", CantCheckoutBranchWhilePulling: "You cannot checkout another branch while pulling the current branch",