diff --git a/.editorconfig b/.editorconfig
index 56725e7b..f3c9a7bf 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -71,20 +71,20 @@ dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
-dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
-dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# private static fields should have s_ prefix
dotnet_naming_rule.private_static_fields_should_have_prefix.severity = suggestion
-dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields
+dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields
dotnet_naming_rule.private_static_fields_should_have_prefix.style = private_static_prefix_style
-dotnet_naming_symbols.private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields.applicable_kinds = field
dotnet_naming_symbols.private_static_fields.required_modifiers = static
dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private
@@ -93,7 +93,7 @@ dotnet_naming_style.private_static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
-dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
+dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
diff --git a/TRANSLATION.md b/TRANSLATION.md
index 051440f0..1fa3259d 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -6,48 +6,24 @@ This document shows the translation status of each locale file in the repository
### 
-### 
+### 
+
+### 
-Missing keys in de_DE.axaml
+Missing keys in es_ES.axaml
-- Text.Avatar.Load
-- Text.BranchCM.ResetToSelectedCommit
-- Text.Checkout.WithFastForward
-- Text.Checkout.WithFastForward.Upstream
-- Text.CommitDetail.Changes.Count
-- Text.CreateBranch.OverwriteExisting
-- Text.DeinitSubmodule
-- Text.DeinitSubmodule.Force
-- Text.DeinitSubmodule.Path
-- Text.Diff.Submodule.Deleted
-- Text.GitFlow.FinishWithPush
-- Text.GitFlow.FinishWithSquash
-- Text.Hotkeys.Global.SwitchWorkspace
-- Text.Hotkeys.Global.SwitchTab
-- Text.Hotkeys.TextEditor.OpenExternalMergeTool
-- Text.Launcher.Workspaces
-- Text.Launcher.Pages
-- Text.Pull.RecurseSubmodules
-- Text.Repository.ClearStashes
-- Text.Repository.ShowSubmodulesAsTree
-- Text.ResetWithoutCheckout
-- Text.ResetWithoutCheckout.MoveTo
-- Text.ResetWithoutCheckout.Target
-- Text.Submodule.Deinit
-- Text.Submodule.Status
-- Text.Submodule.Status.Modified
-- Text.Submodule.Status.NotInited
-- Text.Submodule.Status.RevisionChanged
-- Text.Submodule.Status.Unmerged
-- Text.Submodule.URL
-- Text.WorkingCopy.ResetAuthor
+- Text.CommitCM.PushRevision
+- Text.Merge.Edit
+- Text.Push.Revision
+- Text.Push.Revision.Title
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
+- Text.WorkingCopy.AddToGitIgnore.InFolder
-### 
-
-### 
+### 
Missing keys in fr_FR.axaml
@@ -67,6 +43,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
@@ -86,8 +63,11 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -99,6 +79,8 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
@@ -110,6 +92,7 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -119,7 +102,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in it_IT.axaml
@@ -128,6 +111,7 @@ This document shows the translation status of each locale file in the repository
- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
@@ -138,17 +122,23 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.Global.SwitchTab
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.ClearStashes
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.Submodule.Deinit
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.ResetAuthor
-### 
+### 
Missing keys in ja_JP.axaml
@@ -169,6 +159,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
@@ -188,8 +179,11 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -202,6 +196,8 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
@@ -213,6 +209,7 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -222,7 +219,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in pt_BR.axaml
@@ -254,6 +251,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopySubject
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
@@ -294,6 +292,7 @@ This document shows the translation status of each locale file in the repository
- Text.InProgress.Revert.Head
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Merge.Source
- Text.MergeMultiple
- Text.MergeMultiple.CommitChanges
@@ -307,6 +306,8 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.SSLVerify
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -335,8 +336,8 @@ This document shows the translation status of each locale file in the repository
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
-- Text.Stash.AutoRestore
-- Text.Stash.AutoRestore.Tip
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.StashCM.SaveAsPatch
- Text.Submodule.Deinit
- Text.Submodule.Status
@@ -349,6 +350,7 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
@@ -360,17 +362,9 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
-
-Missing keys in ru_RU.axaml
-
-- Text.Checkout.WithFastForward
-- Text.Checkout.WithFastForward.Upstream
-
-
-
-### 
+### 
Missing keys in ta_IN.axaml
@@ -391,6 +385,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
@@ -410,8 +405,11 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -423,6 +421,8 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
@@ -435,6 +435,7 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
@@ -443,7 +444,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in uk_UA.axaml
@@ -463,6 +464,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.PushRevision
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.ConfigureWorkspace.Name
@@ -478,8 +480,11 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Merge.Edit
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
+- Text.Push.Revision
+- Text.Push.Revision.Title
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -491,6 +496,8 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.Stash.Mode
+- Text.StashCM.CopyMessage
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
@@ -502,6 +509,7 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
+- Text.WorkingCopy.AddToGitIgnore.InFolder
- Text.WorkingCopy.ResetAuthor
diff --git a/VERSION b/VERSION
index d3e094ba..11692c6b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.22
\ No newline at end of file
+2025.23
\ No newline at end of file
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index 8e579373..6b42700d 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -521,7 +521,7 @@ namespace SourceGit
private bool TryLaunchAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
{
var args = desktop.Args;
- if (args == null || args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal))
+ if (args is not { Length: > 1 } || !args[0].Equals("--core-editor", StringComparison.Ordinal))
return false;
var file = args[1];
@@ -531,8 +531,8 @@ namespace SourceGit
return true;
}
- var editor = new Views.StandaloneCommitMessageEditor();
- editor.SetFile(file);
+ var editor = new Views.CommitMessageEditor();
+ editor.AsStandalone(file);
desktop.MainWindow = editor;
return true;
}
diff --git a/src/Commands/Merge.cs b/src/Commands/Merge.cs
index b08377b9..32898593 100644
--- a/src/Commands/Merge.cs
+++ b/src/Commands/Merge.cs
@@ -5,11 +5,20 @@ namespace SourceGit.Commands
{
public class Merge : Command
{
- public Merge(string repo, string source, string mode)
+ public Merge(string repo, string source, string mode, bool edit)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"merge --progress {source} {mode}";
+ Editor = EditorType.CoreEditor;
+
+ var builder = new StringBuilder();
+ builder.Append("merge --progress ");
+ builder.Append(edit ? "--edit " : "--no-edit ");
+ builder.Append(source);
+ builder.Append(' ');
+ builder.Append(mode);
+
+ Args = builder.ToString();
}
public Merge(string repo, List targets, bool autoCommit, string strategy)
diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs
index d0ecd322..f268d709 100644
--- a/src/Commands/QueryBranches.cs
+++ b/src/Commands/QueryBranches.cs
@@ -48,16 +48,12 @@ namespace SourceGit.Commands
if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
{
b.IsUpstreamGone = false;
-
- if (b.TrackStatus == null)
- b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result();
+ b.TrackStatus ??= new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result();
}
else
{
b.IsUpstreamGone = true;
-
- if (b.TrackStatus == null)
- b.TrackStatus = new Models.BranchTrackStatus();
+ b.TrackStatus ??= new Models.BranchTrackStatus();
}
}
}
diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs
index b4067aaf..2b8987b6 100644
--- a/src/Commands/QueryStashes.cs
+++ b/src/Commands/QueryStashes.cs
@@ -9,7 +9,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = "stash list --format=%H%n%P%n%ct%n%gd%n%s";
+ Args = $"stash list -z --no-show-signature --format=\"%H%n%P%n%ct%n%gd%n%B\"";
}
public List Result()
@@ -19,55 +19,50 @@ namespace SourceGit.Commands
if (!rs.IsSuccess)
return outs;
- var nextPartIdx = 0;
- var start = 0;
- var end = rs.StdOut.IndexOf('\n', start);
- while (end > 0)
+ var items = rs.StdOut.Split('\0', StringSplitOptions.RemoveEmptyEntries);
+ foreach (var item in items)
{
- var line = rs.StdOut.Substring(start, end - start);
+ var current = new Models.Stash();
- switch (nextPartIdx)
+ var nextPartIdx = 0;
+ var start = 0;
+ var end = item.IndexOf('\n', start);
+ while (end > 0 && nextPartIdx < 4)
{
- case 0:
- _current = new Models.Stash() { SHA = line };
- outs.Add(_current);
- break;
- case 1:
- ParseParent(line);
- break;
- case 2:
- _current.Time = ulong.Parse(line);
- break;
- case 3:
- _current.Name = line;
- break;
- case 4:
- _current.Message = line;
+ var line = item.Substring(start, end - start);
+
+ switch (nextPartIdx)
+ {
+ case 0:
+ current.SHA = line;
+ break;
+ case 1:
+ if (line.Length > 6)
+ current.Parents.AddRange(line.Split(' ', StringSplitOptions.RemoveEmptyEntries));
+ break;
+ case 2:
+ current.Time = ulong.Parse(line);
+ break;
+ case 3:
+ current.Name = line;
+ break;
+ }
+
+ nextPartIdx++;
+
+ start = end + 1;
+ if (start >= item.Length - 1)
break;
+
+ end = item.IndexOf('\n', start);
}
- nextPartIdx++;
- if (nextPartIdx > 4)
- nextPartIdx = 0;
+ if (start < item.Length)
+ current.Message = item.Substring(start);
- start = end + 1;
- end = rs.StdOut.IndexOf('\n', start);
+ outs.Add(current);
}
-
- if (start < rs.StdOut.Length)
- _current.Message = rs.StdOut.Substring(start);
-
return outs;
}
-
- private void ParseParent(string data)
- {
- if (data.Length < 8)
- return;
-
- _current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
- }
-
- private Models.Stash _current = null;
}
}
diff --git a/src/Commands/QueryTags.cs b/src/Commands/QueryTags.cs
index 4b706439..896d555e 100644
--- a/src/Commands/QueryTags.cs
+++ b/src/Commands/QueryTags.cs
@@ -24,7 +24,7 @@ namespace SourceGit.Commands
var records = rs.StdOut.Split(_boundary, StringSplitOptions.RemoveEmptyEntries);
foreach (var record in records)
{
- var subs = record.Split('\0', StringSplitOptions.None);
+ var subs = record.Split('\0');
if (subs.Length != 6)
continue;
diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs
index 550844ef..64e8f8a5 100644
--- a/src/Commands/SaveRevisionFile.cs
+++ b/src/Commands/SaveRevisionFile.cs
@@ -10,6 +10,10 @@ namespace SourceGit.Commands
{
public static void Run(string repo, string revision, string file, string saveTo)
{
+ var dir = Path.GetDirectoryName(saveTo);
+ if (!Directory.Exists(dir))
+ Directory.CreateDirectory(dir);
+
var isLFSFiltered = new IsLFSFiltered(repo, revision, file).Result();
if (isLFSFiltered)
{
@@ -22,7 +26,7 @@ namespace SourceGit.Commands
}
}
- private static bool ExecCmd(string repo, string args, string outputFile, Stream input = null)
+ private static void ExecCmd(string repo, string args, string outputFile, Stream input = null)
{
var starter = new ProcessStartInfo();
starter.WorkingDirectory = repo;
@@ -45,10 +49,7 @@ namespace SourceGit.Commands
proc.StandardInput.Write(new StreamReader(input).ReadToEnd());
proc.StandardOutput.BaseStream.CopyTo(sw);
proc.WaitForExit();
- var rs = proc.ExitCode == 0;
proc.Close();
-
- return rs;
}
catch (Exception e)
{
@@ -56,7 +57,6 @@ namespace SourceGit.Commands
{
App.RaiseException(repo, "Save file failed: " + e.Message);
});
- return false;
}
}
}
diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs
index fa07975d..bc9fbe95 100644
--- a/src/Models/AvatarManager.cs
+++ b/src/Models/AvatarManager.cs
@@ -26,10 +26,7 @@ namespace SourceGit.Models
{
get
{
- if (_instance == null)
- _instance = new AvatarManager();
-
- return _instance;
+ return _instance ??= new AvatarManager();
}
}
diff --git a/src/Models/DealWithChangesAfterStashing.cs b/src/Models/DealWithChangesAfterStashing.cs
new file mode 100644
index 00000000..63889c96
--- /dev/null
+++ b/src/Models/DealWithChangesAfterStashing.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace SourceGit.Models
+{
+ public class DealWithChangesAfterStashing
+ {
+ public string Label { get; set; }
+ public string Desc { get; set; }
+
+ public static readonly List Supported = [
+ new ("Discard", "All (or selected) changes will be discarded"),
+ new ("Keep Index", "Staged changes are left intact"),
+ new ("Keep All", "All (or selected) changes are left intact"),
+ ];
+
+ public DealWithChangesAfterStashing(string label, string desc)
+ {
+ Label = label;
+ Desc = desc;
+ }
+ }
+}
diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs
index b2d91310..71ed2d9e 100644
--- a/src/Models/DiffResult.cs
+++ b/src/Models/DiffResult.cs
@@ -16,11 +16,10 @@ namespace SourceGit.Models
Deleted,
}
- public class TextInlineRange
+ public class TextInlineRange(int p, int n)
{
- public int Start { get; set; }
- public int End { get; set; }
- public TextInlineRange(int p, int n) { Start = p; End = p + n - 1; }
+ public int Start { get; set; } = p;
+ public int End { get; set; } = p + n - 1;
}
public class TextDiffLine
@@ -556,7 +555,7 @@ namespace SourceGit.Models
}
else if (test.Type == TextDiffLineType.Added)
{
- if (i < start - 1)
+ if (i < start - 1 || isOldSide)
{
if (revert)
{
@@ -566,18 +565,7 @@ namespace SourceGit.Models
}
else
{
- if (isOldSide)
- {
- if (revert)
- {
- newCount++;
- oldCount++;
- }
- }
- else
- {
- newCount++;
- }
+ newCount++;
}
if (i == end - 1 && tailed)
@@ -655,9 +643,7 @@ namespace SourceGit.Models
public string NewImageSize => New != null ? $"{New.PixelSize.Width} x {New.PixelSize.Height}" : "0 x 0";
}
- public class NoOrEOLChange
- {
- }
+ public class NoOrEOLChange;
public class FileModeDiff
{
diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs
index 103e91bc..697c171a 100644
--- a/src/Models/ExternalTool.cs
+++ b/src/Models/ExternalTool.cs
@@ -107,8 +107,7 @@ namespace SourceGit.Models
// Ignore
}
- if (_customPaths == null)
- _customPaths = new ExternalToolPaths();
+ _customPaths ??= new ExternalToolPaths();
}
public void TryAdd(string name, string icon, Func finder, Func execArgsGenerator = null)
diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs
index c2a6c6c7..001c65a6 100644
--- a/src/Models/IpcChannel.cs
+++ b/src/Models/IpcChannel.cs
@@ -8,10 +8,7 @@ namespace SourceGit.Models
{
public class IpcChannel : IDisposable
{
- public bool IsFirstInstance
- {
- get => _isFirstInstance;
- }
+ public bool IsFirstInstance { get; }
public event Action MessageReceived;
@@ -20,7 +17,7 @@ namespace SourceGit.Models
try
{
_singletonLock = File.Open(Path.Combine(Native.OS.DataDir, "process.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
- _isFirstInstance = true;
+ IsFirstInstance = true;
_server = new NamedPipeServerStream(
"SourceGitIPCChannel" + Environment.UserName,
PipeDirection.In,
@@ -32,7 +29,7 @@ namespace SourceGit.Models
}
catch
{
- _isFirstInstance = false;
+ IsFirstInstance = false;
}
}
@@ -97,7 +94,6 @@ namespace SourceGit.Models
}
private FileStream _singletonLock = null;
- private bool _isFirstInstance = false;
private NamedPipeServerStream _server = null;
private CancellationTokenSource _cancellationTokenSource = null;
}
diff --git a/src/Models/Null.cs b/src/Models/Null.cs
index e22ef8b3..1820d4d0 100644
--- a/src/Models/Null.cs
+++ b/src/Models/Null.cs
@@ -1,6 +1,4 @@
namespace SourceGit.Models
{
- public class Null
- {
- }
+ public class Null;
}
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index a54956d3..4e51b368 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -176,17 +176,11 @@ namespace SourceGit.Models
set;
} = false;
- public bool KeepIndexWhenStash
+ public int ChangesAfterStashing
{
get;
set;
- } = false;
-
- public bool AutoRestoreAfterStash
- {
- get;
- set;
- } = false;
+ } = 0;
public string PreferredOpenAIService
{
diff --git a/src/Models/SelfUpdate.cs b/src/Models/SelfUpdate.cs
index e02f80d8..05fa6124 100644
--- a/src/Models/SelfUpdate.cs
+++ b/src/Models/SelfUpdate.cs
@@ -33,9 +33,7 @@ namespace SourceGit.Models
}
}
- public class AlreadyUpToDate
- {
- }
+ public class AlreadyUpToDate;
public class SelfUpdateFailed
{
diff --git a/src/Models/Stash.cs b/src/Models/Stash.cs
index 369ab145..2b77be50 100644
--- a/src/Models/Stash.cs
+++ b/src/Models/Stash.cs
@@ -11,6 +11,24 @@ namespace SourceGit.Models
public ulong Time { get; set; } = 0;
public string Message { get; set; } = "";
- public string TimeStr => DateTime.UnixEpoch.AddSeconds(Time).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
+ public string Subject
+ {
+ get
+ {
+ var idx = Message.IndexOf('\n', StringComparison.Ordinal);
+ return idx > 0 ? Message.Substring(0, idx).Trim() : Message;
+ }
+ }
+
+ public string TimeStr
+ {
+ get
+ {
+ return DateTime.UnixEpoch
+ .AddSeconds(Time)
+ .ToLocalTime()
+ .ToString(DateTimeFormat.Active.DateTime);
+ }
+ }
}
}
diff --git a/src/Models/TemplateEngine.cs b/src/Models/TemplateEngine.cs
index c54f55fb..8f60bd74 100644
--- a/src/Models/TemplateEngine.cs
+++ b/src/Models/TemplateEngine.cs
@@ -102,7 +102,7 @@ namespace SourceGit.Models
private int? Integer()
{
var start = _pos;
- while (Peek() is char c && c >= '0' && c <= '9')
+ while (Peek() is >= '0' and <= '9')
{
_pos++;
}
@@ -118,7 +118,7 @@ namespace SourceGit.Models
// text token start
var tok = _pos;
bool esc = false;
- while (Next() is char c)
+ while (Next() is { } c)
{
if (esc)
{
@@ -129,7 +129,7 @@ namespace SourceGit.Models
{
case ESCAPE:
// allow to escape only \ and $
- if (Peek() is char nc && (nc == ESCAPE || nc == VARIABLE_ANCHOR))
+ if (Peek() is { } nc && (nc == ESCAPE || nc == VARIABLE_ANCHOR))
{
esc = true;
FlushText(tok, _pos - 1);
@@ -173,7 +173,7 @@ namespace SourceGit.Models
if (Next() != VARIABLE_START)
return null;
int name_start = _pos;
- while (Next() is char c)
+ while (Next() is { } c)
{
// name character, continue advancing
if (IsNameChar(c))
@@ -228,7 +228,7 @@ namespace SourceGit.Models
var sb = new StringBuilder();
var tok = _pos;
var esc = false;
- while (Next() is char c)
+ while (Next() is { } c)
{
if (esc)
{
@@ -277,7 +277,7 @@ namespace SourceGit.Models
var sb = new StringBuilder();
var tok = _pos;
var esc = false;
- while (Next() is char c)
+ while (Next() is { } c)
{
if (esc)
{
diff --git a/src/Models/TextInlineChange.cs b/src/Models/TextInlineChange.cs
index 15901d03..afe5bec4 100644
--- a/src/Models/TextInlineChange.cs
+++ b/src/Models/TextInlineChange.cs
@@ -2,27 +2,19 @@
namespace SourceGit.Models
{
- public class TextInlineChange
+ public class TextInlineChange(int dp, int dc, int ap, int ac)
{
- public int DeletedStart { get; set; }
- public int DeletedCount { get; set; }
- public int AddedStart { get; set; }
- public int AddedCount { get; set; }
+ public int DeletedStart { get; set; } = dp;
+ public int DeletedCount { get; set; } = dc;
+ public int AddedStart { get; set; } = ap;
+ public int AddedCount { get; set; } = ac;
- private class Chunk
+ private class Chunk(int hash, int start, int size)
{
- public int Hash;
+ public readonly int Hash = hash;
+ public readonly int Start = start;
+ public readonly int Size = size;
public bool Modified;
- public int Start;
- public int Size;
-
- public Chunk(int hash, int start, int size)
- {
- Hash = hash;
- Modified = false;
- Start = start;
- Size = size;
- }
}
private enum Edit
@@ -43,14 +35,6 @@ namespace SourceGit.Models
public int AddEnd;
}
- public TextInlineChange(int dp, int dc, int ap, int ac)
- {
- DeletedStart = dp;
- DeletedCount = dc;
- AddedStart = ap;
- AddedCount = ac;
- }
-
public static List Compare(string oldValue, string newValue)
{
var hashes = new Dictionary();
diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs
index a3cfc329..4d6656e3 100644
--- a/src/Models/Watcher.cs
+++ b/src/Models/Watcher.cs
@@ -12,27 +12,50 @@ namespace SourceGit.Models
{
_repo = repo;
- _wcWatcher = new FileSystemWatcher();
- _wcWatcher.Path = fullpath;
- _wcWatcher.Filter = "*";
- _wcWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
- _wcWatcher.IncludeSubdirectories = true;
- _wcWatcher.Created += OnWorkingCopyChanged;
- _wcWatcher.Renamed += OnWorkingCopyChanged;
- _wcWatcher.Changed += OnWorkingCopyChanged;
- _wcWatcher.Deleted += OnWorkingCopyChanged;
- _wcWatcher.EnableRaisingEvents = true;
+ var testGitDir = new DirectoryInfo(Path.Combine(fullpath, ".git")).FullName;
+ var desiredDir = new DirectoryInfo(gitDir).FullName;
+ if (testGitDir.Equals(desiredDir, StringComparison.Ordinal))
+ {
+ var combined = new FileSystemWatcher();
+ combined.Path = fullpath;
+ combined.Filter = "*";
+ combined.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
+ combined.IncludeSubdirectories = true;
+ combined.Created += OnRepositoryChanged;
+ combined.Renamed += OnRepositoryChanged;
+ combined.Changed += OnRepositoryChanged;
+ combined.Deleted += OnRepositoryChanged;
+ combined.EnableRaisingEvents = true;
- _repoWatcher = new FileSystemWatcher();
- _repoWatcher.Path = gitDir;
- _repoWatcher.Filter = "*";
- _repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
- _repoWatcher.IncludeSubdirectories = true;
- _repoWatcher.Created += OnRepositoryChanged;
- _repoWatcher.Renamed += OnRepositoryChanged;
- _repoWatcher.Changed += OnRepositoryChanged;
- _repoWatcher.Deleted += OnRepositoryChanged;
- _repoWatcher.EnableRaisingEvents = true;
+ _watchers.Add(combined);
+ }
+ else
+ {
+ var wc = new FileSystemWatcher();
+ wc.Path = fullpath;
+ wc.Filter = "*";
+ wc.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
+ wc.IncludeSubdirectories = true;
+ wc.Created += OnWorkingCopyChanged;
+ wc.Renamed += OnWorkingCopyChanged;
+ wc.Changed += OnWorkingCopyChanged;
+ wc.Deleted += OnWorkingCopyChanged;
+ wc.EnableRaisingEvents = true;
+
+ var git = new FileSystemWatcher();
+ git.Path = gitDir;
+ git.Filter = "*";
+ git.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
+ git.IncludeSubdirectories = true;
+ git.Created += OnGitDirChanged;
+ git.Renamed += OnGitDirChanged;
+ git.Changed += OnGitDirChanged;
+ git.Deleted += OnGitDirChanged;
+ git.EnableRaisingEvents = true;
+
+ _watchers.Add(wc);
+ _watchers.Add(git);
+ }
_timer = new Timer(Tick, null, 100, 100);
}
@@ -77,22 +100,13 @@ namespace SourceGit.Models
public void Dispose()
{
- _repoWatcher.EnableRaisingEvents = false;
- _repoWatcher.Created -= OnRepositoryChanged;
- _repoWatcher.Renamed -= OnRepositoryChanged;
- _repoWatcher.Changed -= OnRepositoryChanged;
- _repoWatcher.Deleted -= OnRepositoryChanged;
- _repoWatcher.Dispose();
- _repoWatcher = null;
-
- _wcWatcher.EnableRaisingEvents = false;
- _wcWatcher.Created -= OnWorkingCopyChanged;
- _wcWatcher.Renamed -= OnWorkingCopyChanged;
- _wcWatcher.Changed -= OnWorkingCopyChanged;
- _wcWatcher.Deleted -= OnWorkingCopyChanged;
- _wcWatcher.Dispose();
- _wcWatcher = null;
+ foreach (var watcher in _watchers)
+ {
+ watcher.EnableRaisingEvents = false;
+ watcher.Dispose();
+ }
+ _watchers.Clear();
_timer.Dispose();
_timer = null;
}
@@ -153,11 +167,45 @@ namespace SourceGit.Models
}
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
+ {
+ if (string.IsNullOrEmpty(e.Name) || e.Name.Equals(".git", StringComparison.Ordinal))
+ return;
+
+ var name = e.Name.Replace('\\', '/').TrimEnd('/');
+ if (name.EndsWith("/.git", StringComparison.Ordinal))
+ return;
+
+ if (name.StartsWith(".git/", StringComparison.Ordinal))
+ HandleGitDirFileChanged(name.Substring(5));
+ else
+ HandleWorkingCopyFileChanged(name);
+ }
+
+ private void OnGitDirChanged(object o, FileSystemEventArgs e)
{
if (string.IsNullOrEmpty(e.Name))
return;
var name = e.Name.Replace('\\', '/').TrimEnd('/');
+ HandleGitDirFileChanged(name);
+ }
+
+ private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
+ {
+ if (string.IsNullOrEmpty(e.Name))
+ return;
+
+ var name = e.Name.Replace('\\', '/').TrimEnd('/');
+ if (name.Equals(".git", StringComparison.Ordinal) ||
+ name.StartsWith(".git/", StringComparison.Ordinal) ||
+ name.EndsWith("/.git", StringComparison.Ordinal))
+ return;
+
+ HandleWorkingCopyFileChanged(name);
+ }
+
+ private void HandleGitDirFileChanged(string name)
+ {
if (name.Contains("fsmonitor--daemon/", StringComparison.Ordinal) ||
name.EndsWith(".lock", StringComparison.Ordinal) ||
name.StartsWith("lfs/", StringComparison.Ordinal))
@@ -200,17 +248,8 @@ namespace SourceGit.Models
}
}
- private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
+ private void HandleWorkingCopyFileChanged(string name)
{
- if (string.IsNullOrEmpty(e.Name))
- return;
-
- var name = e.Name.Replace('\\', '/').TrimEnd('/');
- if (name.Equals(".git", StringComparison.Ordinal) ||
- name.StartsWith(".git/", StringComparison.Ordinal) ||
- name.EndsWith("/.git", StringComparison.Ordinal))
- return;
-
if (name.StartsWith(".vs/", StringComparison.Ordinal))
return;
@@ -236,8 +275,7 @@ namespace SourceGit.Models
}
private readonly IRepository _repo = null;
- private FileSystemWatcher _repoWatcher = null;
- private FileSystemWatcher _wcWatcher = null;
+ private List _watchers = [];
private Timer _timer = null;
private int _lockCount = 0;
private long _updateWC = 0;
diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs
index 07cf51fb..06d80bf0 100644
--- a/src/Native/Windows.cs
+++ b/src/Native/Windows.cs
@@ -54,7 +54,7 @@ namespace SourceGit.Native
public void SetupApp(AppBuilder builder)
{
// Fix drop shadow issue on Windows 10
- if (!OperatingSystem.IsWindowsVersionAtLeast(10, 22000, 0))
+ if (!OperatingSystem.IsWindowsVersionAtLeast(10, 22000))
{
Window.WindowStateProperty.Changed.AddClassHandler((w, _) => FixWindowFrameOnWin10(w));
Control.LoadedEvent.AddClassHandler((w, _) => FixWindowFrameOnWin10(w));
@@ -385,11 +385,11 @@ namespace SourceGit.Native
Microsoft.Win32.RegistryView.Registry64);
// Get default class for VisualStudio.Launcher.sln - the handler for *.sln files
- if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is Microsoft.Win32.RegistryKey launcher)
+ if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is { } launcher)
{
// Get actual path to the executable
if (launcher.GetValue(string.Empty) is string CLSID &&
- localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv &&
+ localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is { } devenv &&
devenv.GetValue(string.Empty) is string localServer32)
return localServer32!.Trim('\"');
}
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index 032e5ce7..99d9f77c 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -39,6 +39,7 @@
ALS UNVERÄNDERT ANGENOMMENE DATEIEN
KEINE ALS UNVERÄNDERT ANGENOMMENEN DATEIEN
ENTFERNEN
+ Bild laden...
Aktualisieren
BINÄRE DATEI NICHT UNTERSTÜTZT!!!
Bisect
@@ -67,6 +68,7 @@
Push ${0}$
Rebase ${0}$ auf ${1}$...
Benenne ${0}$ um...
+ Setze ${0}$ zurück auf ${1}$...
Setze verfolgten Branch...
Branch Vergleich
Ungültiger upstream!
@@ -88,6 +90,8 @@
Stashen & wieder anwenden
Alle Submodule updaten
Branch:
+ Auschecken & Fast-Forward
+ Fast-Forward zu:
Cherry Pick
Quelle an Commit-Nachricht anhängen
Commit(s):
@@ -120,6 +124,7 @@
Interactives Rebase von ${0}$ auf diesen Commit
Merge in ${0}$ hinein
Merge ...
+ Push ${0}$ zu ${1}$
Rebase von ${0}$ auf diesen Commit
Reset ${0}$ auf diesen Commit
Commit rückgängig machen
@@ -128,6 +133,7 @@
Squash in den Vorgänger
Squash Nachfolger Commits bis hier
ÄNDERUNGEN
+ geänderte Datei(en)
Änderungen durchsuchen...
DATEIEN
LFS DATEI
@@ -219,6 +225,7 @@
Branch-Namen eingeben.
Leerzeichen werden durch Bindestriche ersetzt.
Lokalen Branch erstellen
+ Überschreibe existierenden Branch
Tag erstellen...
Neuer Tag auf:
Mit GPG signieren
@@ -233,6 +240,9 @@
Ohne Anmerkung
Halte Strg gedrückt, um direkt auszuführen
Ausschneiden
+ De-initialisiere Submodul
+ Erzwinge De-Initialisierung, selbst wenn es lokale Änderungen enthält.
+ Submodul:
Branch löschen
Branch:
Du löscht gerade einen Remote-Branch!!!
@@ -268,6 +278,7 @@
Zeige versteckte Symbole
Nebeneinander
SUBMODUL
+ GELÖSCHT
NEU
Seiten wechseln
Syntax Hervorhebung
@@ -326,6 +337,8 @@
FLOW - Finish Hotfix
FLOW - Finish Release
Ziel:
+ Push zu Remote(s) nach Durchführung des Finish
+ Squash beim Merge
Hotfix:
Hotfix-Prefix:
Git-Flow initialisieren
@@ -387,6 +400,8 @@
Zum vorherigen Tab wechseln
Neuen Tab erstellen
Einstellungen öffnen
+ Aktiven Arbeitsplatz wechseln
+ Aktiven Tab wechseln
REPOSITORY
Gestagte Änderungen committen
Gestagte Änderungen committen und pushen
@@ -407,6 +422,7 @@
Suchpanel schließen
Suche nächste Übereinstimmung
Suche vorherige Übereinstimmung
+ Öffne mit externem Diff/Merge Tool
Öffne Suchpanel
Verwerfen
Stagen
@@ -428,7 +444,10 @@
In Browser öffnen
FEHLER
INFO
+ Arbeitsplätze
+ Tabs
Branch mergen
+ Merge-Nachricht anpassen
Ziel-Branch:
Merge Option:
Quelle:
@@ -461,6 +480,7 @@
Vor {0} Monaten
Vor {0} Jahren
Gestern
+ Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button
Einstellungen
OPEN AI
Analysierung des Diff Befehl
@@ -530,6 +550,7 @@
Lokale Änderungen:
Verwerfen
Stashen & wieder anwenden
+ Alle Submodule aktualisieren
Remote:
Pull (Fetch & Merge)
Rebase anstatt Merge verwenden
@@ -538,6 +559,8 @@
Erzwinge Push
Lokaler Branch:
Remote:
+ Revision:
+ Push Revision zu Remote-Branch
Push
Remote-Branch:
Remote-Branch verfolgen
@@ -578,6 +601,7 @@
Aufräumen (GC & Prune)
Führt `git gc` auf diesem Repository aus.
Filter aufheben
+ Löschen
Repository Einstellungen
WEITER
Benutzerdefinierte Aktionen
@@ -615,6 +639,7 @@
Commit-Nachricht
SHA
Aktueller Branch
+ Submodule als Baum anzeigen
Zeige Tags als Baum
ÜBERSPRINGEN
Statistiken
@@ -638,12 +663,14 @@
Rücksetzmodus:
Verschiebe zu:
Aktueller Branch:
+ Reset Branch (ohne Checkout)
+ Auf:
+ Branch:
Zeige im Datei-Explorer
Commit rückgängig machen
Commit:
Commit Änderungen rückgängig machen
Commit Nachricht umformulieren
- Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button
Bitte warten...
SPEICHERN
Speichern als...
@@ -669,16 +696,15 @@
Pfad zum privaten SSH Schlüssel
START
Stash
- Automatisch wiederherstellen nach dem Stashen
- Die Arbeitsdateien bleiben unverändert, aber ein Stash wird gespeichert.
Inklusive nicht-verfolgter Dateien
- Behalte gestagte Dateien
Name:
- Optional. Name dieses Stashes
+ Optional. Informationen zu dieses Stashes
+ Modus:
Nur gestagte Änderungen
Gestagte und unstagte Änderungen der ausgewähleten Datei(en) werden gestasht!!!
Lokale Änderungen stashen
Anwenden
+ Kopiere Nachricht
Entfernen
Als Path speichern...
Stash entfernen
@@ -697,11 +723,18 @@
SUBMODULE
Submodul hinzufügen
Relativen Pfad kopieren
+ De-initialisiere Submodul
Untergeordnete Submodule fetchen
Öffne Submodul Repository
Relativer Pfad:
Relativer Ordner um dieses Submodul zu speichern.
Submodul löschen
+ STATUS
+ geändert
+ nicht initialisiert
+ Revision geändert
+ nicht gemerged
+ URL
OK
Tag-Namen kopieren
Tag-Nachricht kopieren
@@ -738,7 +771,7 @@
Git Ignore
Ignoriere alle *{0} Dateien
Ignoriere *{0} Datein im selben Ordner
- Ignoriere Dateien im selben Ordner
+ Ignoriere nicht-verfolgte Dateien in diesem Ordner
Ignoriere nur diese Datei
Amend
Du kannst diese Datei jetzt stagen.
@@ -758,6 +791,7 @@
NICHT-VERFOLGTE DATEIEN INKLUDIEREN
KEINE BISHERIGEN COMMIT-NACHRICHTEN
KEINE COMMIT TEMPLATES
+ Autor zurücksetzen
Rechtsklick auf selektierte Dateien und wähle die Konfliktlösungen aus.
SignOff
GESTAGED
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index ee035551..d4b4d26f 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -120,6 +120,7 @@
Interactively Rebase ${0}$ on Here
Merge to ${0}$
Merge ...
+ Push ${0}$ to ${1}$
Rebase ${0}$ on Here
Reset ${0}$ to Here
Revert Commit
@@ -442,6 +443,7 @@
Workspaces
Pages
Merge Branch
+ Customize merge message
Into:
Merge Option:
Source:
@@ -474,6 +476,7 @@
{0} months ago
{0} years ago
Yesterday
+ Use 'Shift+Enter' to input a new line. 'Enter' is the hotkey of OK button
Preferences
AI
Analyze Diff Prompt
@@ -552,6 +555,8 @@
Force push
Local Branch:
Remote:
+ Revision:
+ Push Revision To Remote
Push Changes To Remote
Remote Branch:
Set as tracking branch
@@ -662,7 +667,6 @@
Commit:
Commit revert changes
Reword Commit Message
- Use 'Shift+Enter' to input a new line. 'Enter' is the hotkey of OK button
Running. Please wait...
SAVE
Save As...
@@ -688,16 +692,15 @@
Private SSH key store path
START
Stash
- Auto-restore after stashing
- Your working files remain unchanged, but a stash is saved.
Include untracked files
- Keep staged files
Message:
- Optional. Name of this stash
+ Optional. Message of this stash
+ Mode:
Only staged changes
Both staged and unstaged changes of selected file(s) will be stashed!!!
Stash Local Changes
Apply
+ Copy Message
Drop
Save as Patch...
Drop Stash
@@ -764,7 +767,7 @@
Git Ignore
Ignore all *{0} files
Ignore *{0} files in the same folder
- Ignore files in the same folder
+ Ignore untracked files in this folder
Ignore this file only
Amend
You can stage this file now.
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index 4f1a4452..d66e515a 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -478,6 +478,7 @@
Hace {0} meses
Hace {0} años
Ayer
+ Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK
Preferencias
OPEN AI
Analizar Diff Prompt
@@ -666,7 +667,6 @@
Commit:
Commit revertir cambios
Reescribir Mensaje de Commit
- Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK
Ejecutando. Por favor espera...
GUARDAR
Guardar Como...
@@ -692,12 +692,9 @@
Ruta de almacenamiento de la clave privada SSH
INICIAR
Stash
- Restaurar automáticamente después del stashing
- Tus archivos de trabajo permanecen sin cambios, pero se guarda un stash.
Incluir archivos no rastreados
- Mantener archivos staged
Mensaje:
- Opcional. Nombre de este stash
+ Opcional. Información de este stash
Solo cambios staged
¡Tanto los cambios staged como los no staged de los archivos seleccionados serán stashed!
Stash Cambios Locales
@@ -768,7 +765,6 @@
Git Ignore
Ignorar todos los archivos *{0}
Ignorar archivos *{0} en la misma carpeta
- Ignorar archivos en la misma carpeta
Ignorar solo este archivo
Enmendar
Puedes hacer stage a este archivo ahora.
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 635d74c2..8e1fd7bd 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -444,6 +444,7 @@
il y a {0} mois
il y a {0} ans
Hier
+ Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider
Préférences
IA
Analyser Diff Prompt
@@ -619,7 +620,6 @@
Commit :
Commit les changements de l'annulation
Reformuler le message de commit
- Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider
En exécution. Veuillez patienter...
SAUVEGARDER
Sauvegarder en tant que...
@@ -645,12 +645,9 @@
Chemin du magasin de clés privées SSH
START
Stash
- Auto-restauration après le stash
- Vos fichiers de travail restent inchangés, mais une sauvegarde est enregistrée.
Inclure les fichiers non-suivis
- Garder les fichiers indexés
Message :
- Optionnel. Nom de ce stash
+ Optionnel. Information de ce stash
Seulement les changements indexés
Les modifications indexées et non-indexées des fichiers sélectionnés seront stockées!!!
Stash les changements locaux
@@ -710,7 +707,6 @@
Git Ignore
Ignorer tous les *{0} fichiers
Ignorer *{0} fichiers dans le même dossier
- Ignorer les fichiers dans le même dossier
N'ignorer que ce fichier
Amender
Vous pouvez indexer ce fichier.
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index 3aef0043..62f15e38 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -464,6 +464,7 @@
{0} mesi fa
{0} anni fa
Ieri
+ Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK
Preferenze
AI
Analizza il Prompt Differenza
@@ -647,7 +648,6 @@
Commit:
Commit delle modifiche di ripristino
Modifica Messaggio di Commit
- Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK
In esecuzione. Attendere...
SALVA
Salva come...
@@ -673,12 +673,9 @@
Percorso per la chiave SSH privata
AVVIA
Stasha
- Auto-ripristino dopo lo stash
- I tuoi file di lavoro rimangono inalterati, ma viene salvato uno stash.
Includi file non tracciati
- Mantieni file in stage
Messaggio:
- Opzionale. Nome di questo stash
+ Opzionale. Informazioni di questo stash
Solo modifiche in stage
Sia le modifiche in stage che quelle non in stage dei file selezionati saranno stashate!!!
Stasha Modifiche Locali
@@ -748,7 +745,6 @@
Git Ignore
Ignora tutti i file *{0}
Ignora i file *{0} nella stessa cartella
- Ignora i file nella stessa cartella
Ignora solo questo file
Modifica
Puoi aggiungere in stage questo file ora.
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
index 918a6b4d..bf9fe586 100644
--- a/src/Resources/Locales/ja_JP.axaml
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -443,6 +443,7 @@
{0} ヶ月前
{0} 年前
昨日
+ 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。
設定
AI
差分分析プロンプト
@@ -617,7 +618,6 @@
コミット:
コミットの変更を戻す
コミットメッセージを書き直す
- 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。
実行中です。しばらくお待ちください...
保存
名前を付けて保存...
@@ -643,12 +643,9 @@
プライベートSSHキーストアのパス
スタート
スタッシュ
- スタッシュ後に自動で復元
- 作業ファイルは変更されず、スタッシュが保存されます。
追跡されていないファイルを含める
- ステージされたファイルを保持
メッセージ:
- オプション. このスタッシュの名前を入力
+ オプション. このスタッシュの情報
ステージされた変更のみ
選択したファイルの、ステージされた変更とステージされていない変更の両方がスタッシュされます!!!
ローカルの変更をスタッシュ
@@ -708,7 +705,6 @@
Git Ignore
すべての*{0}ファイルを無視
同じフォルダ内の*{0}ファイルを無視
- 同じフォルダ内のファイルを無視
このファイルのみを無視
Amend
このファイルを今すぐステージできます。
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index f448a908..fecd9540 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -406,6 +406,7 @@
{0} meses atrás
{0} anos atrás
Ontem
+ Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK
Preferências
INTELIGÊNCIA ARTIFICIAL
Prompt para Analisar Diff
@@ -563,7 +564,6 @@
Commit:
Commitar alterações de reversão
Reescrever Mensagem do Commit
- Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK
Executando. Por favor, aguarde...
SALVAR
Salvar Como...
@@ -585,9 +585,8 @@
INICIAR
Stash
Incluir arquivos não rastreados
- Manter arquivos em stage
Mensagem:
- Opcional. Nome deste stash
+ Opcional. Informações deste stash
Apenas mudanças em stage
Tanto mudanças em stage e fora de stage dos arquivos selecionados serão enviadas para stash!!!
Guardar Alterações Locais
@@ -646,7 +645,6 @@
Git Ignore
Ignorar todos os arquivos *{0}
Ignorar arquivos *{0} na mesma pasta
- Ignorar arquivos na mesma pasta
Ignorar apenas este arquivo
Corrigir
Você pode stagear este arquivo agora.
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index a625df98..708ff7cc 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -90,6 +90,8 @@
Отложить и примненить повторно
Обновить все подкаталоги
Ветка:
+ Переключиться и перемотать
+ Перемотать к:
Частичный выбор
Добавить источник для ревизии сообщения
Ревизия(и):
@@ -122,6 +124,7 @@
Интерактивное перемещение (rebase -i) ${0}$ сюда
Влить в ${0}$
Влить ...
+ Выложить ${0}$ в ${1}$
Переместить ${0}$ сюда
Сбросить ${0}$ сюда
Отменить ревизию
@@ -444,6 +447,7 @@
Рабочие места
Страницы
Влить ветку
+ Изменить сообщение слияния
В:
Опции слияния:
Источник:
@@ -476,6 +480,7 @@
{0} месяцев назад
{0} лет назад
Вчера
+ Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK»
Параметры
ОТКРЫТЬ ИИ
Запрос на анализ сравнения
@@ -554,6 +559,8 @@
Принудительно выложить
Локальная ветка:
Внешний репозиторий:
+ Ревизия:
+ Выложить ревизию на удалёную
Выложить изменения на внешний репозиторий
Ветка внешнего репозитория:
Отслеживать ветку
@@ -664,7 +671,6 @@
Ревизия:
Отмена ревизии
Изменить комментарий ревизии
- Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK»
Запуск. Подождите пожалуйста...
СОХРАНИТЬ
Сохранить как...
@@ -690,16 +696,15 @@
Путь хранения приватного ключа SSH
ЗАПУСК
Отложить
- Автоматически восстанавливать после откладывания
- Ваши рабочие файлы остаются неизменными, но отложенные сохранятся.
Включить неотслеживаемые файлы
- Хранить отложенные файлы
Сообщение:
Имя тайника (необязательно)
+ Режим:
Только сформированные изменения
Сформированные так и несформированные изменения выбранных файлов будут сохранены!!!
Отложить локальные изменения
Принять
+ Копировать сообщение
Отбросить
Сохранить как заплатку...
Отбросить тайник
@@ -766,7 +771,7 @@
Игнорировать Git
Игнорировать все *{0} файлы
Игнорировать *{0} файлы в том же каталоге
- Игнорировать файлы в том же каталоге
+ Игнорировать неотслеживаемые файлы в этом каталоге
Игнорировать только эти файлы
Изменить
Теперь вы можете сформировать этот файл.
diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml
index abe53252..248d5f42 100644
--- a/src/Resources/Locales/ta_IN.axaml
+++ b/src/Resources/Locales/ta_IN.axaml
@@ -443,6 +443,7 @@
{0} திங்களுக்கு முன்பு
{0} ஆண்டுகளுக்கு முன்பு
நேற்று
+ புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும்
விருப்பத்தேர்வுகள்
செநு
வேறுபாடு உடனடியாக பகுப்பாய்வு செய்
@@ -618,7 +619,6 @@
உறுதிமொழி:
பின்வாங்கு மாற்றங்களை உறுதிமொழி
மாறுசொல் உறுதிமொழி செய்தி
- புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும்
இயங்குகிறது. காத்திருக்கவும்...
சேமி
எனச் சேமி...
@@ -644,10 +644,7 @@
தனியார் பாஓடு திறவுகோல் கடை பாதை
தொடங்கு
பதுக்கிவை
- பதுக்கிவைத்த பிறகு தானியங்கி மீட்டமை
- உங்கள் செயல்படும் கோப்புகள் மாறாமல் இருக்கும், ஆனால் ஒரு பதுக்கிவைக்கப்படும்.
கண்காணிக்கப்படாத கோப்புகளைச் சேர்
- நிலைப்படுத்தப்பட்ட கோப்புகளை வைத்திரு
செய்தி:
விருப்பத்தேர்வு. இந்த பதுக்கலின் பெயர்
நிலைப்படுத்தப்பட்ட மாற்றங்கள் மட்டும்
@@ -708,7 +705,6 @@
அறிவிலி புறக்கணி
எல்லா *{0} கோப்புகளையும் புறக்கணி
ஒரே கோப்புறையில் *{0} கோப்புகளைப் புறக்கணி
- ஒரே கோப்புறையில் கோப்புகளைப் புறக்கணி
இந்த கோப்பை மட்டும் புறக்கணி
பின்னொட்டு
இந்த கோப்பை இப்போது நீங்கள் நிலைப்படுத்தலாம்.
diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml
index 096b4398..5d120117 100644
--- a/src/Resources/Locales/uk_UA.axaml
+++ b/src/Resources/Locales/uk_UA.axaml
@@ -448,6 +448,7 @@
{0} місяців тому
{0} років тому
Вчора
+ Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK
Налаштування
AI
Промпт для аналізу різниці
@@ -623,7 +624,6 @@
Коміт:
Закомітити зміни скасування
Змінити повідомлення коміту
- Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK
Виконується. Будь ласка, зачекайте...
ЗБЕРЕГТИ
Зберегти як...
@@ -649,10 +649,7 @@
Шлях до сховища приватного ключа SSH
ПОЧАТИ
Stash (Сховати)
- Автоматично відновити після схову
- Ваші робочі файли залишаться без змін, але буде збережено схованку.
Включити невідстежувані файли
- Зберегти проіндексовані файли
Повідомлення:
Необов'язково. Назва цієї схованки
Лише проіндексовані зміни
@@ -714,7 +711,6 @@
Git Ignore
Ігнорувати всі файли *{0}
Ігнорувати файли *{0} у цій же теці
- Ігнорувати файли у цій же теці
Ігнорувати лише цей файл
Amend (Доповнити)
Тепер ви можете проіндексувати цей файл.
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 2a117fb8..2a5991fd 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -124,6 +124,7 @@
交互式变基(rebase -i) ${0}$ 到此处
合并(merge)此提交至 ${0}$
合并(merge)...
+ 推送(push) ${0}$ 到 ${1}$
变基(rebase) ${0}$ 到此处
重置(reset) ${0}$ 到此处
回滚此提交
@@ -446,6 +447,7 @@
工作区列表
页面列表
合并分支
+ 编辑合并信息
目标分支 :
合并方式 :
合并目标 :
@@ -478,6 +480,7 @@
{0}个月前
{0}年前
昨天
+ 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。
偏好设置
AI
Analyze Diff Prompt
@@ -556,6 +559,8 @@
启用强制推送
本地分支 :
远程仓库 :
+ 修订 :
+ 推送指定修订到远程仓库
推送到远程仓库
远程分支 :
跟踪远程分支
@@ -666,7 +671,6 @@
目标提交 :
回滚后提交更改
编辑提交信息
- 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。
执行操作中,请耐心等待...
保 存
另存为...
@@ -692,16 +696,15 @@
SSH密钥文件
开 始
贮藏(stash)
- 贮藏后自动恢复工作区
- 工作区文件保持未修改状态,但贮藏内容已保存。
包含未跟踪的文件
- 保留暂存区文件
信息 :
- 选填,用于命名此贮藏
+ 选填,此贮藏的描述信息
+ 模式 :
仅贮藏暂存区的变更
选中文件的所有变更均会被贮藏!
贮藏本地变更
应用(apply)
+ 复制描述信息
删除(drop)
另存为补丁...
丢弃贮藏确认
@@ -768,7 +771,7 @@
添加至 .gitignore 忽略列表
忽略所有 *{0} 文件
忽略同目录下所有 *{0} 文件
- 忽略同目录下所有文件
+ 忽略该目录下的新文件
忽略本文件
修补
现在您已可将其加入暂存区中
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 29a5346d..f1736ff8 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -124,6 +124,7 @@
互動式重定基底 (rebase -i) ${0}$ 到此處
合併 (merge) 此提交到 ${0}$
合併 (merge)...
+ 推送(push) ${0}$ 至 ${1}$
重定基底 (rebase) ${0}$ 到此處
重設 (reset) ${0}$ 到此處
復原此提交
@@ -446,6 +447,7 @@
工作區列表
頁面列表
合併分支
+ 編輯合併訊息
目標分支:
合併方式:
合併來源:
@@ -478,6 +480,7 @@
{0} 個月前
{0} 年前
昨天
+ 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。
偏好設定
AI
分析變更差異提示詞
@@ -556,6 +559,8 @@
啟用強制推送
本機分支:
遠端存放庫:
+ 修訂:
+ 推送修訂到遠端存放庫
推送到遠端存放庫
遠端分支:
追蹤遠端分支
@@ -666,7 +671,6 @@
目標提交:
復原後提交變更
編輯提交訊息
- 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。
執行操作中,請耐心等待...
儲存
另存新檔...
@@ -692,16 +696,15 @@
SSH 金鑰檔案
開 始
擱置變更 (stash)
- 擱置變更後自動復原工作區
- 工作區檔案保持未修改,但擱置內容已儲存。
包含未追蹤的檔案
- 保留已暫存的變更
擱置變更訊息:
- 選填,用於命名此擱置變更
+ 選填,用於描述此擱置變更
+ 操作模式:
僅擱置已暫存的變更
已選取的檔案中的變更均會被擱置!
擱置本機變更
套用 (apply)
+ 複製描述訊息
刪除 (drop)
另存為修補檔 (patch)...
捨棄擱置變更確認
@@ -768,7 +771,7 @@
加入至 .gitignore 忽略清單
忽略所有 *{0} 檔案
忽略同路徑下所有 *{0} 檔案
- 忽略同路徑下所有檔案
+ 忽略本路徑下的新增檔案
忽略本檔案
修補
現在您已可將其加入暫存區中
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index 15704775..f42160a2 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -529,13 +529,7 @@
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
diff --git a/src/ViewModels/BranchCompare.cs b/src/ViewModels/BranchCompare.cs
index f56cfd76..64ceea1c 100644
--- a/src/ViewModels/BranchCompare.cs
+++ b/src/ViewModels/BranchCompare.cs
@@ -118,7 +118,7 @@ namespace SourceGit.ViewModels
public ContextMenu CreateChangeContextMenu()
{
- if (_selectedChanges == null || _selectedChanges.Count != 1)
+ if (_selectedChanges is not { Count: 1 })
return null;
var change = _selectedChanges[0];
diff --git a/src/ViewModels/BranchTreeNode.cs b/src/ViewModels/BranchTreeNode.cs
index 130893ec..dffbf671 100644
--- a/src/ViewModels/BranchTreeNode.cs
+++ b/src/ViewModels/BranchTreeNode.cs
@@ -74,9 +74,9 @@ namespace SourceGit.ViewModels
public class Builder
{
- public List Locals => _locals;
- public List Remotes => _remotes;
- public List InvalidExpandedNodes => _invalidExpandedNodes;
+ public List Locals { get; } = [];
+ public List Remotes { get; } = [];
+ public List InvalidExpandedNodes { get; } = [];
public Builder(Models.BranchSortMode localSortMode, Models.BranchSortMode remoteSortMode)
{
@@ -109,14 +109,14 @@ namespace SourceGit.ViewModels
fakeRemoteTime--;
folders.Add(path, node);
- _remotes.Add(node);
+ Remotes.Add(node);
}
foreach (var branch in branches)
{
if (branch.IsLocal)
{
- MakeBranchNode(branch, _locals, folders, "refs/heads", bForceExpanded);
+ MakeBranchNode(branch, Locals, folders, "refs/heads", bForceExpanded);
continue;
}
@@ -131,20 +131,20 @@ namespace SourceGit.ViewModels
foreach (var path in _expanded)
{
if (!folders.ContainsKey(path))
- _invalidExpandedNodes.Add(path);
+ InvalidExpandedNodes.Add(path);
}
folders.Clear();
if (_localSortMode == Models.BranchSortMode.Name)
- SortNodesByName(_locals);
+ SortNodesByName(Locals);
else
- SortNodesByTime(_locals);
+ SortNodesByTime(Locals);
if (_remoteSortMode == Models.BranchSortMode.Name)
- SortNodesByName(_remotes);
+ SortNodesByName(Remotes);
else
- SortNodesByTime(_remotes);
+ SortNodesByTime(Remotes);
}
private void MakeBranchNode(Models.Branch branch, List roots, Dictionary folders, string prefix, bool bForceExpanded)
@@ -269,9 +269,6 @@ namespace SourceGit.ViewModels
private readonly Models.BranchSortMode _localSortMode = Models.BranchSortMode.Name;
private readonly Models.BranchSortMode _remoteSortMode = Models.BranchSortMode.Name;
- private readonly List _locals = new List();
- private readonly List _remotes = new List();
- private readonly List _invalidExpandedNodes = new List();
private readonly HashSet _expanded = new HashSet();
}
}
diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs
index fbecf30e..54673ff2 100644
--- a/src/ViewModels/CommitDetail.cs
+++ b/src/ViewModels/CommitDetail.cs
@@ -81,7 +81,7 @@ namespace SourceGit.ViewModels
{
if (SetProperty(ref _selectedChanges, value))
{
- if (value == null || value.Count != 1)
+ if (value is not { Count: 1 })
DiffContext = null;
else
DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_commit, value[0]), _diffContext);
@@ -133,6 +133,12 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _revisionFileSearchSuggestion, value);
}
+ public bool CanOpenRevisionFileWithDefaultEditor
+ {
+ get => _canOpenRevisionFileWithDefaultEditor;
+ private set => SetProperty(ref _canOpenRevisionFileWithDefaultEditor, value);
+ }
+
public CommitDetail(Repository repo)
{
_repo = repo;
@@ -197,6 +203,7 @@ namespace SourceGit.ViewModels
{
ViewRevisionFilePath = string.Empty;
ViewRevisionFileContent = null;
+ CanOpenRevisionFileWithDefaultEditor = false;
return;
}
@@ -205,6 +212,7 @@ namespace SourceGit.ViewModels
switch (file.Type)
{
case Models.ObjectType.Blob:
+ CanOpenRevisionFileWithDefaultEditor = true;
Task.Run(() =>
{
var isBinary = new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).Result();
@@ -252,6 +260,7 @@ namespace SourceGit.ViewModels
});
break;
case Models.ObjectType.Commit:
+ CanOpenRevisionFileWithDefaultEditor = false;
Task.Run(() =>
{
var submoduleRoot = Path.Combine(_repo.FullPath, file.Path).Replace('\\', '/').Trim('/');
@@ -267,11 +276,26 @@ namespace SourceGit.ViewModels
});
break;
default:
+ CanOpenRevisionFileWithDefaultEditor = false;
ViewRevisionFileContent = null;
break;
}
}
+ public Task OpenRevisionFileWithDefaultEditor(string file)
+ {
+ return Task.Run(() =>
+ {
+ var fullPath = Native.OS.GetAbsPath(_repo.FullPath, file);
+ var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
+ var fileExt = Path.GetExtension(fullPath) ?? "";
+ var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}");
+
+ Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file, tmpFile);
+ Native.OS.OpenWithDefaultEditor(tmpFile);
+ });
+ }
+
public ContextMenu CreateChangeContextMenu(Models.Change change)
{
var diffWithMerger = new MenuItem();
@@ -421,13 +445,10 @@ namespace SourceGit.ViewModels
var openWith = new MenuItem();
openWith.Header = App.Text("OpenWith");
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
+ openWith.IsEnabled = file.Type == Models.ObjectType.Blob;
openWith.Click += async (_, ev) =>
{
- var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
- var fileExt = Path.GetExtension(fullPath) ?? "";
- var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}");
- await Task.Run(() => Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, tmpFile));
- Native.OS.OpenWithDefaultEditor(tmpFile);
+ await OpenRevisionFileWithDefaultEditor(file.Path);
ev.Handled = true;
};
@@ -549,6 +570,8 @@ namespace SourceGit.ViewModels
SignInfo = null;
ViewRevisionFileContent = null;
+ ViewRevisionFilePath = string.Empty;
+ CanOpenRevisionFileWithDefaultEditor = false;
Children = null;
RevisionFileSearchFilter = string.Empty;
RevisionFileSearchSuggestion = null;
@@ -887,5 +910,6 @@ namespace SourceGit.ViewModels
private List _revisionFiles = null;
private string _revisionFileSearchFilter = string.Empty;
private List _revisionFileSearchSuggestion = null;
+ private bool _canOpenRevisionFileWithDefaultEditor = false;
}
}
diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs
index 2fa4dae2..3225f9e2 100644
--- a/src/ViewModels/Fetch.cs
+++ b/src/ViewModels/Fetch.cs
@@ -46,10 +46,7 @@ namespace SourceGit.ViewModels
else if (!string.IsNullOrEmpty(_repo.Settings.DefaultRemote))
{
var def = _repo.Remotes.Find(r => r.Name == _repo.Settings.DefaultRemote);
- if (def != null)
- SelectedRemote = def;
- else
- SelectedRemote = _repo.Remotes[0];
+ SelectedRemote = def ?? _repo.Remotes[0];
}
else
{
diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs
index c3e5aac1..b901700f 100644
--- a/src/ViewModels/FileHistories.cs
+++ b/src/ViewModels/FileHistories.cs
@@ -9,10 +9,11 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public class FileHistoriesRevisionFile(string path, object content)
+ public class FileHistoriesRevisionFile(string path, object content = null, bool canOpenWithDefaultEditor = false)
{
public string Path { get; set; } = path;
public object Content { get; set; } = content;
+ public bool CanOpenWithDefaultEditor { get; set; } = canOpenWithDefaultEditor;
}
public class FileHistoriesSingleRevision : ObservableObject
@@ -49,6 +50,23 @@ namespace SourceGit.ViewModels
return Task.Run(() => new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}"));
}
+ public Task OpenWithDefaultEditor()
+ {
+ if (_viewContent is not FileHistoriesRevisionFile { CanOpenWithDefaultEditor: true })
+ return null;
+
+ return Task.Run(() =>
+ {
+ var fullPath = Native.OS.GetAbsPath(_repo.FullPath, _file);
+ var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
+ var fileExt = Path.GetExtension(fullPath) ?? "";
+ var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_revision.SHA.Substring(0, 10)}{fileExt}");
+
+ Commands.SaveRevisionFile.Run(_repo.FullPath, _revision.SHA, _file, tmpFile);
+ Native.OS.OpenWithDefaultEditor(tmpFile);
+ });
+ }
+
private void RefreshViewContent()
{
if (_isDiffMode)
@@ -62,7 +80,7 @@ namespace SourceGit.ViewModels
var objs = new Commands.QueryRevisionObjects(_repo.FullPath, _revision.SHA, _file).Result();
if (objs.Count == 0)
{
- ViewContent = new FileHistoriesRevisionFile(_file, null);
+ ViewContent = new FileHistoriesRevisionFile(_file);
return;
}
@@ -80,13 +98,13 @@ namespace SourceGit.ViewModels
{
var source = ImageSource.FromRevision(_repo.FullPath, _revision.SHA, _file, imgDecoder);
var image = new Models.RevisionImageFile(_file, source.Bitmap, source.Size);
- Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image));
+ Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image, true));
}
else
{
var size = new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).Result();
var binaryFile = new Models.RevisionBinaryFile() { Size = size };
- Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile));
+ Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile, true));
}
return;
@@ -101,18 +119,18 @@ namespace SourceGit.ViewModels
if (imgDecoder != Models.ImageDecoder.None)
{
var combined = new RevisionLFSImage(_repo.FullPath, _file, lfs, imgDecoder);
- Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, combined));
+ Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, combined, true));
}
else
{
var rlfs = new Models.RevisionLFSObject() { Object = lfs };
- Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs));
+ Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs, true));
}
}
else
{
var txt = new Models.RevisionTextFile() { FileName = obj.Path, Content = content };
- Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, txt));
+ Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, txt, true));
}
});
break;
@@ -132,7 +150,7 @@ namespace SourceGit.ViewModels
});
break;
default:
- ViewContent = new FileHistoriesRevisionFile(_file, null);
+ ViewContent = new FileHistoriesRevisionFile(_file);
break;
}
}
diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs
index db368d80..9e24e9b3 100644
--- a/src/ViewModels/Histories.cs
+++ b/src/ViewModels/Histories.cs
@@ -14,11 +14,6 @@ namespace SourceGit.ViewModels
{
public class Histories : ObservableObject, IDisposable
{
- public Repository Repo
- {
- get => _repo;
- }
-
public bool IsLoading
{
get => _isLoading;
@@ -214,9 +209,56 @@ namespace SourceGit.ViewModels
}
}
- public void DoubleTapped(Models.Commit commit)
+ public bool CheckoutBranchByDecorator(Models.Decorator decorator)
{
- if (commit == null || commit.IsCurrentHead)
+ if (decorator == null)
+ return false;
+
+ if (decorator.Type == Models.DecoratorType.CurrentBranchHead ||
+ decorator.Type == Models.DecoratorType.CurrentCommitHead)
+ return true;
+
+ if (decorator.Type == Models.DecoratorType.LocalBranchHead)
+ {
+ var b = _repo.Branches.Find(x => x.Name == decorator.Name);
+ if (b == null)
+ return false;
+
+ _repo.CheckoutBranch(b);
+ return true;
+ }
+
+ if (decorator.Type == Models.DecoratorType.RemoteBranchHead)
+ {
+ var rb = _repo.Branches.Find(x => x.FriendlyName == decorator.Name);
+ if (rb == null)
+ return false;
+
+ var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName);
+ if (lb == null || lb.TrackStatus.Ahead.Count > 0)
+ {
+ if (_repo.CanCreatePopup())
+ _repo.ShowPopup(new CreateBranch(_repo, rb));
+ }
+ else if (lb.TrackStatus.Behind.Count > 0)
+ {
+ if (_repo.CanCreatePopup())
+ _repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb));
+ }
+ else if (!lb.IsCurrent)
+ {
+ _repo.CheckoutBranch(lb);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public void CheckoutBranchByCommit(Models.Commit commit)
+ {
+ if (commit.IsCurrentHead)
return;
var firstRemoteBranch = null as Models.Branch;
@@ -224,29 +266,28 @@ namespace SourceGit.ViewModels
{
if (d.Type == Models.DecoratorType.LocalBranchHead)
{
- var b = _repo.Branches.Find(x => x.FriendlyName == d.Name);
- if (b != null)
- {
- _repo.CheckoutBranch(b);
- return;
- }
+ var b = _repo.Branches.Find(x => x.Name == d.Name);
+ if (b == null)
+ continue;
+
+ _repo.CheckoutBranch(b);
+ return;
}
else if (d.Type == Models.DecoratorType.RemoteBranchHead)
{
- var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name);
- if (remoteBranch != null)
+ var rb = _repo.Branches.Find(x => x.FriendlyName == d.Name);
+ if (rb == null)
+ continue;
+
+ var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName);
+ if (lb is { TrackStatus.Ahead.Count: 0 })
{
- var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName);
- if (localBranch is { TrackStatus.Ahead.Count: 0 })
- {
- if (_repo.CanCreatePopup())
- _repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch));
- return;
- }
+ if (_repo.CanCreatePopup())
+ _repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb));
+ return;
}
- if (firstRemoteBranch == null)
- firstRemoteBranch = remoteBranch;
+ firstRemoteBranch ??= rb;
}
}
@@ -560,9 +601,7 @@ namespace SourceGit.ViewModels
var parents = new List();
foreach (var sha in commit.Parents)
{
- var parent = _commits.Find(x => x.SHA == sha);
- if (parent == null)
- parent = new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
+ var parent = _commits.Find(x => x.SHA == sha) ?? new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
if (parent != null)
parents.Add(parent);
@@ -627,6 +666,22 @@ namespace SourceGit.ViewModels
if (current.Head != commit.SHA)
{
+ if (current.TrackStatus.Ahead.Contains(commit.SHA))
+ {
+ var upstream = _repo.Branches.Find(x => x.FullName.Equals(current.Upstream, StringComparison.Ordinal));
+ var pushRevision = new MenuItem();
+ pushRevision.Header = App.Text("CommitCM.PushRevision", commit.SHA.Substring(0, 10), upstream.FriendlyName);
+ pushRevision.Icon = App.CreateMenuIcon("Icons.Push");
+ pushRevision.Click += (_, e) =>
+ {
+ if (_repo.CanCreatePopup())
+ _repo.ShowPopup(new PushRevision(_repo, commit, upstream));
+ e.Handled = true;
+ };
+ menu.Items.Add(pushRevision);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ }
+
var compareWithHead = new MenuItem();
compareWithHead.Header = App.Text("CommitCM.CompareWithHead");
compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare");
diff --git a/src/ViewModels/ImageSource.cs b/src/ViewModels/ImageSource.cs
index f94b0c95..f0e2df30 100644
--- a/src/ViewModels/ImageSource.cs
+++ b/src/ViewModels/ImageSource.cs
@@ -89,7 +89,7 @@ namespace SourceGit.ViewModels
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
- }
+ }
}
return new ImageSource(null, 0);
@@ -154,7 +154,7 @@ namespace SourceGit.ViewModels
return new ImageSource(bitmap, size);
}
}
-
+
private static ImageSource DecodeWithTiff(Stream stream, long size)
{
using (var tiff = Tiff.ClientOpen($"{Guid.NewGuid()}.tif", "r", stream, new TiffStream()))
@@ -166,7 +166,7 @@ namespace SourceGit.ViewModels
var height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
var pixels = new int[width * height];
- // Currently only supports image when its `BITSPERSAMPLE` is one in [1,2,4,8,16]
+ // Currently only supports image when its `BITSPERSAMPLE` is one in [1,2,4,8,16]
tiff.ReadRGBAImageOriented(width, height, pixels, Orientation.TOPLEFT);
var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0);
diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs
index bb3efd51..fd2e2626 100644
--- a/src/ViewModels/Launcher.cs
+++ b/src/ViewModels/Launcher.cs
@@ -65,17 +65,14 @@ namespace SourceGit.ViewModels
var repos = ActiveWorkspace.Repositories.ToArray();
foreach (var repo in repos)
{
- var node = pref.FindNode(repo);
- if (node == null)
- {
- node = new RepositoryNode()
+ var node = pref.FindNode(repo) ??
+ new RepositoryNode
{
Id = repo,
Name = Path.GetFileName(repo),
Bookmark = 0,
IsRepository = true,
};
- }
OpenRepositoryInTab(node, null);
}
@@ -184,17 +181,14 @@ namespace SourceGit.ViewModels
var repos = to.Repositories.ToArray();
foreach (var repo in repos)
{
- var node = pref.FindNode(repo);
- if (node == null)
- {
- node = new RepositoryNode()
+ var node = pref.FindNode(repo) ??
+ new RepositoryNode
{
Id = repo,
Name = Path.GetFileName(repo),
Bookmark = 0,
IsRepository = true,
};
- }
OpenRepositoryInTab(node, null);
}
@@ -290,8 +284,7 @@ namespace SourceGit.ViewModels
return;
}
- if (page == null)
- page = _activePage;
+ page ??= _activePage;
var removeIdx = Pages.IndexOf(page);
var activeIdx = Pages.IndexOf(_activePage);
diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs
index 8a59d246..191a8163 100644
--- a/src/ViewModels/LauncherPage.cs
+++ b/src/ViewModels/LauncherPage.cs
@@ -87,7 +87,7 @@ namespace SourceGit.ViewModels
public bool CanCreatePopup()
{
- return _popup == null || !_popup.InProgress;
+ return _popup is not { InProgress: true };
}
public void StartPopup(Popup popup)
diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs
index eb54418c..d7b6a29c 100644
--- a/src/ViewModels/Merge.cs
+++ b/src/ViewModels/Merge.cs
@@ -21,6 +21,12 @@ namespace SourceGit.ViewModels
set;
}
+ public bool Edit
+ {
+ get;
+ set;
+ } = false;
+
public Merge(Repository repo, Models.Branch source, string into, bool forceFastForward)
{
_repo = repo;
@@ -62,7 +68,7 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
- new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg).Use(log).Exec();
+ new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, Edit).Use(log).Exec();
log.Complete();
var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs
index 1a6f2e01..1ddd6d99 100644
--- a/src/ViewModels/Pull.cs
+++ b/src/ViewModels/Pull.cs
@@ -7,7 +7,7 @@ namespace SourceGit.ViewModels
public class Pull : Popup
{
public List Remotes => _repo.Remotes;
- public Models.Branch Current => _current;
+ public Models.Branch Current { get; }
public bool HasSpecifiedRemoteBranch
{
@@ -64,7 +64,7 @@ namespace SourceGit.ViewModels
public Pull(Repository repo, Models.Branch specifiedRemoteBranch)
{
_repo = repo;
- _current = repo.CurrentBranch;
+ Current = repo.CurrentBranch;
if (specifiedRemoteBranch != null)
{
@@ -84,12 +84,12 @@ namespace SourceGit.ViewModels
else
{
var autoSelectedRemote = null as Models.Remote;
- if (!string.IsNullOrEmpty(_current.Upstream))
+ if (!string.IsNullOrEmpty(Current.Upstream))
{
- var remoteNameEndIdx = _current.Upstream.IndexOf('/', 13);
+ var remoteNameEndIdx = Current.Upstream.IndexOf('/', 13);
if (remoteNameEndIdx > 0)
{
- var remoteName = _current.Upstream.Substring(13, remoteNameEndIdx - 13);
+ var remoteName = Current.Upstream.Substring(13, remoteNameEndIdx - 13);
autoSelectedRemote = _repo.Remotes.Find(x => x.Name == remoteName);
}
}
@@ -146,7 +146,7 @@ namespace SourceGit.ViewModels
bool rs = new Commands.Pull(
_repo.FullPath,
_selectedRemote.Name,
- !string.IsNullOrEmpty(_current.Upstream) && _current.Upstream.Equals(_selectedBranch.FullName) ? string.Empty : _selectedBranch.Name,
+ !string.IsNullOrEmpty(Current.Upstream) && Current.Upstream.Equals(_selectedBranch.FullName) ? string.Empty : _selectedBranch.Name,
UseRebase).Use(log).Exec();
if (rs)
@@ -188,12 +188,12 @@ namespace SourceGit.ViewModels
RemoteBranches = branches;
var autoSelectedBranch = false;
- if (!string.IsNullOrEmpty(_current.Upstream) &&
- _current.Upstream.StartsWith($"refs/remotes/{remoteName}/", System.StringComparison.Ordinal))
+ if (!string.IsNullOrEmpty(Current.Upstream) &&
+ Current.Upstream.StartsWith($"refs/remotes/{remoteName}/", System.StringComparison.Ordinal))
{
foreach (var branch in branches)
{
- if (_current.Upstream == branch.FullName)
+ if (Current.Upstream == branch.FullName)
{
SelectedBranch = branch;
autoSelectedBranch = true;
@@ -206,7 +206,7 @@ namespace SourceGit.ViewModels
{
foreach (var branch in branches)
{
- if (_current.Name == branch.Name)
+ if (Current.Name == branch.Name)
{
SelectedBranch = branch;
autoSelectedBranch = true;
@@ -220,7 +220,6 @@ namespace SourceGit.ViewModels
}
private readonly Repository _repo = null;
- private readonly Models.Branch _current = null;
private Models.Remote _selectedRemote = null;
private List _remoteBranches = null;
private Models.Branch _selectedBranch = null;
diff --git a/src/ViewModels/PushRevision.cs b/src/ViewModels/PushRevision.cs
new file mode 100644
index 00000000..9322db2c
--- /dev/null
+++ b/src/ViewModels/PushRevision.cs
@@ -0,0 +1,59 @@
+using System.Threading.Tasks;
+
+namespace SourceGit.ViewModels
+{
+ public class PushRevision : Popup
+ {
+ public Models.Commit Revision
+ {
+ get;
+ }
+
+ public Models.Branch RemoteBranch
+ {
+ get;
+ }
+
+ public bool Force
+ {
+ get;
+ set;
+ }
+
+ public PushRevision(Repository repo, Models.Commit revision, Models.Branch remoteBranch)
+ {
+ _repo = repo;
+ Revision = revision;
+ RemoteBranch = remoteBranch;
+ Force = false;
+ }
+
+ public override Task Sure()
+ {
+ _repo.SetWatcherEnabled(false);
+ ProgressDescription = $"Push {Revision.SHA.Substring(0, 10)} -> {RemoteBranch.FriendlyName} ...";
+
+ var log = _repo.CreateLog("Push Revision");
+ Use(log);
+
+ return Task.Run(() =>
+ {
+ var succ = new Commands.Push(
+ _repo.FullPath,
+ Revision.SHA,
+ RemoteBranch.Remote,
+ RemoteBranch.Name,
+ false,
+ false,
+ false,
+ Force).Use(log).Exec();
+
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return succ;
+ });
+ }
+
+ private readonly Repository _repo;
+ }
+}
diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index 742d3634..52f2f43a 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -172,7 +172,7 @@ namespace SourceGit.ViewModels
private set
{
var oldHead = _currentBranch?.Head;
- if (SetProperty(ref _currentBranch, value))
+ if (SetProperty(ref _currentBranch, value) && value != null)
{
if (oldHead != _currentBranch.Head && _workingCopy is { UseAmend: true })
_workingCopy.UseAmend = false;
@@ -1090,6 +1090,7 @@ namespace SourceGit.ViewModels
var succ = new Commands.Bisect(_fullpath, subcmd).Use(log).Exec();
log.Complete();
+ var head = new Commands.QueryRevisionByRefName(_fullpath, "HEAD").Result();
Dispatcher.UIThread.Invoke(() =>
{
if (!succ)
@@ -1098,6 +1099,7 @@ namespace SourceGit.ViewModels
App.SendNotification(_fullpath, log.Content.Substring(log.Content.IndexOf('\n')).Trim());
MarkBranchesDirtyManually();
+ NavigateToCommit(head, true);
SetWatcherEnabled(true);
IsBisectCommandRunning = false;
});
@@ -1424,17 +1426,14 @@ namespace SourceGit.ViewModels
var root = Path.GetFullPath(Path.Combine(_fullpath, submodule));
var normalizedPath = root.Replace('\\', '/').TrimEnd('/');
- var node = Preferences.Instance.FindNode(normalizedPath);
- if (node == null)
- {
- node = new RepositoryNode()
+ var node = Preferences.Instance.FindNode(normalizedPath) ??
+ new RepositoryNode
{
Id = normalizedPath,
Name = Path.GetFileName(normalizedPath),
Bookmark = selfPage.Node.Bookmark,
IsRepository = true,
};
- }
App.GetLauncher().OpenRepositoryInTab(node, null);
}
@@ -1453,17 +1452,14 @@ namespace SourceGit.ViewModels
public void OpenWorktree(Models.Worktree worktree)
{
- var node = Preferences.Instance.FindNode(worktree.FullPath);
- if (node == null)
- {
- node = new RepositoryNode()
+ var node = Preferences.Instance.FindNode(worktree.FullPath) ??
+ new RepositoryNode
{
Id = worktree.FullPath,
Name = Path.GetFileName(worktree.FullPath),
Bookmark = 0,
IsRepository = true,
};
- }
App.GetLauncher()?.OpenRepositoryInTab(node, null);
}
@@ -2244,7 +2240,7 @@ namespace SourceGit.ViewModels
}
var compareWithHead = new MenuItem();
- compareWithHead.Header = App.Text("BranchCM.CompareWithHead");
+ compareWithHead.Header = App.Text("BranchCM.CompareWithCurrent", _currentBranch.Name);
compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare");
compareWithHead.Click += (_, _) =>
{
diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs
index 39400aa3..f04d1e30 100644
--- a/src/ViewModels/RevisionCompare.cs
+++ b/src/ViewModels/RevisionCompare.cs
@@ -24,10 +24,7 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _endPoint, value);
}
- public bool CanSaveAsPatch
- {
- get => _canSaveAsPatch;
- }
+ public bool CanSaveAsPatch { get; }
public List VisibleChanges
{
@@ -78,7 +75,7 @@ namespace SourceGit.ViewModels
_repo = repo;
_startPoint = (object)startPoint ?? new Models.Null();
_endPoint = (object)endPoint ?? new Models.Null();
- _canSaveAsPatch = startPoint != null && endPoint != null;
+ CanSaveAsPatch = startPoint != null && endPoint != null;
Task.Run(Refresh);
}
@@ -138,7 +135,7 @@ namespace SourceGit.ViewModels
public ContextMenu CreateChangeContextMenu()
{
- if (_selectedChanges == null || _selectedChanges.Count != 1)
+ if (_selectedChanges is not { Count: 1 })
return null;
var change = _selectedChanges[0];
@@ -244,7 +241,6 @@ namespace SourceGit.ViewModels
private string _repo;
private object _startPoint = null;
private object _endPoint = null;
- private bool _canSaveAsPatch = false;
private List _changes = null;
private List _visibleChanges = null;
private List _selectedChanges = null;
diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs
index 11e449fb..639a0a7b 100644
--- a/src/ViewModels/StashChanges.cs
+++ b/src/ViewModels/StashChanges.cs
@@ -27,19 +27,20 @@ namespace SourceGit.ViewModels
public bool OnlyStaged
{
get => _repo.Settings.OnlyStagedWhenStash;
- set => _repo.Settings.OnlyStagedWhenStash = value;
+ set
+ {
+ if (_repo.Settings.OnlyStagedWhenStash != value)
+ {
+ _repo.Settings.OnlyStagedWhenStash = value;
+ OnPropertyChanged();
+ }
+ }
}
- public bool KeepIndex
+ public int ChangesAfterStashing
{
- get => _repo.Settings.KeepIndexWhenStash;
- set => _repo.Settings.KeepIndexWhenStash = value;
- }
-
- public bool AutoRestore
- {
- get => _repo.Settings.AutoRestoreAfterStash;
- set => _repo.Settings.AutoRestoreAfterStash = value;
+ get => _repo.Settings.ChangesAfterStashing;
+ set => _repo.Settings.ChangesAfterStashing = value;
}
public StashChanges(Repository repo, List changes, bool hasSelectedFiles)
@@ -59,6 +60,8 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
+ var mode = (DealWithChangesAfterStashing)ChangesAfterStashing;
+ var keepIndex = mode == DealWithChangesAfterStashing.KeepIndex;
var succ = false;
if (!HasSelectedFiles)
@@ -67,7 +70,7 @@ namespace SourceGit.ViewModels
{
if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED)
{
- succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, KeepIndex);
+ succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, keepIndex);
}
else
{
@@ -78,20 +81,20 @@ namespace SourceGit.ViewModels
staged.Add(c);
}
- succ = StashWithChanges(staged, log);
+ succ = StashWithChanges(staged, keepIndex, log);
}
}
else
{
- succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, KeepIndex);
+ succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, keepIndex);
}
}
else
{
- succ = StashWithChanges(_changes, log);
+ succ = StashWithChanges(_changes, keepIndex, log);
}
- if (AutoRestore && succ)
+ if (mode == DealWithChangesAfterStashing.KeepAll && succ)
succ = new Commands.Stash(_repo.FullPath).Use(log).Apply("stash@{0}", true);
log.Complete();
@@ -105,7 +108,7 @@ namespace SourceGit.ViewModels
});
}
- private bool StashWithChanges(List changes, CommandLog log)
+ private bool StashWithChanges(List changes, bool keepIndex, CommandLog log)
{
if (changes.Count == 0)
return true;
@@ -119,7 +122,7 @@ namespace SourceGit.ViewModels
var pathSpecFile = Path.GetTempFileName();
File.WriteAllLines(pathSpecFile, paths);
- succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, KeepIndex);
+ succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, keepIndex);
File.Delete(pathSpecFile);
}
else
@@ -128,7 +131,7 @@ namespace SourceGit.ViewModels
{
var count = Math.Min(32, changes.Count - i);
var step = changes.GetRange(i, count);
- succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, KeepIndex);
+ succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, keepIndex);
if (!succ)
break;
}
@@ -137,6 +140,13 @@ namespace SourceGit.ViewModels
return succ;
}
+ private enum DealWithChangesAfterStashing
+ {
+ Discard = 0,
+ KeepIndex,
+ KeepAll,
+ }
+
private readonly Repository _repo = null;
private readonly List _changes = null;
}
diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs
index f039d54e..431f61e6 100644
--- a/src/ViewModels/StashesPage.cs
+++ b/src/ViewModels/StashesPage.cs
@@ -142,6 +142,7 @@ namespace SourceGit.ViewModels
var apply = new MenuItem();
apply.Header = App.Text("StashCM.Apply");
+ apply.Icon = App.CreateMenuIcon("Icons.CheckCircled");
apply.Click += (_, ev) =>
{
if (_repo.CanCreatePopup())
@@ -152,6 +153,7 @@ namespace SourceGit.ViewModels
var drop = new MenuItem();
drop.Header = App.Text("StashCM.Drop");
+ drop.Icon = App.CreateMenuIcon("Icons.Clear");
drop.Click += (_, ev) =>
{
if (_repo.CanCreatePopup())
@@ -194,11 +196,22 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
+ var copy = new MenuItem();
+ copy.Header = App.Text("StashCM.CopyMessage");
+ copy.Icon = App.CreateMenuIcon("Icons.Copy");
+ copy.Click += (_, ev) =>
+ {
+ App.CopyText(stash.Message);
+ ev.Handled = true;
+ };
+
var menu = new ContextMenu();
menu.Items.Add(apply);
menu.Items.Add(drop);
menu.Items.Add(new MenuItem { Header = "-" });
menu.Items.Add(patch);
+ menu.Items.Add(new MenuItem { Header = "-" });
+ menu.Items.Add(copy);
return menu;
}
diff --git a/src/ViewModels/Welcome.cs b/src/ViewModels/Welcome.cs
index 069dcf38..b726c413 100644
--- a/src/ViewModels/Welcome.cs
+++ b/src/ViewModels/Welcome.cs
@@ -11,7 +11,7 @@ namespace SourceGit.ViewModels
{
public class Welcome : ObservableObject
{
- public static Welcome Instance => _instance;
+ public static Welcome Instance { get; } = new();
public AvaloniaList Rows
{
@@ -354,7 +354,6 @@ namespace SourceGit.ViewModels
}
}
- private static Welcome _instance = new Welcome();
private string _searchFilter = string.Empty;
}
}
diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs
index 09ebc6f6..f41bc162 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,76 @@ 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);
-
- var byExtensionInSameFolder = new MenuItem();
- byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension);
- byExtensionInSameFolder.IsVisible = !isRooted;
- byExtensionInSameFolder.Click += (_, e) =>
+ 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) =>
{
- var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/');
- Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}");
+ Commands.GitIgnore.Add(_repo.FullPath, change.Path);
e.Handled = true;
};
- addToIgnore.Items.Add(byExtensionInSameFolder);
+ addToIgnore.Items.Add(singleFile);
+
+ 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);
@@ -1028,6 +1052,22 @@ namespace SourceGit.ViewModels
return menu;
}
+ if (!string.IsNullOrEmpty(selectedSingleFolder))
+ {
+ var dir = Path.Combine(_repo.FullPath, selectedSingleFolder);
+ var explore = new MenuItem();
+ explore.Header = App.Text("RevealFile");
+ explore.Icon = App.CreateMenuIcon("Icons.Explore");
+ explore.IsEnabled = Directory.Exists(dir);
+ explore.Click += (_, e) =>
+ {
+ Native.OS.OpenInFileManager(dir, true);
+ e.Handled = true;
+ };
+ menu.Items.Add(explore);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ }
+
var stage = new MenuItem();
stage.Header = App.Text("FileCM.StageMulti", _selectedUnstaged.Count);
stage.Icon = App.CreateMenuIcon("Icons.File.Add");
@@ -1086,12 +1126,31 @@ 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;
}
- public ContextMenu CreateContextMenuForStagedChanges()
+ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder)
{
if (_selectedStaged == null || _selectedStaged.Count == 0)
return null;
@@ -1340,6 +1399,23 @@ namespace SourceGit.ViewModels
}
else
{
+ if (!string.IsNullOrEmpty(selectedSingleFolder))
+ {
+ var dir = Path.Combine(_repo.FullPath, selectedSingleFolder);
+ var explore = new MenuItem();
+ explore.IsEnabled = Directory.Exists(dir);
+ explore.Header = App.Text("RevealFile");
+ explore.Icon = App.CreateMenuIcon("Icons.Explore");
+ explore.Click += (_, e) =>
+ {
+ Native.OS.OpenInFileManager(dir, true);
+ e.Handled = true;
+ };
+
+ menu.Items.Add(explore);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ }
+
var unstage = new MenuItem();
unstage.Header = App.Text("FileCM.UnstageMulti", _selectedStaged.Count);
unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
diff --git a/src/Views/AddWorktree.axaml.cs b/src/Views/AddWorktree.axaml.cs
index dad947de..8e16642e 100644
--- a/src/Views/AddWorktree.axaml.cs
+++ b/src/Views/AddWorktree.axaml.cs
@@ -26,7 +26,7 @@ namespace SourceGit.Views
{
var folder = selected[0];
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString();
- TxtLocation.Text = folderPath;
+ TxtLocation.Text = folderPath.TrimEnd(['\\', '/']);
}
}
catch (Exception exception)
diff --git a/src/Views/ApplyStash.axaml b/src/Views/ApplyStash.axaml
index 44a97f42..ded0e9f2 100644
--- a/src/Views/ApplyStash.axaml
+++ b/src/Views/ApplyStash.axaml
@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
- xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ApplyStash"
x:DataType="vm:ApplyStash">
@@ -16,14 +15,16 @@
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.ApplyStash.Stash}"/>
-
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
+
diff --git a/src/Views/Blame.axaml.cs b/src/Views/Blame.axaml.cs
index 171d51d9..5f49fa34 100644
--- a/src/Views/Blame.axaml.cs
+++ b/src/Views/Blame.axaml.cs
@@ -306,7 +306,7 @@ namespace SourceGit.Views
return;
var view = TextArea.TextView;
- if (view == null || !view.VisualLinesValid)
+ if (view is not { VisualLinesValid: true })
return;
var color = (Color)this.FindResource("SystemAccentColor")!;
diff --git a/src/Views/BranchCompare.axaml b/src/Views/BranchCompare.axaml
index 1fe66e9b..3d3859a9 100644
--- a/src/Views/BranchCompare.axaml
+++ b/src/Views/BranchCompare.axaml
@@ -13,13 +13,7 @@
Title="{DynamicResource Text.BranchCompare}"
MinWidth="1280" MinHeight="720"
WindowStartupLocation="CenterOwner">
-
-
-
-
-
-
-
+
diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs
index d66ac11d..4cbbf0a6 100644
--- a/src/Views/ChangeStatusIcon.cs
+++ b/src/Views/ChangeStatusIcon.cs
@@ -4,57 +4,24 @@ using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
+using Avalonia.Styling;
namespace SourceGit.Views
{
public class ChangeStatusIcon : Control
{
private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "★", "!"];
- private static readonly IBrush[] BACKGROUNDS = [
- Brushes.Transparent,
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Colors.Tomato, 0), new GradientStop(Color.FromRgb(252, 165, 150), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Colors.Orchid, 0), new GradientStop(Color.FromRgb(248, 161, 245), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- Brushes.OrangeRed,
+ private static readonly Color[] COLOR =
+ [
+ Colors.Transparent,
+ Colors.Goldenrod,
+ Colors.Goldenrod,
+ Colors.LimeGreen,
+ Colors.Tomato,
+ Colors.Orchid,
+ Colors.Goldenrod,
+ Colors.LimeGreen,
+ Colors.OrangeRed,
];
public static readonly StyledProperty IsUnstagedChangeProperty =
@@ -82,18 +49,20 @@ namespace SourceGit.Views
var typeface = new Typeface("fonts:SourceGit#JetBrains Mono");
- IBrush background;
- string indicator;
- if (IsUnstagedChange)
+ var idx = (int)(IsUnstagedChange ? Change.WorkTree : Change.Index);
+ var indicator = INDICATOR[idx];
+ var color = COLOR[idx];
+ var hsl = color.ToHsl();
+ var color2 = ActualThemeVariant == ThemeVariant.Dark
+ ? new HslColor(hsl.A, hsl.H, hsl.S, hsl.L - 0.1).ToRgb()
+ : new HslColor(hsl.A, hsl.H, hsl.S, hsl.L + 0.1).ToRgb();
+
+ var background = new LinearGradientBrush
{
- background = BACKGROUNDS[(int)Change.WorkTree];
- indicator = INDICATOR[(int)Change.WorkTree];
- }
- else
- {
- background = BACKGROUNDS[(int)Change.Index];
- indicator = INDICATOR[(int)Change.Index];
- }
+ GradientStops = [new GradientStop(color, 0), new GradientStop(color2, 1)],
+ StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
+ EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
+ };
var txt = new FormattedText(
indicator,
@@ -113,7 +82,9 @@ namespace SourceGit.Views
{
base.OnPropertyChanged(change);
- if (change.Property == IsUnstagedChangeProperty || change.Property == ChangeProperty)
+ if (change.Property == IsUnstagedChangeProperty ||
+ change.Property == ChangeProperty ||
+ (change.Property.Name == "ActualThemeVariant" && change.NewValue != null))
InvalidateVisual();
}
}
diff --git a/src/Views/ColorPicker.cs b/src/Views/ColorPicker.cs
index 5090af86..606a913e 100644
--- a/src/Views/ColorPicker.cs
+++ b/src/Views/ColorPicker.cs
@@ -10,7 +10,7 @@ namespace SourceGit.Views
public class ColorPicker : Control
{
public static readonly StyledProperty ValueProperty =
- AvaloniaProperty.Register(nameof(Value), 0);
+ AvaloniaProperty.Register(nameof(Value));
public uint Value
{
diff --git a/src/Views/CommandLogTime.cs b/src/Views/CommandLogTime.cs
index 665e6e7b..0e51c1e3 100644
--- a/src/Views/CommandLogTime.cs
+++ b/src/Views/CommandLogTime.cs
@@ -11,7 +11,7 @@ namespace SourceGit.Views
public class CommandLogTime : TextBlock
{
public static readonly StyledProperty LogProperty =
- AvaloniaProperty.Register(nameof(Log), null);
+ AvaloniaProperty.Register(nameof(Log));
public ViewModels.CommandLog Log
{
diff --git a/src/Views/CommitDetail.axaml b/src/Views/CommitDetail.axaml
index d6ce74a1..d2ba60e7 100644
--- a/src/Views/CommitDetail.axaml
+++ b/src/Views/CommitDetail.axaml
@@ -58,7 +58,7 @@
-
+
File.WriteAllText(file, msg);
+ _shouldExitApp = true;
+
+ var content = File.ReadAllText(file).ReplaceLineEndings("\n").Trim();
+ var firstLineEnd = content.IndexOf('\n', StringComparison.Ordinal);
+ if (firstLineEnd == -1)
+ {
+ Editor.SubjectEditor.Text = content;
+ }
+ else
+ {
+ Editor.SubjectEditor.Text = content.Substring(0, firstLineEnd);
+ Editor.DescriptionEditor.Text = content.Substring(firstLineEnd + 1).Trim();
+ }
+ }
+
+ public void AsBuiltin(string msg, Action onSave)
+ {
+ _onSave = onSave;
+ _shouldExitApp = false;
+
+ var firstLineEnd = msg.IndexOf('\n', StringComparison.Ordinal);
+ if (firstLineEnd == -1)
+ {
+ Editor.SubjectEditor.Text = msg;
+ }
+ else
+ {
+ Editor.SubjectEditor.Text = msg.Substring(0, firstLineEnd);
+ Editor.DescriptionEditor.Text = msg.Substring(firstLineEnd + 1).Trim();
+ }
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+
+ if (_shouldExitApp)
+ App.Quit(_exitCode);
+ }
+
+ private void SaveAndClose(object _1, RoutedEventArgs _2)
+ {
+ _onSave?.Invoke(Editor.Text);
+ _exitCode = 0;
+ Close();
+ }
+
+ private Action _onSave = null;
+ private bool _shouldExitApp = true;
+ private int _exitCode = -1;
+ }
+}
diff --git a/src/Views/CommitMessageTextBox.axaml.cs b/src/Views/CommitMessageTextBox.axaml.cs
index 83d6f900..5330852c 100644
--- a/src/Views/CommitMessageTextBox.axaml.cs
+++ b/src/Views/CommitMessageTextBox.axaml.cs
@@ -57,7 +57,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty ShowAdvancedOptionsProperty =
- AvaloniaProperty.Register(nameof(ShowAdvancedOptions), false);
+ AvaloniaProperty.Register(nameof(ShowAdvancedOptions));
public static readonly StyledProperty TextProperty =
AvaloniaProperty.Register(nameof(Text), string.Empty);
@@ -182,7 +182,7 @@ namespace SourceGit.Views
{
var menu = vm.CreateContextMenuForCommitMessages();
menu.Placement = PlacementMode.TopEdgeAlignedLeft;
- menu?.Open(button);
+ menu.Open(button);
}
e.Handled = true;
@@ -201,7 +201,14 @@ namespace SourceGit.Views
private void OnOpenConventionalCommitHelper(object _, RoutedEventArgs e)
{
- App.ShowWindow(new ViewModels.ConventionalCommitMessageBuilder(text => Text = text), true);
+ var toplevel = TopLevel.GetTopLevel(this);
+ if (toplevel is Window owner)
+ {
+ var vm = new ViewModels.ConventionalCommitMessageBuilder(text => Text = text);
+ var builder = new ConventionalCommitMessageBuilder() { DataContext = vm };
+ builder.ShowDialog(owner);
+ }
+
e.Handled = true;
}
diff --git a/src/Views/CommitRefsPresenter.cs b/src/Views/CommitRefsPresenter.cs
index 507da1c2..a5717c6c 100644
--- a/src/Views/CommitRefsPresenter.cs
+++ b/src/Views/CommitRefsPresenter.cs
@@ -17,6 +17,7 @@ namespace SourceGit.Views
public IBrush Brush { get; set; } = null;
public bool IsHead { get; set; } = false;
public double Width { get; set; } = 0.0;
+ public Models.Decorator Decorator { get; set; } = null;
}
public static readonly StyledProperty FontFamilyProperty =
@@ -93,6 +94,19 @@ namespace SourceGit.Views
ShowTagsProperty);
}
+ public Models.Decorator DecoratorAt(Point point)
+ {
+ var x = 0.0;
+ foreach (var item in _items)
+ {
+ x += item.Width;
+ if (point.X < x)
+ return item.Decorator;
+ }
+
+ return null;
+ }
+
public override void Render(DrawingContext context)
{
if (_items.Count == 0)
@@ -198,7 +212,8 @@ namespace SourceGit.Views
{
Label = label,
Brush = normalBG,
- IsHead = isHead
+ IsHead = isHead,
+ Decorator = decorator,
};
StreamGeometry geo;
diff --git a/src/Views/CommitTimeTextBlock.cs b/src/Views/CommitTimeTextBlock.cs
index db63e8a6..63ecda61 100644
--- a/src/Views/CommitTimeTextBlock.cs
+++ b/src/Views/CommitTimeTextBlock.cs
@@ -19,7 +19,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty DateTimeFormatProperty =
- AvaloniaProperty.Register(nameof(DateTimeFormat), 0);
+ AvaloniaProperty.Register(nameof(DateTimeFormat));
public int DateTimeFormat
{
diff --git a/src/Views/Conflict.axaml b/src/Views/Conflict.axaml
index e0434896..7e4003ed 100644
--- a/src/Views/Conflict.axaml
+++ b/src/Views/Conflict.axaml
@@ -112,7 +112,7 @@
-
+
diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml
index be0c91a0..e9c956ec 100644
--- a/src/Views/FileHistories.axaml
+++ b/src/Views/FileHistories.axaml
@@ -13,12 +13,7 @@
Icon="/App.ico"
Title="{DynamicResource Text.FileHistory}"
MinWidth="1280" MinHeight="720">
-
-
-
-
-
-
+
@@ -139,7 +134,7 @@
-
+
+
diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs
index 3e7d5dc6..6a67d120 100644
--- a/src/Views/FileHistories.axaml.cs
+++ b/src/Views/FileHistories.axaml.cs
@@ -76,5 +76,13 @@ namespace SourceGit.Views
ToolTip.SetTip(border, vm.GetCommitFullMessage(commit));
}
}
+
+ private async void OnOpenFileWithDefaultEditor(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ViewModels.FileHistories { ViewContent: ViewModels.FileHistoriesSingleRevision revision })
+ await revision.OpenWithDefaultEditor();
+
+ e.Handled = true;
+ }
}
}
diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml
index 7afe12fa..35951cb1 100644
--- a/src/Views/Histories.axaml
+++ b/src/Views/Histories.axaml
@@ -34,7 +34,7 @@
-
+
@@ -70,7 +70,6 @@
LayoutUpdated="OnCommitListLayoutUpdated"
SelectionChanged="OnCommitListSelectionChanged"
ContextRequested="OnCommitListContextRequested"
- DoubleTapped="OnCommitListDoubleTapped"
KeyDown="OnCommitListKeyDown">