From 2e1be459574cf17e250f26e35939b3a122e3b2aa Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 26 Mar 2025 18:26:18 +0100 Subject: [PATCH] Better main view display for conflicing files For the less common conflict types DD, AU, UA, DU, and UD, we would previously only show "* Unmerged path" in the main view, which isn't helpful. Also, for some of these we would split the main view and show this text both in the unstaged changes and staged changes views, which is a bit embarrassing. Improve this by offering more explanation about what's going on, and what the most likely way to resolve the situation is for each case. --- pkg/commands/models/file.go | 17 +++++++++++++ pkg/gui/controllers/files_controller.go | 32 +++++++++++++++++++++++++ pkg/i18n/english.go | 16 +++++++++++++ 3 files changed, 65 insertions(+) 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",