diff --git a/.editorconfig b/.editorconfig
index 3ad9d05b..83b15884 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -293,6 +293,10 @@ end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf
+# Package manifests
+[{*.spec,control}]
+end_of_line = lf
+
# YAML files
[*.{yml,yaml}]
indent_size = 2
diff --git a/.gitattributes b/.gitattributes
index 7410eb08..bd1dfea9 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,10 +3,12 @@
*.png binary
*.ico binary
*.sh text eol=lf
+*.spec text eol=lf
+control text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.json text
.gitattributes export-ignore
-.gitignore export-ignore
\ No newline at end of file
+.gitignore export-ignore
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index 53affe3d..e973c1ab 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -3,7 +3,7 @@ on:
workflow_call:
inputs:
version:
- description: Source Git package version
+ description: SourceGit package version
required: true
type: string
jobs:
diff --git a/README.md b/README.md
index e464f74c..85e3ae64 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@
## Translation Status
-[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
+[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
## How to Use
diff --git a/TRANSLATION.md b/TRANSLATION.md
index cda4a773..c646acf4 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -1,22 +1,4 @@
-### de_DE.axaml: 98.70%
-
-
-
-Missing Keys
-
-- Text.Diff.SaveAsPatch
-- Text.Diff.VisualLines.All
-- Text.Hotkeys.Repo.CreateBranchOnCommit
-- Text.Hotkeys.Repo.Fetch
-- Text.Hotkeys.Repo.Pull
-- Text.Hotkeys.Repo.Push
-- Text.IssueLinkCM.OpenInBrowser
-- Text.IssueLinkCM.CopyLink
-- Text.Preference.Appearance.EditorFontSize
-
-
-
-### es_ES.axaml: 100.00%
+### de_DE.axaml: 100.00%
@@ -26,7 +8,19 @@
-### fr_FR.axaml: 86.58%
+### es_ES.axaml: 99.57%
+
+
+
+Missing Keys
+
+- Text.Preference.Appearance.FontSize
+- Text.Preference.Appearance.FontSize.Default
+- Text.Preference.Appearance.FontSize.Editor
+
+
+
+### fr_FR.axaml: 86.31%
@@ -99,7 +93,9 @@
- Text.Preference.AI.Model
- Text.Preference.AI.Name
- Text.Preference.AI.Server
-- Text.Preference.Appearance.EditorFontSize
+- Text.Preference.Appearance.FontSize
+- Text.Preference.Appearance.FontSize.Default
+- Text.Preference.Appearance.FontSize.Editor
- Text.Preference.General.ShowAuthorTime
- Text.Preference.Integration
- Text.Preference.Shell
@@ -128,13 +124,15 @@
-### pt_BR.axaml: 100.00%
+### pt_BR.axaml: 99.57%
Missing Keys
-
+- Text.Preference.Appearance.FontSize
+- Text.Preference.Appearance.FontSize.Default
+- Text.Preference.Appearance.FontSize.Editor
diff --git a/build/resources/_common/applications/sourcegit.desktop b/build/resources/_common/applications/sourcegit.desktop
index ff7ef135..bcf9c813 100644
--- a/build/resources/_common/applications/sourcegit.desktop
+++ b/build/resources/_common/applications/sourcegit.desktop
@@ -1,5 +1,5 @@
[Desktop Entry]
-Name=Source Git
+Name=SourceGit
Comment=Open-source & Free Git GUI Client
Exec=/opt/sourcegit/sourcegit
Icon=/usr/share/icons/sourcegit.png
diff --git a/build/resources/rpm/SPECS/build.spec b/build/resources/rpm/SPECS/build.spec
index 9dda5f96..d31b6587 100644
--- a/build/resources/rpm/SPECS/build.spec
+++ b/build/resources/rpm/SPECS/build.spec
@@ -5,8 +5,8 @@ Summary: Open-source & Free Git Gui Client
License: MIT
URL: https://sourcegit-scm.github.io/
Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.tar.gz
-Requires: (libX11 or libX11-6)
-Requires: (libSM or libSM6)
+Requires: libX11.so.6()(%{__isa_bits}bit)
+Requires: libSM.so.6()(%{__isa_bits}bit)
%define _build_id_links none
diff --git a/build/scripts/package.linux.sh b/build/scripts/package.linux.sh
index 5ffd5a27..5abb058b 100755
--- a/build/scripts/package.linux.sh
+++ b/build/scripts/package.linux.sh
@@ -5,16 +5,6 @@ set -o
set -u
set pipefail
-if [[ -z "$VERSION" ]]; then
- echo "Provide the version as environment variable VERSION"
- exit 1
-fi
-
-if [[ -z "$RUNTIME" ]]; then
- echo "Provide the runtime as environment variable RUNTIME"
- exit 1
-fi
-
arch=
appimage_arch=
target=
diff --git a/build/scripts/package.osx-app.sh b/build/scripts/package.osx-app.sh
index 4a50a860..2d43e24a 100755
--- a/build/scripts/package.osx-app.sh
+++ b/build/scripts/package.osx-app.sh
@@ -5,16 +5,6 @@ set -o
set -u
set pipefail
-if [[ -z "$VERSION" ]]; then
- echo "Provide the version as environment variable VERSION"
- exit 1
-fi
-
-if [[ -z "$RUNTIME" ]]; then
- echo "Provide the runtime as environment variable RUNTIME"
- exit 1
-fi
-
cd build
mkdir -p SourceGit.app/Contents/Resources
diff --git a/build/scripts/package.windows-portable.sh b/build/scripts/package.windows-portable.sh
index 9ba29216..6bd3879b 100755
--- a/build/scripts/package.windows-portable.sh
+++ b/build/scripts/package.windows-portable.sh
@@ -5,16 +5,6 @@ set -o
set -u
set pipefail
-if [[ -z "$VERSION" ]]; then
- echo "Provide the version as environment variable VERSION"
- exit 1
-fi
-
-if [[ -z "$RUNTIME" ]]; then
- echo "Provide the runtime as environment variable RUNTIME"
- exit 1
-fi
-
cd build
rm -rf SourceGit/*.pdb
diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs
index 890b54ee..4ec8da82 100644
--- a/src/Commands/Branch.cs
+++ b/src/Commands/Branch.cs
@@ -48,8 +48,18 @@
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
- cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
- cmd.Args = $"push {remote} --delete {name}";
+
+ bool exists = new Remote(repo).HasBranch(remote, name);
+ if (exists)
+ {
+ cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
+ cmd.Args = $"push {remote} --delete {name}";
+ }
+ else
+ {
+ cmd.Args = $"branch -D -r {remote}/{name}";
+ }
+
return cmd.Exec();
}
}
diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs
index 04103d68..cb9e6a18 100644
--- a/src/Commands/Diff.cs
+++ b/src/Commands/Diff.cs
@@ -129,7 +129,7 @@ namespace SourceGit.Commands
_oldLine = int.Parse(match.Groups[1].Value);
_newLine = int.Parse(match.Groups[2].Value);
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
- }
+ }
}
else
{
diff --git a/src/Commands/ExecuteCustomAction.cs b/src/Commands/ExecuteCustomAction.cs
index f5fec82c..4981b2f9 100644
--- a/src/Commands/ExecuteCustomAction.cs
+++ b/src/Commands/ExecuteCustomAction.cs
@@ -44,7 +44,7 @@ namespace SourceGit.Commands
{
outputHandler?.Invoke(e.Data);
builder.AppendLine(e.Data);
- }
+ }
};
try
diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs
index 08d2d1c6..834cd7fc 100644
--- a/src/Commands/Fetch.cs
+++ b/src/Commands/Fetch.cs
@@ -16,7 +16,7 @@ namespace SourceGit.Commands
if (noTags)
Args += "--no-tags ";
else
- Args += "--force ";
+ Args += "--tags ";
if (prune)
Args += "--prune ";
diff --git a/src/Commands/Remote.cs b/src/Commands/Remote.cs
index f2e8d09e..beaf412b 100644
--- a/src/Commands/Remote.cs
+++ b/src/Commands/Remote.cs
@@ -45,5 +45,14 @@
Args = "remote set-url" + (isPush ? " --push " : " ") + $"{name} {url}";
return Exec();
}
+
+ public bool HasBranch(string remote, string branch)
+ {
+ SSHKey = new Config(WorkingDirectory).Get($"remote.{remote}.sshkey");
+ Args = $"ls-remote {remote} {branch}";
+
+ var rs = ReadToEnd();
+ return rs.IsSuccess && rs.StdOut.Trim().Length > 0;
+ }
}
}
diff --git a/src/Models/Filter.cs b/src/Models/Filter.cs
new file mode 100644
index 00000000..8ffd27c7
--- /dev/null
+++ b/src/Models/Filter.cs
@@ -0,0 +1,60 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace SourceGit.Models
+{
+ public enum FilterType
+ {
+ LocalBranch = 0,
+ LocalBranchFolder,
+ RemoteBranch,
+ RemoteBranchFolder,
+ Tag,
+ }
+
+ public enum FilterMode
+ {
+ None = 0,
+ Included,
+ Excluded,
+ }
+
+ public class Filter : ObservableObject
+ {
+ public string Pattern
+ {
+ get => _pattern;
+ set => SetProperty(ref _pattern, value);
+ }
+
+ public FilterType Type
+ {
+ get;
+ set;
+ } = FilterType.LocalBranch;
+
+ public FilterMode Mode
+ {
+ get => _mode;
+ set => SetProperty(ref _mode, value);
+ }
+
+ public bool IsBranch
+ {
+ get => Type != FilterType.Tag;
+ }
+
+ public Filter()
+ {
+ }
+
+ public Filter(string pattern, FilterType type, FilterMode mode)
+ {
+ _pattern = pattern;
+ _mode = mode;
+ Type = type;
+ }
+
+ private string _pattern = string.Empty;
+ private FilterMode _mode = FilterMode.None;
+ }
+}
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index 77c58ee7..f0156bc2 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -1,4 +1,9 @@
-using Avalonia.Collections;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Avalonia.Collections;
+using Avalonia.Threading;
namespace SourceGit.Models
{
@@ -76,11 +81,11 @@ namespace SourceGit.Models
set;
} = true;
- public AvaloniaList Filters
+ public AvaloniaList HistoriesFilters
{
get;
set;
- } = new AvaloniaList();
+ } = new AvaloniaList();
public AvaloniaList CommitTemplates
{
@@ -148,6 +153,177 @@ namespace SourceGit.Models
set;
} = "---";
+ public FilterMode GetHistoriesFilterMode(string pattern, FilterType type)
+ {
+ foreach (var filter in HistoriesFilters)
+ {
+ if (filter.Type != type)
+ continue;
+
+ if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ return filter.Mode;
+ }
+
+ return FilterMode.None;
+ }
+
+ public bool UpdateHistoriesFilter(string pattern, FilterType type, FilterMode mode)
+ {
+ for (int i = 0; i < HistoriesFilters.Count; i++)
+ {
+ var filter = HistoriesFilters[i];
+ if (filter.Type != type)
+ continue;
+
+ if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ {
+ if (mode == FilterMode.None)
+ {
+ HistoriesFilters.RemoveAt(i);
+ return true;
+ }
+
+ if (mode != filter.Mode)
+ {
+ filter.Mode = mode;
+ return true;
+ }
+ }
+ }
+
+ if (mode != FilterMode.None)
+ {
+ HistoriesFilters.Add(new Filter(pattern, type, mode));
+ return true;
+ }
+
+ return false;
+ }
+
+ public string BuildHistoriesFilter()
+ {
+ var builder = new StringBuilder();
+
+ var excludedBranches = new List();
+ var excludedRemotes = new List();
+ var excludedTags = new List();
+ var includedBranches = new List();
+ var includedRemotes = new List();
+ var includedTags = new List();
+ foreach (var filter in HistoriesFilters)
+ {
+ if (filter.Type == FilterType.LocalBranch)
+ {
+ var name = filter.Pattern.Substring(11);
+ var b = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
+
+ if (filter.Mode == FilterMode.Included)
+ includedBranches.Add(b);
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedBranches.Add(b);
+ }
+ else if (filter.Type == FilterType.LocalBranchFolder)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedBranches.Add($"{filter.Pattern.Substring(11)}/*");
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedBranches.Add($"{filter.Pattern.Substring(11)}/*");
+ }
+ else if (filter.Type == FilterType.RemoteBranch)
+ {
+ var name = filter.Pattern.Substring(13);
+ var r = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
+
+ if (filter.Mode == FilterMode.Included)
+ includedRemotes.Add(r);
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedRemotes.Add(r);
+ }
+ else if (filter.Type == FilterType.RemoteBranchFolder)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
+ }
+ else if (filter.Type == FilterType.Tag)
+ {
+ var name = filter.Pattern;
+ var t = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
+
+ if (filter.Mode == FilterMode.Included)
+ includedTags.Add(t);
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedTags.Add(t);
+ }
+ }
+
+ foreach (var b in excludedBranches)
+ {
+ builder.Append("--exclude=");
+ builder.Append(b);
+ builder.Append(' ');
+ }
+
+ if (includedBranches.Count > 0)
+ {
+ foreach (var b in includedBranches)
+ {
+ builder.Append("--branches=");
+ builder.Append(b);
+ builder.Append(' ');
+ }
+ }
+ else if (excludedBranches.Count > 0)
+ {
+ builder.Append("--branches ");
+ }
+
+ foreach (var r in excludedRemotes)
+ {
+ builder.Append("--exclude=");
+ builder.Append(r);
+ builder.Append(' ');
+ }
+
+ if (includedRemotes.Count > 0)
+ {
+ foreach (var r in includedRemotes)
+ {
+ builder.Append("--remotes=");
+ builder.Append(r);
+ builder.Append(' ');
+ }
+ }
+ else if (excludedRemotes.Count > 0)
+ {
+ builder.Append("--remotes ");
+ }
+
+ foreach (var t in excludedTags)
+ {
+ builder.Append("--exclude=");
+ builder.Append(t);
+ builder.Append(' ');
+ }
+
+ if (includedTags.Count > 0)
+ {
+ foreach (var t in includedTags)
+ {
+ builder.Append("--tags=");
+ builder.Append(t);
+ builder.Append(' ');
+ }
+ }
+ else if (excludedTags.Count > 0)
+ {
+ builder.Append("--tags ");
+ }
+
+ return builder.ToString();
+ }
+
public void PushCommitMessage(string message)
{
var existIdx = CommitMessages.IndexOf(message);
diff --git a/src/Models/Tag.cs b/src/Models/Tag.cs
index 2ec9e093..2e8f2c8e 100644
--- a/src/Models/Tag.cs
+++ b/src/Models/Tag.cs
@@ -1,10 +1,19 @@
-namespace SourceGit.Models
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace SourceGit.Models
{
- public class Tag
+ public class Tag : ObservableObject
{
- public string Name { get; set; }
- public string SHA { get; set; }
- public string Message { get; set; }
- public bool IsFiltered { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string SHA { get; set; } = string.Empty;
+ public string Message { get; set; } = string.Empty;
+
+ public FilterMode FilterMode
+ {
+ get => _filterMode;
+ set => SetProperty(ref _filterMode, value);
+ }
+
+ private FilterMode _filterMode = FilterMode.None;
}
}
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index d1f43695..ae2e89d7 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -73,7 +73,7 @@
ABBRECHEN
Auf diese Revision zurücksetzen
Auf Vorgänger-Revision zurücksetzen
- Generiere Commit-Nachricht
+ Generiere Commit-Nachricht
ANZEIGE MODUS ÄNDERN
Zeige als Datei- und Ordnerliste
Zeige als Pfadliste
@@ -240,6 +240,7 @@
Nächste Änderung
KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN
Vorherige Änderung
+ Als Patch speichern
Zeige versteckte Symbole
Nebeneinander
SUBMODUL
@@ -248,6 +249,7 @@
Syntax Hervorhebung
Zeilenumbruch
Öffne in Merge Tool
+ Alle Zeilen anzeigen
Weniger Zeilen anzeigen
Mehr Zeilen anzeigen
WÄHLE EINE DATEI AUS UM ÄNDERUNGEN ANZUZEIGEN
@@ -364,8 +366,12 @@
Gestagte Änderungen committen
Gestagte Änderungen committen und pushen
Alle Änderungen stagen und committen
+ Neuen Branch basierend auf ausgewählten Commit erstellen
Ausgewählte Änderungen verwerfen
+ Fetch, wird direkt ausgeführt
Dashboard Modus (Standard)
+ Pull, wird direkt ausgeführt
+ Push, wird direkt ausgeführt
Erzwinge Neuladen des Repositorys
Ausgewählte Änderungen stagen/unstagen
Commit-Suchmodus
@@ -389,6 +395,8 @@
Interaktiver Rebase
Ziel Branch:
Auf:
+ In Browser öffnen
+ Link kopieren
FEHLER
INFO
Branch mergen
@@ -429,7 +437,9 @@
Modell
DARSTELLUNG
Standardschriftart
- Standardschriftgröße
+ Schriftgröße
+ Standard
+ Texteditor
Monospace-Schriftart
Verwende die Monospace-Schriftart nur im Texteditor
Design
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index 3803bd39..281f13a3 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -434,8 +434,9 @@
Server
APPEARANCE
Default Font
- Default Font Size
- Editor Font Size
+ Font Size
+ Default
+ Editor
Monospace Font
Only use monospace font in text editor
Theme
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index 6bc96dd1..365cebfb 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -438,8 +438,6 @@
Servidor
APARIENCIA
Fuente por defecto
- Tamaño de fuente por defecto
- Tamaño de fuente del editor
Fuente Monospace
Usar solo fuente monospace en el editor de texto
Tema
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 043e8f97..5668db44 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -371,7 +371,6 @@
Préférences
APPARENCE
Police par défaut
- Taille de police par défaut
Police monospace
N'utiliser que des polices monospace pour l'éditeur de texte
Thème
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index 61ded334..ecd1654c 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -460,8 +460,6 @@
Servidor
INTELIGÊNCIA ARTIFICIAL
Fonte Padrão
- Tamanho da fonte padrão
- Tamanho da fonte do editor
Fonte Monoespaçada
Usar fonte monoespaçada apenas no editor de texto
Tema
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index 3ea6a922..ac94ee77 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -438,8 +438,9 @@
Сервер
ВИД
Шрифт по-умолчанию
- Размер шрифта по-умолчанию
- Размер шрифта редактора
+ Размер шрифта
+ По-умолчанию
+ Редактор
Моноширный шрифт
В текстовом редакторе используется только моноширный шрифт
Тема
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 3df54899..5b1f1403 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -437,7 +437,9 @@
服务地址
外观配置
缺省字体
- 默认字体大小
+ 字体大小
+ 默认
+ 代码编辑器
代码字体大小
等宽字体
仅在文本编辑器中使用等宽字体
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 4dcb31aa..0587f089 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -437,8 +437,9 @@
產生提交訊息提示詞
外觀設定
預設字型
- 預設字型大小
- 程式碼字型大小
+ 字型大小
+ 預設
+ 程式碼
等寬字型
僅在文字編輯器中使用等寬字型
佈景主題
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index 50f4d830..8fdfaa3c 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -168,12 +168,13 @@
-
+
@@ -1037,35 +1038,6 @@
-
-
-
-
+
+
@@ -44,7 +48,7 @@
@@ -67,15 +71,8 @@
Foreground="{DynamicResource Brush.BadgeFG}"
Background="{DynamicResource Brush.Badge}"/>
-
-
+
+
diff --git a/src/Views/BranchTree.axaml.cs b/src/Views/BranchTree.axaml.cs
index e96b2594..92c2b043 100644
--- a/src/Views/BranchTree.axaml.cs
+++ b/src/Views/BranchTree.axaml.cs
@@ -428,28 +428,6 @@ namespace SourceGit.Views
}
}
- private void OnToggleFilterClicked(object sender, RoutedEventArgs e)
- {
- if (DataContext is ViewModels.Repository repo &&
- sender is ToggleButton toggle &&
- toggle.DataContext is ViewModels.BranchTreeNode { Backend: Models.Branch branch } node)
- {
- bool filtered = toggle.IsChecked == true;
- List filters = [branch.FullName];
- if (branch.IsLocal && !string.IsNullOrEmpty(branch.Upstream))
- {
- filters.Add(branch.Upstream);
-
- node.IsFiltered = filtered;
- UpdateUpstreamFilterState(repo.RemoteBranchTrees, branch.Upstream, filtered);
- }
-
- repo.UpdateFilters(filters, filtered);
- }
-
- e.Handled = true;
- }
-
private void MakeRows(List rows, List nodes, int depth)
{
foreach (var node in nodes)
@@ -477,23 +455,6 @@ namespace SourceGit.Views
CollectBranchesInNode(outs, sub);
}
- private bool UpdateUpstreamFilterState(List collection, string upstream, bool isFiltered)
- {
- foreach (var node in collection)
- {
- if (node.Backend is Models.Branch b && b.FullName == upstream)
- {
- node.IsFiltered = isFiltered;
- return true;
- }
-
- if (node.Backend is Models.Remote r && upstream.StartsWith($"refs/remotes/{r.Name}/", StringComparison.Ordinal))
- return UpdateUpstreamFilterState(node.Children, upstream, isFiltered);
- }
-
- return false;
- }
-
private bool _disableSelectionChangingEvent = false;
}
}
diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml
index 76ea0227..d8b77a18 100644
--- a/src/Views/CommitBaseInfo.axaml
+++ b/src/Views/CommitBaseInfo.axaml
@@ -117,7 +117,28 @@
TextDecorations="Underline"
Cursor="Hand"
Margin="0,0,16,0"
- PointerPressed="OnSHAPressed"/>
+ PointerEntered="OnSHAPointerEntered"
+ PointerPressed="OnSHAPressed">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs
index 228fbe8e..6eb31a60 100644
--- a/src/Views/CommitBaseInfo.axaml.cs
+++ b/src/Views/CommitBaseInfo.axaml.cs
@@ -1,3 +1,5 @@
+using System.Threading.Tasks;
+
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
@@ -113,6 +115,29 @@ namespace SourceGit.Views
e.Handled = true;
}
+ private async void OnSHAPointerEntered(object sender, PointerEventArgs e)
+ {
+ if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha } ctl)
+ {
+ var tooltip = ToolTip.GetTip(ctl);
+ if (tooltip is Models.Commit commit && commit.SHA == sha)
+ {
+ ToolTip.SetIsOpen(ctl, true);
+ }
+ else
+ {
+ var c = await Task.Run(() => detail.GetParent(sha));
+ if (c != null)
+ {
+ ToolTip.SetTip(ctl, c);
+ ToolTip.SetIsOpen(ctl, true);
+ }
+ }
+ }
+
+ e.Handled = true;
+ }
+
private void OnSHAPressed(object sender, PointerPressedEventArgs e)
{
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })
diff --git a/src/Views/FilterModeSwitchButton.axaml b/src/Views/FilterModeSwitchButton.axaml
new file mode 100644
index 00000000..5b6d5341
--- /dev/null
+++ b/src/Views/FilterModeSwitchButton.axaml
@@ -0,0 +1,41 @@
+
+
+
diff --git a/src/Views/FilterModeSwitchButton.axaml.cs b/src/Views/FilterModeSwitchButton.axaml.cs
new file mode 100644
index 00000000..7bcf3100
--- /dev/null
+++ b/src/Views/FilterModeSwitchButton.axaml.cs
@@ -0,0 +1,256 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.VisualTree;
+
+namespace SourceGit.Views
+{
+ public partial class FilterModeSwitchButton : UserControl
+ {
+ public static readonly StyledProperty ModeProperty =
+ AvaloniaProperty.Register(nameof(Mode));
+
+ public Models.FilterMode Mode
+ {
+ get => GetValue(ModeProperty);
+ set => SetValue(ModeProperty, value);
+ }
+
+ public static readonly StyledProperty IsNoneVisibleProperty =
+ AvaloniaProperty.Register(nameof(IsNoneVisible));
+
+ public bool IsNoneVisible
+ {
+ get => GetValue(IsNoneVisibleProperty);
+ set => SetValue(IsNoneVisibleProperty, value);
+ }
+
+ public static readonly StyledProperty IsContextMenuOpeningProperty =
+ AvaloniaProperty.Register(nameof(IsContextMenuOpening));
+
+ public bool IsContextMenuOpening
+ {
+ get => GetValue(IsContextMenuOpeningProperty);
+ set => SetValue(IsContextMenuOpeningProperty, value);
+ }
+
+ public FilterModeSwitchButton()
+ {
+ InitializeComponent();
+ }
+
+ private void OnChangeFilterModeButtonClicked(object sender, RoutedEventArgs e)
+ {
+ var repoView = this.FindAncestorOfType();
+ if (repoView == null)
+ return;
+
+ var repo = repoView.DataContext as ViewModels.Repository;
+ if (repo == null)
+ return;
+
+ var button = sender as Button;
+ if (button == null)
+ return;
+
+ if (DataContext is Models.Tag tag)
+ {
+ var mode = tag.FilterMode;
+
+ var none = new MenuItem();
+ none.Icon = App.CreateMenuIcon("Icons.Eye");
+ none.Header = "Default";
+ none.IsEnabled = mode != Models.FilterMode.None;
+ none.Click += (_, ev) =>
+ {
+ UpdateTagFilterMode(repo, tag, Models.FilterMode.None);
+ ev.Handled = true;
+ };
+
+ var include = new MenuItem();
+ include.Icon = App.CreateMenuIcon("Icons.Filter");
+ include.Header = "Filter";
+ include.IsEnabled = mode != Models.FilterMode.Included;
+ include.Click += (_, ev) =>
+ {
+ UpdateTagFilterMode(repo, tag, Models.FilterMode.Included);
+ ev.Handled = true;
+ };
+
+ var exclude = new MenuItem();
+ exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
+ exclude.Header = "Hide";
+ exclude.IsEnabled = mode != Models.FilterMode.Excluded;
+ exclude.Click += (_, ev) =>
+ {
+ UpdateTagFilterMode(repo, tag, Models.FilterMode.Excluded);
+ ev.Handled = true;
+ };
+
+ var menu = new ContextMenu();
+ menu.Items.Add(none);
+ menu.Items.Add(include);
+ menu.Items.Add(exclude);
+
+ if (mode == Models.FilterMode.None)
+ {
+ IsContextMenuOpening = true;
+ menu.Closed += (_, _) => IsContextMenuOpening = false;
+ }
+
+ menu.Open(button);
+ }
+ else if (DataContext is ViewModels.BranchTreeNode node)
+ {
+ var mode = node.FilterMode;
+
+ var none = new MenuItem();
+ none.Icon = App.CreateMenuIcon("Icons.Eye");
+ none.Header = "Default";
+ none.IsEnabled = mode != Models.FilterMode.None;
+ none.Click += (_, ev) =>
+ {
+ UpdateBranchFilterMode(repo, node, Models.FilterMode.None);
+ ev.Handled = true;
+ };
+
+ var include = new MenuItem();
+ include.Icon = App.CreateMenuIcon("Icons.Filter");
+ include.Header = "Filter";
+ include.IsEnabled = mode != Models.FilterMode.Included;
+ include.Click += (_, ev) =>
+ {
+ UpdateBranchFilterMode(repo, node, Models.FilterMode.Included);
+ ev.Handled = true;
+ };
+
+ var exclude = new MenuItem();
+ exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
+ exclude.Header = "Hide";
+ exclude.IsEnabled = mode != Models.FilterMode.Excluded;
+ exclude.Click += (_, ev) =>
+ {
+ UpdateBranchFilterMode(repo, node, Models.FilterMode.Excluded);
+ ev.Handled = true;
+ };
+
+ var menu = new ContextMenu();
+ menu.Items.Add(none);
+ menu.Items.Add(include);
+ menu.Items.Add(exclude);
+
+ if (mode == Models.FilterMode.None)
+ {
+ IsContextMenuOpening = true;
+ menu.Closed += (_, _) => IsContextMenuOpening = false;
+ }
+
+ menu.Open(button);
+ }
+
+ e.Handled = true;
+ }
+
+ private void UpdateTagFilterMode(ViewModels.Repository repo, Models.Tag tag, Models.FilterMode mode)
+ {
+ var changed = repo.Settings.UpdateHistoriesFilter(tag.Name, Models.FilterType.Tag, mode);
+ if (changed)
+ {
+ tag.FilterMode = mode;
+ Task.Run(repo.RefreshCommits);
+ }
+ }
+
+ private void UpdateBranchFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, Models.FilterMode mode)
+ {
+ var isLocal = node.Path.StartsWith("refs/heads/", StringComparison.Ordinal);
+ var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
+ var tree = isLocal ? repo.LocalBranchTrees : repo.RemoteBranchTrees;
+
+ if (node.Backend is Models.Branch branch)
+ {
+ var changed = repo.Settings.UpdateHistoriesFilter(node.Path, type, mode);
+ if (!changed)
+ return;
+
+ node.FilterMode = mode;
+ }
+ else
+ {
+ var changed = repo.Settings.UpdateHistoriesFilter(node.Path, isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder, mode);
+ if (!changed)
+ return;
+
+ node.FilterMode = mode;
+ ResetChildrenBranchNodeFilterMode(repo, node, isLocal);
+ }
+
+ var parentType = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
+ var cur = node;
+ do
+ {
+ var lastSepIdx = cur.Path.LastIndexOf('/');
+ if (lastSepIdx <= 0)
+ break;
+
+ var parentPath = cur.Path.Substring(0, lastSepIdx);
+ var parent = FindParentNode(tree, parentPath);
+ if (parent == null)
+ break;
+
+ repo.Settings.UpdateHistoriesFilter(parent.Path, parentType, Models.FilterMode.None);
+ parent.FilterMode = Models.FilterMode.None;
+ cur = parent;
+ } while (true);
+
+ Task.Run(repo.RefreshCommits);
+ }
+
+ private void ResetChildrenBranchNodeFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, bool isLocal)
+ {
+ foreach (var child in node.Children)
+ {
+ child.FilterMode = Models.FilterMode.None;
+
+ if (child.IsBranch)
+ {
+ var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
+ repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
+ }
+ else
+ {
+ var type = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
+ repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
+ ResetChildrenBranchNodeFilterMode(repo, child, isLocal);
+ }
+ }
+ }
+
+ private ViewModels.BranchTreeNode FindParentNode(List nodes, string parent)
+ {
+ foreach (var node in nodes)
+ {
+ if (node.IsBranch)
+ continue;
+
+ if (node.Path.Equals(parent, StringComparison.Ordinal))
+ return node;
+
+ if (parent.StartsWith(node.Path, StringComparison.Ordinal))
+ {
+ var founded = FindParentNode(node.Children, parent);
+ if (founded != null)
+ return founded;
+ }
+ }
+
+ return null;
+ }
+ }
+}
+
+
diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs
index 9f436346..85092b64 100644
--- a/src/Views/Histories.axaml.cs
+++ b/src/Views/Histories.axaml.cs
@@ -192,35 +192,26 @@ namespace SourceGit.Views
if (string.IsNullOrEmpty(subject))
return;
- var offset = 0;
var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject);
if (!keywordMatch.Success)
keywordMatch = REG_KEYWORD_FORMAT2().Match(subject);
- if (keywordMatch.Success)
- {
- var keyword = new Run(subject.Substring(0, keywordMatch.Length));
- keyword.FontWeight = FontWeight.Bold;
- Inlines.Add(keyword);
-
- offset = keywordMatch.Length;
- subject = subject.Substring(offset);
- }
-
- var rules = IssueTrackerRules;
- if (rules == null || rules.Count == 0)
- {
- Inlines.Add(new Run(subject));
- return;
- }
-
+ var rules = IssueTrackerRules ?? [];
var matches = new List();
foreach (var rule in rules)
rule.Matches(matches, subject);
if (matches.Count == 0)
{
- Inlines.Add(new Run(subject));
+ if (keywordMatch.Success)
+ {
+ Inlines.Add(new Run(subject.Substring(0, keywordMatch.Length)) { FontWeight = FontWeight.Bold });
+ Inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
+ }
+ else
+ {
+ Inlines.Add(new Run(subject));
+ }
return;
}
@@ -232,18 +223,44 @@ namespace SourceGit.Views
foreach (var match in matches)
{
if (match.Start > pos)
- inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
+ {
+ if (keywordMatch.Success && pos < keywordMatch.Length)
+ {
+ if (keywordMatch.Length < match.Start)
+ {
+ inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
+ inlines.Add(new Run(subject.Substring(keywordMatch.Length, match.Start - keywordMatch.Length)));
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos, match.Start - pos)) { FontWeight = FontWeight.Bold });
+ }
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
+ }
+ }
var link = new Run(subject.Substring(match.Start, match.Length));
link.Classes.Add("issue_link");
inlines.Add(link);
pos = match.Start + match.Length;
- match.Start += offset; // Because we use this index of whole subject to detect mouse event.
}
if (pos < subject.Length)
- inlines.Add(new Run(subject.Substring(pos)));
+ {
+ if (keywordMatch.Success && pos < keywordMatch.Length)
+ {
+ inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
+ inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos)));
+ }
+ }
Inlines.AddRange(inlines);
}
diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml
index 73be0f7c..9b84604a 100644
--- a/src/Views/Preference.axaml
+++ b/src/Views/Preference.axaml
@@ -121,7 +121,7 @@
-
+
-
+
+ Value="{Binding DefaultFontSize, Mode=TwoWay}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
@@ -196,16 +205,16 @@
-
-
-
-
+
-
+
@@ -592,10 +592,24 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/RepositoryToolbar.axaml.cs b/src/Views/RepositoryToolbar.axaml.cs
index e2c7df8c..afc8ac5a 100644
--- a/src/Views/RepositoryToolbar.axaml.cs
+++ b/src/Views/RepositoryToolbar.axaml.cs
@@ -52,7 +52,7 @@ namespace SourceGit.Views
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
if (!startDirectly && OperatingSystem.IsMacOS())
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
-
+
repo.Fetch(startDirectly);
e.Handled = true;
}
@@ -66,7 +66,7 @@ namespace SourceGit.Views
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
if (!startDirectly && OperatingSystem.IsMacOS())
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
-
+
repo.Pull(startDirectly);
e.Handled = true;
}
@@ -80,7 +80,7 @@ namespace SourceGit.Views
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
if (!startDirectly && OperatingSystem.IsMacOS())
startDirectly = launcher.HasKeyModifier(KeyModifiers.Meta);
-
+
repo.Push(startDirectly);
e.Handled = true;
}
diff --git a/src/Views/TagsView.axaml b/src/Views/TagsView.axaml
index a30f63de..78165f2c 100644
--- a/src/Views/TagsView.axaml
+++ b/src/Views/TagsView.axaml
@@ -12,6 +12,10 @@
+
+
@@ -43,15 +47,14 @@
Classes="primary"
Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}"
Margin="8,0,0,0"/>
-
-
+
+
+
+
+
+
+
+
@@ -60,32 +63,28 @@
-
+ Margin="8,0,0,0"
+ TextTrimming="CharacterEllipsis"/>
-
+
diff --git a/src/Views/TagsView.axaml.cs b/src/Views/TagsView.axaml.cs
index 8d4168b2..c83cfd28 100644
--- a/src/Views/TagsView.axaml.cs
+++ b/src/Views/TagsView.axaml.cs
@@ -65,7 +65,7 @@ namespace SourceGit.Views
}
if (node.Tag != null)
- CreateContent(new Thickness(0, 2, 0, 0), "Icons.Tag");
+ CreateContent(new Thickness(0, 0, 0, 0), "Icons.Tag");
else if (node.IsExpanded)
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open");
else
@@ -247,23 +247,6 @@ namespace SourceGit.Views
}
}
- private void OnToggleFilterClicked(object sender, RoutedEventArgs e)
- {
- if (sender is ToggleButton toggle && DataContext is ViewModels.Repository repo)
- {
- var target = null as Models.Tag;
- if (toggle.DataContext is ViewModels.TagTreeNode node)
- target = node.Tag;
- else if (toggle.DataContext is Models.Tag tag)
- target = tag;
-
- if (target != null)
- repo.UpdateFilters([target.Name], toggle.IsChecked == true);
- }
-
- e.Handled = true;
- }
-
private void MakeTreeRows(List rows, List nodes)
{
foreach (var node in nodes)