From 6729d4e8968705051d903f1a4b72a92f75cbf09f Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 22:10:23 +0800 Subject: [PATCH] feature: supports to ignore new files in folder from context menu of selected folder node in change tree (#1432) Signed-off-by: leo --- src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/ViewModels/WorkingCopy.cs | 122 +++++++++++++++++++++--------- src/Views/WorkingCopy.axaml.cs | 8 +- 5 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index a4066891..c459bb88 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -764,6 +764,7 @@ Git Ignore Ignore all *{0} files Ignore *{0} files in the same folder + Ignore files in this folder Ignore files in the same folder Ignore this file only Amend diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 783cb664..988fd329 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -768,6 +768,7 @@ 添加至 .gitignore 忽略列表 忽略所有 *{0} 文件 忽略同目录下所有 *{0} 文件 + 忽略该目录下的新文件 忽略同目录下所有文件 忽略本文件 修补 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index d8aff0fd..4b9e9bb5 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -768,6 +768,7 @@ 加入至 .gitignore 忽略清單 忽略所有 *{0} 檔案 忽略同路徑下所有 *{0} 檔案 + 忽略本路徑下的新增檔案 忽略同路徑下所有檔案 忽略本檔案 修補 diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 09ebc6f6..48a1b206 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -581,7 +581,7 @@ namespace SourceGit.ViewModels DoCommit(false, true); } - public ContextMenu CreateContextMenuForUnstagedChanges() + public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFolder) { if (_selectedUnstaged == null || _selectedUnstaged.Count == 0) return null; @@ -761,52 +761,87 @@ namespace SourceGit.ViewModels var hasExtra = false; if (change.WorkTree == Models.ChangeState.Untracked) { - var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0; var addToIgnore = new MenuItem(); addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); - var singleFile = new MenuItem(); - singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile"); - singleFile.Click += (_, e) => + if (!string.IsNullOrEmpty(selectedSingleFolder)) { - Commands.GitIgnore.Add(_repo.FullPath, change.Path); - e.Handled = true; - }; - addToIgnore.Items.Add(singleFile); - - var byParentFolder = new MenuItem(); - byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); - byParentFolder.IsVisible = !isRooted; - byParentFolder.Click += (_, e) => - { - var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); - Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); - e.Handled = true; - }; - addToIgnore.Items.Add(byParentFolder); - - if (!string.IsNullOrEmpty(extension)) - { - var byExtension = new MenuItem(); - byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); - byExtension.Click += (_, e) => + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => { - Commands.GitIgnore.Add(_repo.FullPath, $"*{extension}"); + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); e.Handled = true; }; - addToIgnore.Items.Add(byExtension); + addToIgnore.Items.Add(ignoreFolder); + } + else + { + var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0; + var singleFile = new MenuItem(); + singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile"); + singleFile.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, change.Path); + e.Handled = true; + }; + addToIgnore.Items.Add(singleFile); - var byExtensionInSameFolder = new MenuItem(); - byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension); - byExtensionInSameFolder.IsVisible = !isRooted; - byExtensionInSameFolder.Click += (_, e) => + var byParentFolder = new MenuItem(); + byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); + byParentFolder.IsVisible = !isRooted; + byParentFolder.Click += (_, e) => { var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); - Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); + Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); e.Handled = true; }; - addToIgnore.Items.Add(byExtensionInSameFolder); + addToIgnore.Items.Add(byParentFolder); + + if (!string.IsNullOrEmpty(extension)) + { + var byExtension = new MenuItem(); + byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); + byExtension.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"*{extension}"); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtension); + + var byExtensionInSameFolder = new MenuItem(); + byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension); + byExtensionInSameFolder.IsVisible = !isRooted; + byExtensionInSameFolder.Click += (_, e) => + { + var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); + Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtensionInSameFolder); + } + } + + menu.Items.Add(addToIgnore); + hasExtra = true; + } + else if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var addToIgnore = new MenuItem(); + addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); + addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); + + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); + e.Handled = true; + }; + addToIgnore.Items.Add(ignoreFolder); } menu.Items.Add(addToIgnore); @@ -1086,6 +1121,25 @@ namespace SourceGit.ViewModels menu.Items.Add(discard); menu.Items.Add(stash); menu.Items.Add(patch); + + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); + e.Handled = true; + }; + + var addToIgnore = new MenuItem(); + addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); + addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); + addToIgnore.Items.Add(ignoreFolder); + + menu.Items.Add(new MenuItem() { Header = "-" }); + menu.Items.Add(addToIgnore); + } } return menu; diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index ca2ebbb7..93293c68 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -1,6 +1,7 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.VisualTree; namespace SourceGit.Views { @@ -29,7 +30,12 @@ namespace SourceGit.Views { if (DataContext is ViewModels.WorkingCopy vm && sender is Control control) { - var menu = vm.CreateContextMenuForUnstagedChanges(); + var container = control.FindDescendantOfType(); + var selectedSingleFolder = string.Empty; + if (container is { SelectedItems: { Count: 1 }, SelectedItem: ViewModels.ChangeTreeNode { IsFolder: true } node }) + selectedSingleFolder = node.FullPath; + + var menu = vm.CreateContextMenuForUnstagedChanges(selectedSingleFolder); menu?.Open(control); e.Handled = true; }