Merge branch 'release/8.39'

This commit is contained in:
leo 2024-11-19 09:53:03 +08:00
commit f7ef61f1ce
No known key found for this signature in database
72 changed files with 1788 additions and 841 deletions

View file

@ -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

4
.gitattributes vendored
View file

@ -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
.gitignore export-ignore

View file

@ -32,7 +32,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Configure arm64 packages
if: ${{ matrix.runtime == 'linux-arm64' }}
run: |

View file

@ -3,7 +3,7 @@ on:
workflow_call:
inputs:
version:
description: Source Git package version
description: SourceGit package version
required: true
type: string
jobs:

View file

@ -47,7 +47,7 @@
## Translation Status
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-98.70%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-100.00%25-brightgreen)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-86.58%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-100.00%25-brightgreen)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-100.00%25-brightgreen)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.14%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-98.42%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-99.14%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
## How to Use

View file

@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F45A
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{67B6D05F-A000-40BA-ADB4-C9065F880D7B}"
ProjectSection(SolutionItems) = preProject
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\ci.yml = .github\workflows\ci.yml
.github\workflows\package.yml = .github\workflows\package.yml
.github\workflows\release.yml = .github\workflows\release.yml

View file

@ -1,22 +1,4 @@
### de_DE.axaml: 98.70%
<details>
<summary>Missing Keys</summary>
- 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
</details>
### es_ES.axaml: 100.00%
### de_DE.axaml: 100.00%
<details>
@ -26,115 +8,53 @@
</details>
### fr_FR.axaml: 86.58%
### es_ES.axaml: 99.14%
<details>
<summary>Missing Keys</summary>
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
</details>
### fr_FR.axaml: 98.42%
<details>
<summary>Missing Keys</summary>
- Text.About.Chart
- Text.AIAssistant
- Text.AIAssistant.Tip
- Text.BranchCM.FetchInto
- Text.ChangeCM.GenerateCommitMessage
- Text.CherryPick.AppendSourceToMessage
- Text.CherryPick.Mainline
- Text.CherryPick.Mainline.Tips
- Text.CommitCM.CherryPickMultiple
- Text.CommitCM.CustomAction
- Text.CommitCM.SquashCommitsSinceThis
- Text.CommitDetail.Info.WebLinks
- Text.Configure.CustomAction
- Text.Configure.CustomAction.Arguments
- Text.Configure.CustomAction.Arguments.Tip
- Text.Configure.CustomAction.Executable
- Text.Configure.CustomAction.Name
- Text.Configure.CustomAction.Scope
- Text.Configure.CustomAction.Scope.Commit
- Text.Configure.CustomAction.Scope.Repository
- Text.Configure.Git.DefaultRemote
- Text.Configure.Git.EnablePruneOnFetch
- Text.Configure.Git.EnableSignOff
- Text.Configure.IssueTracker.AddSampleGitLabIssue
- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
- Text.Configure.OpenAI
- Text.Configure.OpenAI.Prefered
- Text.Configure.OpenAI.Prefered.Tip
- Text.ConfigureWorkspace
- Text.ConfigureWorkspace.Color
- Text.ConfigureWorkspace.Restore
- Text.ConventionalCommit
- Text.ConventionalCommit.BreakingChanges
- Text.ConventionalCommit.ClosedIssue
- Text.ConventionalCommit.Detail
- Text.ConventionalCommit.Scope
- Text.ConventionalCommit.ShortDescription
- Text.ConventionalCommit.Type
- Text.Diff.IgnoreWhitespace
- Text.Diff.SaveAsPatch
- Text.Diff.VisualLines.All
- Text.Discard.IncludeIgnored
- Text.ExecuteCustomAction
- Text.ExecuteCustomAction.Name
- Text.FileHistory.FileChange
- Text.GitLFS.Locks.OnlyMine
- Text.Histories.Header.AuthorTime
- Text.Histories.Tips
- Text.Histories.Tips.MacOS
- Text.Histories.Tips.Prefix
- Text.Hotkeys.Repo.CommitWithAutoStage
- Text.Hotkeys.Repo.CreateBranchOnCommit
- Text.Hotkeys.Repo.DiscardSelected
- Text.Hotkeys.Repo.Fetch
- Text.Hotkeys.Repo.Pull
- Text.Hotkeys.Repo.Push
- Text.IssueLinkCM.OpenInBrowser
- Text.IssueLinkCM.CopyLink
- Text.MoveRepositoryNode
- Text.MoveRepositoryNode.Target
- Text.Preference.AI
- Text.Preference.AI.AnalyzeDiffPrompt
- Text.Preference.AI.ApiKey
- Text.Preference.AI.GenerateSubjectPrompt
- Text.Preference.AI.Model
- Text.Preference.AI.Name
- Text.Preference.AI.Server
- Text.Preference.Appearance.EditorFontSize
- Text.Preference.General.ShowAuthorTime
- Text.Preference.Integration
- Text.Preference.Shell
- Text.Preference.Shell.Type
- Text.Preference.Shell.Path
- Text.Repository.AutoFetching
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Repository.CustomActions
- Text.Repository.CustomActions.Empty
- Text.Repository.EnableReflog
- Text.Repository.Search.InCurrentBranch
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.ScanRepositories
- Text.ScanRepositories.RootDir
- Text.Squash.Into
- Text.Stash.KeepIndex
- Text.Stash.OnlyStagedChanges
- Text.Stash.TipForSelectedFiles
- Text.Statistics.Overview
- Text.TagCM.CopyMessage
- Text.Welcome.Move
- Text.Welcome.ScanDefaultCloneDir
- Text.WorkingCopy.CommitTip
- Text.WorkingCopy.CommitWithAutoStage
- Text.WorkingCopy.ConfirmCommitWithoutFiles
- Text.Workspace
- Text.Workspace.Configure
</details>
### pt_BR.axaml: 100.00%
### pt_BR.axaml: 99.14%
<details>
<summary>Missing Keys</summary>
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
</details>

View file

@ -1 +1 @@
8.38
8.39

View file

@ -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

View file

@ -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

View file

@ -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=

View file

@ -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

View file

@ -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

View file

@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.0",
"version": "9.0.0",
"rollForward": "latestMajor",
"allowPrerelease": false
}

View file

@ -478,17 +478,20 @@ namespace SourceGit
if (args.Length <= 1 || !args[0].Equals("--rebase-message-editor", StringComparison.Ordinal))
return false;
exitCode = 0;
var file = args[1];
var filename = Path.GetFileName(file);
if (!filename.Equals("COMMIT_EDITMSG", StringComparison.OrdinalIgnoreCase))
return true;
var jobsFile = Path.Combine(Path.GetDirectoryName(file)!, "sourcegit_rebase_jobs.json");
var gitDir = Path.GetDirectoryName(file)!;
var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile))
return true;
var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
var doneFile = Path.Combine(Path.GetDirectoryName(file)!, "rebase-merge", "done");
var doneFile = Path.Combine(gitDir, "rebase-merge", "done");
if (!File.Exists(doneFile))
return true;
@ -499,7 +502,6 @@ namespace SourceGit
var job = collection.Jobs[done.Length - 1];
File.WriteAllText(file, job.Message);
exitCode = 0;
return true;
}

View file

@ -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();
}
}

View file

@ -28,9 +28,9 @@ namespace SourceGit.Commands
Context = repo;
if (ignoreWhitespace)
Args = $"diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
Args = $"diff --no-ext-diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
else
Args = $"diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
Args = $"diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
}
public Models.DiffResult Result()
@ -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
{

View file

@ -44,7 +44,7 @@ namespace SourceGit.Commands
{
outputHandler?.Invoke(e.Data);
builder.AppendLine(e.Data);
}
}
};
try

View file

@ -16,7 +16,7 @@ namespace SourceGit.Commands
if (noTags)
Args += "--no-tags ";
else
Args += "--force ";
Args += "--tags ";
if (prune)
Args += "--prune ";

View file

@ -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;
}
}
}

View file

@ -4,11 +4,11 @@ namespace SourceGit.Commands
{
public class Statistics : Command
{
public Statistics(string repo)
public Statistics(string repo, int max)
{
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --branches --remotes -40000 --pretty=format:\"%ct$%aN\"";
Args = $"log --date-order --branches --remotes -{max} --pretty=format:\"%ct$%aN\"";
}
public Models.Statistics Result()

View file

@ -0,0 +1,22 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
namespace SourceGit.Converters
{
public static class FilterModeConverters
{
public static readonly FuncValueConverter<Models.FilterMode, IBrush> ToBorderBrush =
new FuncValueConverter<Models.FilterMode, IBrush>(v =>
{
switch (v)
{
case Models.FilterMode.Included:
return Brushes.Green;
case Models.FilterMode.Excluded:
return Brushes.Red;
default:
return Brushes.Transparent;
}
});
}
}

View file

@ -39,7 +39,7 @@ namespace SourceGit.Models
new ExternalMerger(4, "tortoise_merge", "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""),
new ExternalMerger(5, "kdiff3", "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(6, "beyond_compare", "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(7, "win_merge", "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(7, "win_merge", "WinMerge", "WinMergeU.exe", "\"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(8, "codium", "VSCodium", "VSCodium.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(9, "p4merge", "P4Merge", "p4merge.exe", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
};

60
src/Models/Filter.cs Normal file
View file

@ -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;
}
}

View file

@ -155,7 +155,12 @@ namespace SourceGit.Models
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(60) };
if (!string.IsNullOrEmpty(ApiKey))
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
{
if (Server.Contains("openai.azure.com/", StringComparison.Ordinal))
client.DefaultRequestHeaders.Add("api-key", ApiKey);
else
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
}
var req = new StringContent(JsonSerializer.Serialize(chat, JsonCodeGen.Default.OpenAIChatRequest), Encoding.UTF8, "application/json");
try

View file

@ -1,4 +1,8 @@
using Avalonia.Collections;
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Collections;
namespace SourceGit.Models
{
@ -76,11 +80,11 @@ namespace SourceGit.Models
set;
} = true;
public AvaloniaList<string> Filters
public AvaloniaList<Filter> HistoriesFilters
{
get;
set;
} = new AvaloniaList<string>();
} = new AvaloniaList<Filter>();
public AvaloniaList<CommitTemplate> CommitTemplates
{
@ -148,6 +152,208 @@ namespace SourceGit.Models
set;
} = "---";
public Dictionary<string, FilterMode> CollectHistoriesFilters()
{
var map = new Dictionary<string, FilterMode>();
foreach (var filter in HistoriesFilters)
map.Add(filter.Pattern, filter.Mode);
return map;
}
public bool UpdateHistoriesFilter(string pattern, FilterType type, FilterMode mode)
{
// Clear all filters when there's a filter that has different mode.
if (mode != FilterMode.None)
{
var clear = false;
foreach (var filter in HistoriesFilters)
{
if (filter.Mode != mode)
{
clear = true;
break;
}
}
if (clear)
{
HistoriesFilters.Clear();
HistoriesFilters.Add(new Filter(pattern, type, mode));
return true;
}
}
else
{
for (int i = 0; i < HistoriesFilters.Count; i++)
{
var filter = HistoriesFilters[i];
if (filter.Type == type && filter.Pattern.Equals(pattern, StringComparison.Ordinal))
{
HistoriesFilters.RemoveAt(i);
return true;
}
}
return false;
}
for (int i = 0; i < HistoriesFilters.Count; i++)
{
var filter = HistoriesFilters[i];
if (filter.Type != type)
continue;
if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
return false;
}
HistoriesFilters.Add(new Filter(pattern, type, mode));
return true;
}
public void RemoveChildrenBranchFilters(string pattern)
{
var dirty = new List<Filter>();
var prefix = $"{pattern}/";
foreach (var filter in HistoriesFilters)
{
if (filter.Type == FilterType.Tag)
continue;
if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal))
dirty.Add(filter);
}
foreach (var filter in dirty)
HistoriesFilters.Remove(filter);
}
public string BuildHistoriesFilter()
{
var excludedBranches = new List<string>();
var excludedRemotes = new List<string>();
var excludedTags = new List<string>();
var includedBranches = new List<string>();
var includedRemotes = new List<string>();
var includedTags = new List<string>();
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);
}
}
bool hasIncluded = includedBranches.Count > 0 || includedRemotes.Count > 0 || includedTags.Count > 0;
bool hasExcluded = excludedBranches.Count > 0 || excludedRemotes.Count > 0 || excludedTags.Count > 0;
var builder = new StringBuilder();
if (hasIncluded)
{
foreach (var b in includedBranches)
{
builder.Append("--branches=");
builder.Append(b);
builder.Append(' ');
}
foreach (var r in includedRemotes)
{
builder.Append("--remotes=");
builder.Append(r);
builder.Append(' ');
}
foreach (var t in includedTags)
{
builder.Append("--tags=");
builder.Append(t);
builder.Append(' ');
}
}
else if (hasExcluded)
{
if (excludedBranches.Count > 0)
{
foreach (var b in excludedBranches)
{
builder.Append("--exclude=");
builder.Append(b);
builder.Append(' ');
}
}
builder.Append("--exclude=HEA[D] --branches ");
if (excludedRemotes.Count > 0)
{
foreach (var r in excludedRemotes)
{
builder.Append("--exclude=");
builder.Append(r);
builder.Append(' ');
}
}
builder.Append("--exclude=origin/HEA[D] --remotes ");
if (excludedTags.Count > 0)
{
foreach (var t in excludedTags)
{
builder.Append("--exclude=");
builder.Append(t);
builder.Append(' ');
}
}
builder.Append("--tags ");
}
return builder.ToString();
}
public void PushCommitMessage(string message)
{
var existIdx = CommitMessages.IndexOf(message);

View file

@ -6,23 +6,25 @@ namespace SourceGit.Models
{
public static readonly ResetMode[] Supported =
[
new ResetMode("Soft", "Keep all changes. Stage differences", "--soft", Brushes.Green),
new ResetMode("Mixed", "Keep all changes. Unstage differences", "--mixed", Brushes.Orange),
new ResetMode("Merge", "Reset while keeping unmerged changes", "--merge", Brushes.Purple),
new ResetMode("Keep", "Reset while keeping local modifications", "--keep", Brushes.Purple),
new ResetMode("Hard", "Discard all changes", "--hard", Brushes.Red),
new ResetMode("Soft", "Keep all changes. Stage differences", "--soft", "S", Brushes.Green),
new ResetMode("Mixed", "Keep all changes. Unstage differences", "--mixed", "M", Brushes.Orange),
new ResetMode("Merge", "Reset while keeping unmerged changes", "--merge", "G", Brushes.Purple),
new ResetMode("Keep", "Reset while keeping local modifications", "--keep", "K", Brushes.Purple),
new ResetMode("Hard", "Discard all changes", "--hard", "H", Brushes.Red),
];
public string Name { get; set; }
public string Desc { get; set; }
public string Arg { get; set; }
public string Key { get; set; }
public IBrush Color { get; set; }
public ResetMode(string n, string d, string a, IBrush b)
public ResetMode(string n, string d, string a, string k, IBrush b)
{
Name = n;
Desc = d;
Arg = a;
Key = k;
Color = b;
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using LiveChartsCore;
using LiveChartsCore.Defaults;
@ -138,7 +139,8 @@ namespace SourceGit.Models
public Statistics()
{
_today = DateTime.Now.ToLocalTime().Date;
_thisWeekStart = _today.AddSeconds(-(int)_today.DayOfWeek * 3600 * 24);
var weekOffset = (7 + (int)_today.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek) % 7;
_thisWeekStart = _today.AddDays(-weekOffset);
_thisMonthStart = _today.AddDays(1 - _today.Day);
All = new StatisticsReport(StaticsticsMode.All, DateTime.MinValue);

View file

@ -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;
}
}

View file

@ -113,22 +113,11 @@ namespace SourceGit.Models
if (_updateTags > 0)
{
_updateTags = 0;
Task.Run(() =>
{
_repo.RefreshTags();
_repo.RefreshBranches();
_repo.RefreshCommits();
});
}
else
{
Task.Run(() =>
{
_repo.RefreshBranches();
_repo.RefreshCommits();
});
Task.Run(_repo.RefreshTags);
}
Task.Run(_repo.RefreshBranches);
Task.Run(_repo.RefreshCommits);
Task.Run(_repo.RefreshWorkingCopyChanges);
Task.Run(_repo.RefreshWorktrees);
}

View file

@ -58,7 +58,7 @@
<x:String x:Key="Text.BranchCM.DeleteMultiBranches" xml:space="preserve">Lösche alle ausgewählten {0} Branches</x:String>
<x:String x:Key="Text.BranchCM.DiscardAll" xml:space="preserve">Alle Änderungen verwerfen</x:String>
<x:String x:Key="Text.BranchCM.FastForward" xml:space="preserve">Fast-Forward zu ${0}$</x:String>
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetche ${0}$ nach ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetche ${0}$ in ${1}$ hinein...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Abschließen ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Merge ${0}$ in ${1}$ hinein...</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Pull ${0}$</x:String>
@ -73,7 +73,7 @@
<x:String x:Key="Text.Cancel" xml:space="preserve">ABBRECHEN</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Auf diese Revision zurücksetzen</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Auf Vorgänger-Revision zurücksetzen</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generiere Commit-Nachricht</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generiere Commit-Nachricht</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">ANZEIGE MODUS ÄNDERN</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Zeige als Datei- und Ordnerliste</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Zeige als Pfadliste</x:String>
@ -162,8 +162,8 @@
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Beispiel für Github-Regel hinzufügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Beispiel für Jira-Regel hinzufügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Beispiel für eine Gitlab Issue Regel einfügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Beispiel für einen Gitlab Merge Request einfügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Beispiel für Gitlab Issue Regel einfügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Beispiel für Gitlab Merge Request einfügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Neue Regel</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Ticketnummer Regex-Ausdruck:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Name:</x:String>
@ -171,7 +171,7 @@
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Verwende bitte $1, $2 um auf Regex-Gruppenwerte zuzugreifen.</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">Bevorzugter Service:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Wenn der 'Bevorzugte Service' aktiviert ist, wird SourceGit nur dieses Repository nutzen. Ansonsten wird, wenn mehrere Services verfügbar sind, eine Kontextmenü zur Auswahl angezeigt.</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Der ausgewählte 'Bevorzugte Service' wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Servies verfügbar sind wird ein Kontextmenü zur Auswahl angezeigt.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP Proxy für dieses Repository</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>
@ -240,6 +240,7 @@
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Vorherige Änderung</x:String>
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Als Patch speichern</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Zeige versteckte Symbole</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Nebeneinander</x:String>
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODUL</x:String>
@ -248,6 +249,7 @@
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Hervorhebung</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Zeilenumbruch</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Öffne in Merge Tool</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Alle Zeilen anzeigen</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Weniger Zeilen anzeigen</x:String>
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Mehr Zeilen anzeigen</x:String>
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">WÄHLE EINE DATEI AUS UM ÄNDERUNGEN ANZUZEIGEN</x:String>
@ -263,7 +265,7 @@
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Ziel:</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Ausgewählte Gruppe bearbeiten</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Ausgewähltes Repository bearbeiten</x:String>
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Führe benutzerte Aktion aus</x:String>
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Führe benutzerdefinierte Aktion aus</x:String>
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">Name der Aktion:</x:String>
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (ohne Auschecken)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
@ -290,7 +292,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">Datei Historie</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">INHALT</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">ÄNDERUNGEN</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTER</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development-Branch:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
@ -364,8 +365,12 @@
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Gestagte Änderungen committen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Gestagte Änderungen committen und pushen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Alle Änderungen stagen und committen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Neuen Branch basierend auf ausgewählten Commit erstellen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Ausgewählte Änderungen verwerfen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, wird direkt ausgeführt</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard Modus (Standard)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, wird direkt ausgeführt</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, wird direkt ausgeführt</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Erzwinge Neuladen des Repositorys</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ausgewählte Änderungen stagen/unstagen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit-Suchmodus</x:String>
@ -389,6 +394,8 @@
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interaktiver Rebase</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Ziel Branch:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Auf:</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">In Browser öffnen</x:String>
<x:String x:Key="Text.IssueLinkCM.CopyLink" xml:space="preserve">Link kopieren</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">FEHLER</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">INFO</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Branch mergen</x:String>
@ -429,7 +436,9 @@
<x:String x:Key="Text.Preference.AI.Model" xml:space="preserve">Modell</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">DARSTELLUNG</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Standardschriftgröße</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Schriftgröße</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">Standard</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Texteditor</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace-Schriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende die Monospace-Schriftart nur im Texteditor</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String>
@ -526,7 +535,7 @@
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Änderungen automatisch von Remote fetchen...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Aufräumen (GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Führt `git gc` auf diesem Repository aus.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Filter aufheben</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Repository Einstellungen</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String>
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">Benutzerdefinierte Aktionen</x:String>
@ -534,7 +543,9 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Aktiviere '--reflog' Option</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Öffne im Datei-Browser</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Suche Branches/Tags/Submodule</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">GEFILTERT:</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Aufheben</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Im Graph ausblenden</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Im Graph filtern</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOKALE BRANCHES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Zum HEAD wechseln</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Aktiviere '--first-parent' Option</x:String>
@ -593,7 +604,7 @@
<x:String x:Key="Text.Start" xml:space="preserve">START</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Stash</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Inklusive nicht-verfolgter Dateien</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Behalte Dateien des Stages</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Behalte gestagte Dateien</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Name:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Optional. Name dieses Stashes</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Nur gestagte Änderungen</x:String>

View file

@ -289,7 +289,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">File History</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENT</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">CHANGE</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTER</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development Branch:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
@ -434,8 +433,9 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Server</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPEARANCE</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Default Font</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Default Font Size</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Editor Font Size</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Font Size</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">Default</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace Font</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Only use monospace font in text editor</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Theme</x:String>
@ -540,7 +540,9 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Enable '--reflog' Option</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Open in File Browser</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Search Branches/Tags/Submodules</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">FILTERED BY:</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Unset</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Hide in commit graph</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Filter in commit graph</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOCAL BRANCHES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navigate to HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Enable '--first-parent' Option</x:String>

View file

@ -294,7 +294,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">Historial de Archivos</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENIDO</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">CAMBIO</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTRO</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Rama de Desarrollo:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
@ -438,8 +437,6 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APARIENCIA</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fuente por defecto</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Tamaño de fuente por defecto</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Tamaño de fuente del editor</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fuente Monospace</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar solo fuente monospace en el editor de texto</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
@ -544,7 +541,6 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Habilitar Opción '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Abrir en el Explorador</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Buscar Ramas/Etiquetas/Submódulos</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">FILTRAR POR:</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">RAMAS LOCALES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navegar a HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Habilitar Opción '--first-parent'</x:String>

View file

@ -3,23 +3,26 @@
<ResourceInclude Source="avares://SourceGit/Resources/Locales/en_US.axaml"/>
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="Text.About" xml:space="preserve">À propos</x:String>
<x:String x:Key="Text.About.Menu" xml:space="preserve">À propos de SourceGit</x:String>
<x:String x:Key="Text.About.BuildWith" xml:space="preserve">• Compilé avec </x:String>
<x:String x:Key="Text.About.Chart" xml:space="preserve">• Le graphique est rendu par </x:String>
<x:String x:Key="Text.About.Copyright" xml:space="preserve">© 2024 sourcegit-scm</x:String>
<x:String x:Key="Text.About.Editor" xml:space="preserve">• TextEditor de </x:String>
<x:String x:Key="Text.About.Fonts" xml:space="preserve">• Les polices Monospace proviennent de </x:String>
<x:String x:Key="Text.About.Menu" xml:space="preserve">À propos de SourceGit</x:String>
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Le code source est disponible sur </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Client Git Open Source et Gratuit</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Ajouter un Worktree</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">What to Checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Créer une nouvelle branche</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Branche existante</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Emplacement :</x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">Chemin vers ce worktree. Relatif supporté.</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Nom de branche:</x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Optionnel. Nom du dossier de destination par défaut.</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Suivre la branche :</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Suivi de la branche distante</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">What to Checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Créer une nouvelle branche</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Branche existante</x:String>
<x:String x:Key="Text.AIAssistant" xml:space="preserve">Assistant IA</x:String>
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Utiliser l'IA pour générer un message de commit</x:String>
<x:String x:Key="Text.Apply" xml:space="preserve">Appliquer</x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">Erreur</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">Soulever les erreurs et refuser d'appliquer le patch</x:String>
@ -55,6 +58,7 @@
<x:String x:Key="Text.BranchCM.DeleteMultiBranches" xml:space="preserve">Supprimer {0} branches sélectionnées</x:String>
<x:String x:Key="Text.BranchCM.DiscardAll" xml:space="preserve">Rejeter tous les changements</x:String>
<x:String x:Key="Text.BranchCM.FastForward" xml:space="preserve">Fast-Forward vers ${0}$</x:String>
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetch ${0}$ vers ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Terminer ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Fusionner ${0}$ dans ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Tirer ${0}$</x:String>
@ -69,6 +73,7 @@
<x:String x:Key="Text.Cancel" xml:space="preserve">ANNULER</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Réinitialiser à la révision parente</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Réinitialiser à cette révision</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Générer un message de commit</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">CHANGER LE MODE D'AFFICHAGE</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Afficher comme liste de dossiers/fichiers</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Afficher comme liste de chemins</x:String>
@ -77,24 +82,25 @@
<x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Checkout ce commit</x:String>
<x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Commit :</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Avertissement: un checkout vers un commit aboutiera vers un HEAD détaché</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branche :</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Changements locaux :</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Annuler</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Ne rien faire</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Mettre en stash et réappliquer</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branche :</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick de ce commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit :</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit tous les changements</x:String>
<x:String x:Key="Text.CherryPick.Mainline" xml:space="preserve">Ligne principale :</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Supprimer les stashes</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Vous essayez de supprimer tous les stashes. Êtes-vous sûr de vouloir continuer ?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Cloner repository distant</x:String>
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">Paramètres supplémentaires :</x:String>
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">Arguments additionnels au clônage. Optionnel.</x:String>
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Nom local :</x:String>
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Nom de dépôt. Optionnel.</x:String>
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Dossier parent :</x:String>
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">URL du dépôt :</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Cloner le dépôt distant</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">FERMER</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Éditeur</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Changer de commit</x:String>
@ -103,6 +109,7 @@
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Comparer avec le worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copier les informations</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copier le SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Action personnalisée</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Rebase interactif de ${0}$ ici</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebaser ${0}$ ici</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Réinitialiser ${0}$ ici</x:String>
@ -110,6 +117,7 @@
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Reformuler</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Enregistrer en tant que patch...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Squash dans le parent</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Squash les commits enfants ici</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">CHANGEMENTS</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Rechercher les changements...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">FICHIERS</x:String>
@ -126,29 +134,56 @@
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">PARENTS</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Description</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Ouvrir dans le navigateur</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Entrez le message du commit</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Description</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Configurer le dépôt</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">MODÈLE DE COMMIT</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Contenu de modèle:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Nom de modèle:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Contenu de modèle:</x:String>
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">ACTION PERSONNALISÉE</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">Arguments :</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">${REPO} - Chemin du repository; ${SHA} - SHA du commit sélectionné</x:String>
<x:String x:Key="Text.Configure.CustomAction.Executable" xml:space="preserve">Fichier exécutable :</x:String>
<x:String x:Key="Text.Configure.CustomAction.Name" xml:space="preserve">Nom :</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope" xml:space="preserve">Portée :</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope.Commit" xml:space="preserve">Commit</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">Repository</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Adresse e-mail</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Adresse e-mail</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch les dépôts distants automatiquement</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">minute(s)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Dépôt par défaut</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Activer --prune pour fetch</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Activer --signoff pour commit</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">SUIVI DES PROBLÈMES</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Ajouter une règle d'exemple Github</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Ajouter une règle d'exemple Jira</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Ajouter une règle d'exemple pour Incidents GitLab</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Ajouter une règle d'exemple pour Merge Request GitLab</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Nouvelle règle</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Issue Regex Expression:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Nom de règle :</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Veuillez utiliser $1, $2 pour accéder aux valeurs des groupes regex.</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL résultant:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Veuillez utiliser $1, $2 pour accéder aux valeurs des groupes regex.</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">IA</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">Service préféré:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Si le 'Service préféré' est défini, SourceGit l'utilisera seulement dans ce repository. Sinon, si plus d'un service est disponible, un menu contextuel permettant de choisir l'un d'eux sera affiché.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">Proxy HTTP</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">Proxy HTTP utilisé par ce dépôt</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Nom d'utilisateur</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Nom d'utilisateur pour ce dépôt</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Espaces de travail</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Couleur</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restaurer les onglets au démarrage</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Assistant Commits Conventionnels</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Changement Radical :</x:String>
<x:String x:Key="Text.ConventionalCommit.ClosedIssue" xml:space="preserve">Incident Clos :</x:String>
<x:String x:Key="Text.ConventionalCommit.Detail" xml:space="preserve">Détail des Modifications :</x:String>
<x:String x:Key="Text.ConventionalCommit.Scope" xml:space="preserve">Portée :</x:String>
<x:String x:Key="Text.ConventionalCommit.ShortDescription" xml:space="preserve">Courte Description :</x:String>
<x:String x:Key="Text.ConventionalCommit.Type" xml:space="preserve">Type de Changement :</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Copier</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Copier tout le texte</x:String>
<x:String x:Key="Text.CopyFileName" xml:space="preserve">Copier le nom de fichier</x:String>
@ -198,10 +233,12 @@
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">ANCIEN</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copier</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Mode de fichier changé</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorer les changements d'espaces</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">CHANGEMENT D'OBJET LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Différence suivante</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">PAS DE CHANGEMENT OU SEULEMENT EN FIN DE LIGNE</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Différence précédente</x:String>
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Enregistrer en tant que patch</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Afficher les caractères invisibles</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Diff côte-à-côte</x:String>
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SOUS-MODULE</x:String>
@ -210,6 +247,7 @@
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Coloration syntaxique</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Retour à la ligne</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Ouvrir dans l'outil de fusion</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Voir toutes les lignes</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Réduit le nombre de ligne visibles</x:String>
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Augmente le nombre de ligne visibles</x:String>
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">SÉLECTIONNEZ UN FICHIER POUR VOIR LES CHANGEMENTS</x:String>
@ -217,6 +255,7 @@
<x:String x:Key="Text.Discard" xml:space="preserve">Rejeter les changements</x:String>
<x:String x:Key="Text.Discard.All" xml:space="preserve">Tous les changements dans la copie de travail.</x:String>
<x:String x:Key="Text.Discard.Changes" xml:space="preserve">Changements :</x:String>
<x:String x:Key="Text.Discard.IncludeIgnored" xml:space="preserve">Inclure les fichiers ignorés</x:String>
<x:String x:Key="Text.Discard.Total" xml:space="preserve">{0} changements seront rejetés</x:String>
<x:String x:Key="Text.Discard.Warning" xml:space="preserve">Vous ne pouvez pas annuler cette action !!!</x:String>
<x:String x:Key="Text.EditRepositoryNode.Bookmark" xml:space="preserve">Signet :</x:String>
@ -224,6 +263,8 @@
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Cible :</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Éditer le groupe sélectionné</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Éditer le dépôt sélectionné</x:String>
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Lancer action personnalisée</x:String>
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">Nom de l'action :</x:String>
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (sans checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Fetch toutes les branches distantes</x:String>
@ -248,63 +289,68 @@
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Utiliser les leurs (checkout --theirs)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">Historique du fichier</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENU</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTRER</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">MODIFICATION</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development Branch:</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Branche de développement :</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Feature Prefix:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Finish Feature</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Finish Hotfix</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Finish Release</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Terminer Feature</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Terminer Hotfix</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Terminer Release</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Cible:</x:String>
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix Prefix:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Initialize Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Keep branch</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Production Branch:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Release:</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Release Prefix:</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Start Feature...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Start Feature</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Start Hotfix...</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">FLOW - Start Hotfix</x:String>
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Enter name</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Start Release...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Start Release</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Version Tag Prefix:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Initialiser Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Garder la branche</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Branche de production :</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Release :</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Release Prefix :</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Commencer Feature...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Commencer Feature</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Commencer Hotfix...</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">FLOW - Commencer Hotfix</x:String>
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Saisir le nom</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Commencer Release...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Commencer Release</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Préfixe Tag de Version :</x:String>
<x:String x:Key="Text.GitLFS" xml:space="preserve">Git LFS</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern" xml:space="preserve">Add Track Pattern...</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Pattern is file name</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Custom Pattern:</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Add Track Pattern to Git LFS</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern" xml:space="preserve">Ajouter un pattern de suivi...</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Le pattern est un nom de fichier</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Pattern personnalisé :</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Ajouter un pattern de suivi à Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Fetch LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Run `git lfs fetch` to download Git LFS objects. This does not update the working copy.</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Install Git LFS hooks</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Show Locks</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">No Locked Files</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Lock</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">LFS Locks</x:String>
<x:String x:Key="Text.GitLFS.Locks.Unlock" xml:space="preserve">Unlock</x:String>
<x:String x:Key="Text.GitLFS.Locks.UnlockForce" xml:space="preserve">Force Unlock</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Fetch les objets LFS</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Lancer `git lfs fetch` pour télécharger les objets Git LFS. Cela ne met pas à jour la copie de travail.</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Installer les hooks Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Afficher les verrous</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Pas de fichiers verrouillés</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Verrouiller</x:String>
<x:String x:Key="Text.GitLFS.Locks.OnlyMine" xml:space="preserve">Afficher seulement mes verrous</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">Verrous LFS</x:String>
<x:String x:Key="Text.GitLFS.Locks.Unlock" xml:space="preserve">Déverouiller</x:String>
<x:String x:Key="Text.GitLFS.Locks.UnlockForce" xml:space="preserve">Forcer le déverouillage</x:String>
<x:String x:Key="Text.GitLFS.Prune" xml:space="preserve">Prune</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Run `git lfs prune` to delete old LFS files from local storage</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Lancer `git lfs prune` pour supprimer les anciens fichier LFS du stockage local</x:String>
<x:String x:Key="Text.GitLFS.Pull" xml:space="preserve">Pull</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Pull LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Run `git lfs pull` to download all Git LFS files for current ref &amp; checkout</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Pull les objets LFS</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Lancer `git lfs pull` pour télécharger tous les fichier Git LFS de la référence actuelle &amp; checkout</x:String>
<x:String x:Key="Text.GitLFS.Push" xml:space="preserve">Push</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Push LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Push queued large files to the Git LFS endpoint</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Track files named '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Track all *{0} files</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Push les objets LFS</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Transférer les fichiers volumineux en file d'attente vers le point de terminaison Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Dépôt :</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Suivre les fichiers appelés '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Suivre tous les fichiers *{0}</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Historique</x:String>
<x:String x:Key="Text.Histories.DisplayMode" xml:space="preserve">Basculer entre dispositions Horizontal/Vertical</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTEUR</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">HEURE DE L'AUTEUR</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">GRAPHE &amp; SUJET</x:String>
<x:String x:Key="Text.Histories.Header.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">HEURE DE COMMIT</x:String>
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMITS SÉLECTIONNÉS</x:String>
<x:String x:Key="Text.Histories.Tips" xml:space="preserve">Maintenir 'Ctrl' ou 'Shift' enfoncée pour sélectionner plusieurs commits.</x:String>
<x:String x:Key="Text.Histories.Tips.MacOS" xml:space="preserve">Maintenir ⌘ ou ⇧ enfoncée pour sélectionner plusieurs commits.</x:String>
<x:String x:Key="Text.Histories.Tips.Prefix" xml:space="preserve">CONSEILS:</x:String>
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Référence des raccourcis clavier</x:String>
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Annuler le popup en cours</x:String>
@ -316,7 +362,13 @@
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">DÉPÔT</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Commit les changements de l'index</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Commit et pousser les changements de l'index</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Ajouter tous les changements et commit</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Créer une nouvelle branche basée sur le commit actuel</x:String>
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Rejeter les changements sélectionnés</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, démarre directement</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Mode tableau de bord (Défaut)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, démarre directement</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, démarre directement</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Forcer le rechargement du dépôt</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ajouter/Retirer les changements sélectionnés de l'index</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Recherche de commit</x:String>
@ -331,26 +383,30 @@
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Stage</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Retirer de l'index</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Rejeter</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialize Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interactive Rebase</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Target Branch:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">On:</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">ERROR</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialiser le repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Chemin :</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick en cours. Appuyer sur 'Abort' pour restaurer le HEAD d'origine.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request in progress. Appuyer sur 'Abort' pour restaurer le HEAD d'origine.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase in progress. Appuyer sur 'Abort' pour restaurer le HEAD d'origine.</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert in progress. Appuyer sur 'Abort' pour restaurer le HEAD d'origine.</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Rebase interactif</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Branche cible :</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Sur :</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">Ouvrir dans le navigateur</x:String>
<x:String x:Key="Text.IssueLinkCM.CopyLink" xml:space="preserve">Copier le lien</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">ERREUR</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">NOTICE</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Merge Branch</x:String>
<x:String x:Key="Text.Merge.Into" xml:space="preserve">Into:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Merge Option:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Source Branch:</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Merger la branche </x:String>
<x:String x:Key="Text.Merge.Into" xml:space="preserve">Dans :</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Option de merge:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Branche source :</x:String>
<x:String x:Key="Text.MoveRepositoryNode" xml:space="preserve">Déplacer le noeud du repository</x:String>
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Sélectionnier le noeud parent pour :</x:String>
<x:String x:Key="Text.Name" xml:space="preserve">Nom :</x:String>
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git n'a PAS été configuré. Veuillez d'abord le faire dans le menu Préférence.</x:String>
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Ouvrir le dossier AppData</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Open With...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Ouvrir avec...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Optionnel.</x:String>
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Créer un nouvel onglet</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Bookmark</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Fermer l'onglet</x:String>
@ -369,9 +425,17 @@
<x:String x:Key="Text.Period.LastYear" xml:space="preserve">L'an dernier</x:String>
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">il y a {0} ans</x:String>
<x:String x:Key="Text.Preference" xml:space="preserve">Préférences</x:String>
<x:String x:Key="Text.Preference.AI" xml:space="preserve">IA</x:String>
<x:String x:Key="Text.Preference.AI.AnalyzeDiffPrompt" xml:space="preserve">Analyser Diff Prompt</x:String>
<x:String x:Key="Text.Preference.AI.ApiKey" xml:space="preserve">Clé d'API</x:String>
<x:String x:Key="Text.Preference.AI.GenerateSubjectPrompt" xml:space="preserve">Générer le sujet de Prompt</x:String>
<x:String x:Key="Text.Preference.AI.Model" xml:space="preserve">Modèle</x:String>
<x:String x:Key="Text.Preference.AI.Name" xml:space="preserve">Nom</x:String>
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Serveur</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APPARENCE</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Police par défaut</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Taille de police par défaut</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Taille de police de l'éditeur</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Police monospace</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">N'utiliser que des polices monospace pour l'éditeur de texte</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Thème</x:String>
@ -386,6 +450,7 @@
<x:String x:Key="Text.Preference.General.Check4UpdatesOnStartup" xml:space="preserve">Vérifier les mises à jour au démarrage</x:String>
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Language</x:String>
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Historique de commits</x:String>
<x:String x:Key="Text.Preference.General.ShowAuthorTime" xml:space="preserve">Afficher l'heure de l'auteur au lieu de l'heure de validation dans le graphique</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Guide de longueur du sujet</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Activer auto CRLF</x:String>
@ -405,6 +470,10 @@
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">Saisir le chemin d'installation vers le programme GPG</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">Clé de signature de l'utilisateur</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">Clé de signature GPG de l'utilisateur</x:String>
<x:String x:Key="Text.Preference.Integration" xml:space="preserve">INTEGRATION</x:String>
<x:String x:Key="Text.Preference.Shell" xml:space="preserve">SHELL/TERMINAL</x:String>
<x:String x:Key="Text.Preference.Shell.Type" xml:space="preserve">Shell/Terminal</x:String>
<x:String x:Key="Text.Preference.Shell.Path" xml:space="preserve">Chemin</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Élaguer une branche distant</x:String> <!-- If it is indeed about a branch -->
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Cible :</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Élaguer les Worktrees</x:String>
@ -418,87 +487,90 @@
<x:String x:Key="Text.Pull.LocalChanges.DoNothing" xml:space="preserve">Ne rien faire</x:String>
<x:String x:Key="Text.Pull.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Réappliquer</x:String>
<x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Fetch sans les tags</x:String>
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Distant :</x:String> <!-- Branch ?-->
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Dépôt distant :</x:String>
<x:String x:Key="Text.Pull.Title" xml:space="preserve">Pull (Fetch &amp; Merge)</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Use rebase instead of merge</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Utiliser rebase au lieu de merge</x:String>
<x:String x:Key="Text.Push" xml:space="preserve">Push</x:String>
<x:String x:Key="Text.Push.CheckSubmodules" xml:space="preserve">Make sure submodules have been pushed</x:String>
<x:String x:Key="Text.Push.CheckSubmodules" xml:space="preserve">Assurez-vous que les submodules ont été poussés</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Force push</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Local Branch:</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Push Changes To Remote</x:String>
<x:String x:Key="Text.Push.To" xml:space="preserve">Remote Branch:</x:String>
<x:String x:Key="Text.Push.Tracking" xml:space="preserve">Set as tracking branch</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Push all tags</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Branche locale :</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Dépôt distant :</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Pousser les changements vers le dépôt distant</x:String>
<x:String x:Key="Text.Push.To" xml:space="preserve">Branche distante :</x:String>
<x:String x:Key="Text.Push.Tracking" xml:space="preserve">Définir comme branche de suivi</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Push tous les tags</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">Push Tag To Remote</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Push to all remotes</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Tag:</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Quit</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Rebase Current Branch</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Stash &amp; reapply local changes</x:String>
<x:String x:Key="Text.Rebase.On" xml:space="preserve">On:</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Rebase:</x:String>
<x:String x:Key="Text.RefetchAvatar" xml:space="preserve">Refresh</x:String>
<x:String x:Key="Text.Remote.AddTitle" xml:space="preserve">Add Remote</x:String>
<x:String x:Key="Text.Remote.EditTitle" xml:space="preserve">Edit Remote</x:String>
<x:String x:Key="Text.Remote.Name" xml:space="preserve">Name:</x:String>
<x:String x:Key="Text.Remote.Name.Placeholder" xml:space="preserve">Remote name</x:String>
<x:String x:Key="Text.Remote.URL" xml:space="preserve">Repository URL:</x:String>
<x:String x:Key="Text.Remote.URL.Placeholder" xml:space="preserve">Remote git repository URL</x:String>
<x:String x:Key="Text.RemoteCM.CopyURL" xml:space="preserve">Copy URL</x:String>
<x:String x:Key="Text.RemoteCM.Delete" xml:space="preserve">Delete...</x:String>
<x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Edit...</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Push tous les dépôts distants</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Dépôt distant :</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Tag :</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Quitter</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Rebase la branche actuelle</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Stash &amp; réappliquer changements locaux</x:String>
<x:String x:Key="Text.Rebase.On" xml:space="preserve">Sur :</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Rebase :</x:String>
<x:String x:Key="Text.RefetchAvatar" xml:space="preserve">Rafraîchir</x:String>
<x:String x:Key="Text.Remote.AddTitle" xml:space="preserve">Ajouter dépôt distant</x:String>
<x:String x:Key="Text.Remote.EditTitle" xml:space="preserve">Modifier dépôt distant</x:String>
<x:String x:Key="Text.Remote.Name" xml:space="preserve">Nom :</x:String>
<x:String x:Key="Text.Remote.Name.Placeholder" xml:space="preserve">Nom du dépôt distant</x:String>
<x:String x:Key="Text.Remote.URL" xml:space="preserve">URL du repository :</x:String>
<x:String x:Key="Text.Remote.URL.Placeholder" xml:space="preserve">URL du dépôt distant </x:String>
<x:String x:Key="Text.RemoteCM.CopyURL" xml:space="preserve">Copier l'URL</x:String>
<x:String x:Key="Text.RemoteCM.Delete" xml:space="preserve">Supprimer...</x:String>
<x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Editer...</x:String>
<x:String x:Key="Text.RemoteCM.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Open In Browser</x:String>
<x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Ouvrir dans le navigateur</x:String>
<x:String x:Key="Text.RemoteCM.Prune" xml:space="preserve">Prune</x:String>
<x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Confirm to Remove Worktree</x:String>
<x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Enable `--force` Option</x:String>
<x:String x:Key="Text.RemoveWorktree.Target" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.RenameBranch" xml:space="preserve">Rename Branch</x:String>
<x:String x:Key="Text.RenameBranch.Name" xml:space="preserve">New Name:</x:String>
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Unique name for this branch</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Confirmer la suppression du Worktree</x:String>
<x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Activer l'option `--force`</x:String>
<x:String x:Key="Text.RemoveWorktree.Target" xml:space="preserve">Cible :</x:String>
<x:String x:Key="Text.RenameBranch" xml:space="preserve"> la branche</x:String>
<x:String x:Key="Text.RenameBranch.Name" xml:space="preserve">Nouveau nom :</x:String>
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Nom unique pour cette branche</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Branche :</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">ABORT</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Cleanup(GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Run `git gc` command for this repository.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Clear all</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Configure this repository</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">CONTINUE</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Ouvrir dans l'explorateur Windows</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Search Branches/Tags/Submodules</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">FILTERED BY:</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOCAL BRANCHES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navigate To HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Enable '--first-parent' Option</x:String>
<x:String x:Key="Text.Repository.NewBranch" xml:space="preserve">Create Branch</x:String>
<x:String x:Key="Text.Repository.OpenIn" xml:space="preserve">Open In {0}</x:String>
<x:String x:Key="Text.Repository.OpenWithExternalTools" xml:space="preserve">Open In External Tools</x:String>
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Refresh</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ADD REMOTE</x:String>
<x:String x:Key="Text.Repository.Resolve" xml:space="preserve">RESOLVE</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Search Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">File</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Fetch automatique des changements depuis les dépôts...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Nettoyage(GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Lancer `git gc` pour ce repository.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Tout effacer</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Configurer ce repository</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">CONTINUER</x:String>
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">Pas d'actions personnalisées</x:String>
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Activer l'option '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Ouvrir dans l'explorateur de fichiers</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Rechercher Branches/Tags/Submodules</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">BRANCHES LOCALES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Naviguer vers le HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Activer l'option '--first-parent'</x:String>
<x:String x:Key="Text.Repository.NewBranch" xml:space="preserve">Créer une branche</x:String>
<x:String x:Key="Text.Repository.OpenIn" xml:space="preserve">Ouvrir dans {0}</x:String>
<x:String x:Key="Text.Repository.OpenWithExternalTools" xml:space="preserve">Ouvrir dans un outil externe</x:String>
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Rafraîchir</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">DEPOTS DISTANTS</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">AJOUTER DEPOT DISTANT</x:String>
<x:String x:Key="Text.Repository.Resolve" xml:space="preserve">RESOUDRE</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Rechercher un commit</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Fichier</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Message</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Author &amp; Committer</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Show Tags as Tree</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistics</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Auteur &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Branche actuelle</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Voir les Tags en tant qu'arbre</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistiques</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">ADD SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">UPDATE SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">AJOUTER SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">METTRE A JOUR SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Tags" xml:space="preserve">TAGS</x:String>
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">NEW TAG</x:String>
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">NOUVEAU TAG</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Ouvrir dans un terminal</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREES</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">ADD WORKTREE</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">AJOUTER WORKTREE</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">PRUNE</x:String>
<x:String x:Key="Text.RepositoryURL" xml:space="preserve">Git Repository URL</x:String>
<x:String x:Key="Text.Reset" xml:space="preserve">Reset Current Branch To Revision</x:String>
<x:String x:Key="Text.RepositoryURL" xml:space="preserve">URL du repository Git</x:String>
<x:String x:Key="Text.Reset" xml:space="preserve">Reset branche actuelle à la révision</x:String>
<x:String x:Key="Text.Reset.Mode" xml:space="preserve">Reset Mode:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Move To:</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Current Branch:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Déplacer vers :</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Branche actuelle :</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Ouvrir dans l'explorateur de fichier</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Revert le Commit</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">Commit :</x:String>
@ -509,7 +581,8 @@
<x:String x:Key="Text.Save" xml:space="preserve">SAUVEGARDER</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Sauvegarder en tant que...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Le patch a été sauvegardé !</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">Vérifier les mises à jour...</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">Dossier racine :</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">Rechercher des mises à jour...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">Une nouvelle version du logiciel est disponible :</x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">La vérification de mise à jour à échouée !</x:String>
<x:String x:Key="Text.SelfUpdate.GotoDownload" xml:space="preserve">Télécharger</x:String>
@ -517,13 +590,17 @@
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Mise à jour du logiciel</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Il n'y a pas de mise à jour pour le moment.</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash Commits</x:String>
<x:String x:Key="Text.Squash.Into" xml:space="preserve">Dans :</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">SSH Private Key:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Private SSH key store path</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">START</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Stash</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Include untracked files</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Message:</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Garder les fichiers staged</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Message :</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Optionnel. Nom de ce stash</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Seulement les changements staged</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Les modifications staged et unstaged des fichiers sélectionnés seront stockées!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Stash les changements locaux</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Appliquer</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Effacer</x:String>
@ -540,6 +617,7 @@
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">WEEK</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTHORS: </x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">APERCU</x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Add Submodule</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copy Relative Path</x:String>
@ -550,6 +628,7 @@
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Delete Submodule</x:String>
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Copy Tag Name</x:String>
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">Copier le message du tag</x:String>
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Delete ${0}$...</x:String>
<x:String x:Key="Text.TagCM.Merge" xml:space="preserve">Fusionner ${0}$ dans ${1}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Push ${0}$...</x:String>
@ -568,9 +647,11 @@
<x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Supprimer</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">GLISSER / DEPOSER DE DOSSIER SUPPORTÉ. GROUPAGE PERSONNALISÉ SUPPORTÉ.</x:String>
<x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Éditer</x:String>
<x:String x:Key="Text.Welcome.Move" xml:space="preserve">Déplacer vers un autre groupe</x:String>
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Ouvrir tous les dépôts</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Ouvrir un dépôt</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">Ouvrir le terminal</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">Réanalyser les repositories dans le dossier de clonage par défaut</x:String>
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">Chercher des dépôts...</x:String>
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">Trier</x:String>
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">Changements</x:String>
@ -584,6 +665,9 @@
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">COMMIT</x:String>
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">COMMIT &amp; PUSH</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Modèles/Historiques</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Trigger click event</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Stage tous les changements et commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithoutFiles" xml:space="preserve">Un commit vide a été détecté ! Voulez-vous continuer (--allow-empty) ?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLITS DÉTECTÉS</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">LES CONFLITS DE FICHIER SONT RÉSOLUS</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">INCLURE LES FICHIERS NON-SUIVIS</x:String>
@ -598,6 +682,8 @@
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">VOIR LES FICHIERS PRÉSUMÉS INCHANGÉS</x:String>
<x:String x:Key="Text.WorkingCopy.UseCommitTemplate" xml:space="preserve">Modèle: ${0}$</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Faites un clique droit sur les fichiers sélectionnés et faites vos choix pour la résoluion des conflits.</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">ESPACE DE TRAVAIL : </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Configurer les espaces de travail...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Copier le chemin</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Verrouiller</x:String>

View file

@ -176,7 +176,6 @@
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">Repositório</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Endereço de email</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Endereço de email</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Endereço de Email</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Buscar remotos automaticamente</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minuto(s)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Remoto padrão</x:String>
@ -317,7 +316,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">Histórico de Arquivos</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTEUDO</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">MUDANÇA</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTRO</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Branch de Desenvolvimento:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Prefixo da Feature:</x:String>
@ -460,8 +458,6 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
<x:String x:Key="Text.Preference.AI" xml:space="preserve">INTELIGÊNCIA ARTIFICIAL</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fonte Padrão</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Tamanho da fonte padrão</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Tamanho da fonte do editor</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fonte Monoespaçada</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar fonte monoespaçada apenas no editor de texto</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
@ -568,7 +564,6 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Habilitar opção '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Abrir no Navegador de Arquivos</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Pesquisar Branches/Tags/Submódulos</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">FILTRADO POR:</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Habilitar opção '--first-parent'</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">BRANCHES LOCAIS</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navegar para HEAD</x:String>

View file

@ -62,7 +62,7 @@
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Поток Git - Завершение ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Слить ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Забрать ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Перетащить ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Забрать ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Выложить ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Rebase" xml:space="preserve">Переместить ${0}$ на ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Переименовать ${0}$...</x:String>
@ -213,7 +213,7 @@
<x:String x:Key="Text.CreateTag.Type" xml:space="preserve">Вид:</x:String>
<x:String x:Key="Text.CreateTag.Type.Annotated" xml:space="preserve">Аннотированный</x:String>
<x:String x:Key="Text.CreateTag.Type.Lightweight" xml:space="preserve">Лёгкий</x:String>
<x:String x:Key="Text.CtrlClickTip" xml:space="preserve">Удерживайте Ctrl, чтобы начать непосредственно</x:String>
<x:String x:Key="Text.CtrlClickTip" xml:space="preserve">Удерживайте Ctrl, чтобы начать сразу</x:String>
<x:String x:Key="Text.Cut" xml:space="preserve">Вырезать</x:String>
<x:String x:Key="Text.DeleteBranch" xml:space="preserve">Удалить ветку</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">Ветка:</x:String>
@ -293,7 +293,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">История файлов</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">СОДЕРЖИМОЕ</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">ИЗМЕНИТЬ</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">ФИЛЬТР</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-поток</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Ветка разработчика:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Свойство:</x:String>
@ -369,11 +368,11 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Подготовить все изменения и зафиксировать</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Создать новую ветку на основе выбранной ветки</x:String>
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Отклонить выбранные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Извлечение, запускается непосредственно</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Извлечение, запускается сразу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Режим доски (по-умолчанию)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Принудительно перезагрузить этот хранилище</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Забрать, запускается непосредственно</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Выложить, запускается непосредственно</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Забрать, запускается сразу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Выложить, запускается сразу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Подготовленные/Неподготовленные выбранные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Режим поиска фиксаций</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Переключить на «Изменения»</x:String>
@ -438,8 +437,9 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Сервер</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">ВИД</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Шрифт по-умолчанию</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Размер шрифта по-умолчанию</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">Размер шрифта редактора</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Размер шрифта</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">По-умолчанию</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Редактор</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Моноширный шрифт</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">В текстовом редакторе используется только моноширный шрифт</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Тема</x:String>
@ -544,7 +544,10 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Разрешить опцию --reflog</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Открыть в файловом менеджере</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Поиск веток, меток и подмодулей</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">ОТФИЛЬТРОВАНО:</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Не установлен (По-умолчанию)</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Скрыть в графе фиксации</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Фильтр в графе фиксации</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Prefix" xml:space="preserve">ОТФИЛЬТРОВАНО:</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">ЛОКАЛЬНЫЕ ВЕТКИ</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Навигация по заголовку</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Включить опцию --first-parent</x:String>

View file

@ -292,7 +292,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">文件历史</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">文件内容</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">文件变更</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">过滤</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">GIT工作流</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">开发分支 </x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">特性分支 </x:String>
@ -437,7 +436,9 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">服务地址</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外观配置</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">缺省字体</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">默认字体大小</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">字体大小</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">默认</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">代码编辑器</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">代码字体大小</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等宽字体</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">仅在文本编辑器中使用等宽字体</x:String>
@ -543,7 +544,9 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">启用 --reflog 选项</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">在文件浏览器中打开</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">快速查找分支/标签/子模块</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">过滤规则 </x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">不指定</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">在提交列表中隐藏</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">使用其对提交列表过滤</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">本地分支</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">定位HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">启用 --first-parent 过滤选项</x:String>

View file

@ -292,7 +292,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">檔案歷史</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">檔案内容</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">檔案變更</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">篩選</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git 工作流</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">開發分支:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">功能分支:</x:String>
@ -437,8 +436,9 @@
<x:String x:Key="Text.Preference.AI.GenerateSubjectPrompt" xml:space="preserve">產生提交訊息提示詞</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">外觀設定</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">預設字型</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">預設字型大小</x:String>
<x:String x:Key="Text.Preference.Appearance.EditorFontSize" xml:space="preserve">程式碼字型大小</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">字型大小</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">預設</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">程式碼</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">等寬字型</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">僅在文字編輯器中使用等寬字型</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">佈景主題</x:String>
@ -543,7 +543,9 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">啟用 [--reflog] 選項</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">在檔案瀏覽器中開啟</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">快速搜尋分支/標籤/子模組</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">篩選規則:</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">不指定</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">在提交清單中隱藏</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">使用其來篩選提交清單</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">本機分支</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">回到 HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">啟用 [--first-parent] 選項</x:String>

View file

@ -168,12 +168,13 @@
<Setter Property="TextBlock.TextDecorations" Value=""/>
<Setter Property="Template">
<ControlTemplate>
<Grid Effect="drop-shadow(0 0 8 #80000000)">
<Grid Effect="drop-shadow(0 0 8 #30000000)">
<Border Margin="8"
Padding="8,6"
CornerRadius="4"
Background="{DynamicResource Brush.Popup}"
BorderThickness="0"
BorderBrush="{DynamicResource Brush.Border2}"
BorderThickness="1"
MaxWidth="{TemplateBinding MaxWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
@ -511,6 +512,12 @@
<Style Selector="Button.flat.primary ToolTip TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
</Style>
<Style Selector="Button.flat:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.flat:disabled">
<Setter Property="Background" Value="{DynamicResource Brush.FlatButton.Background}"/>
</Style>
<Style Selector="aes|SearchPanel">
<Setter Property="Template">
@ -1037,35 +1044,6 @@
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ToggleButton.filter">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="Transparent">
<Path x:Name="PART_IndicatorIcon"
Width="12"
Data="{StaticResource Icons.Filter}"
Fill="Transparent"
StrokeThickness="1"
Stroke="{DynamicResource Brush.FG2}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ToggleButton.filter:pressed">
<Setter Property="RenderTransform" Value="scale(1)"/>
</Style>
<Style Selector="ToggleButton.filter:checked /template/ Path#PART_IndicatorIcon">
<Setter Property="Fill" Value="{DynamicResource Brush.FG2}"/>
</Style>
<Style Selector="ToggleButton.filter:pointerover /template/ Path#PART_IndicatorIcon">
<Setter Property="Stroke" Value="{DynamicResource Brush.Accent}"/>
</Style>
<Style Selector="ToggleButton.tree_expander">
<Setter Property="Margin" Value="0" />
<Setter Property="Width" Value="9" />

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>App.manifest</ApplicationManifest>
<ApplicationIcon>App.ico</ApplicationIcon>
@ -37,17 +37,17 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.1.4" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.4" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.4" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.4" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.1.4" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.1.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc3.3" />
<PackageReference Include="TextMateSharp" Version="1.0.63" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.63" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc4.5" />
<PackageReference Include="TextMateSharp" Version="1.0.64" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.64" />
</ItemGroup>
<ItemGroup>

View file

@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
@ -13,15 +11,16 @@ namespace SourceGit.ViewModels
public class BranchTreeNode : ObservableObject
{
public string Name { get; private set; } = string.Empty;
public string Path { get; private set; } = string.Empty;
public object Backend { get; private set; } = null;
public int Depth { get; set; } = 0;
public bool IsSelected { get; set; } = false;
public List<BranchTreeNode> Children { get; private set; } = new List<BranchTreeNode>();
public bool IsFiltered
public Models.FilterMode FilterMode
{
get => _isFiltered;
set => SetProperty(ref _isFiltered, value);
get => _filterMode;
set => SetProperty(ref _filterMode, value);
}
public bool IsExpanded
@ -51,7 +50,7 @@ namespace SourceGit.ViewModels
get => Backend is Models.Branch b ? b.FriendlyName : null;
}
private bool _isFiltered = false;
private Models.FilterMode _filterMode = Models.FilterMode.None;
private bool _isExpanded = false;
private CornerRadius _cornerRadius = new CornerRadius(4);
@ -66,10 +65,11 @@ namespace SourceGit.ViewModels
foreach (var remote in remotes)
{
var path = $"remote/{remote.Name}";
var path = $"refs/remotes/{remote.Name}";
var node = new BranchTreeNode()
{
Name = remote.Name,
Path = path,
Backend = remote,
IsExpanded = bForceExpanded || _expanded.Contains(path),
};
@ -80,16 +80,15 @@ namespace SourceGit.ViewModels
foreach (var branch in branches)
{
var isFiltered = _filters.Contains(branch.FullName);
if (branch.IsLocal)
{
MakeBranchNode(branch, _locals, folders, "local", isFiltered, bForceExpanded);
MakeBranchNode(branch, _locals, folders, "refs/heads", bForceExpanded);
}
else
{
var remote = _remotes.Find(x => x.Name == branch.Remote);
if (remote != null)
MakeBranchNode(branch, remote.Children, folders, $"remote/{remote.Name}", isFiltered, bForceExpanded);
MakeBranchNode(branch, remote.Children, folders, $"refs/remotes/{remote.Name}", bForceExpanded);
}
}
@ -98,42 +97,32 @@ namespace SourceGit.ViewModels
SortNodes(_remotes);
}
public void SetFilters(AvaloniaList<string> filters)
{
_filters.AddRange(filters);
}
public void CollectExpandedNodes(List<BranchTreeNode> nodes, bool isLocal)
{
CollectExpandedNodes(nodes, isLocal ? "local" : "remote");
}
private void CollectExpandedNodes(List<BranchTreeNode> nodes, string prefix)
public void CollectExpandedNodes(List<BranchTreeNode> nodes)
{
foreach (var node in nodes)
{
if (node.Backend is Models.Branch)
continue;
var path = prefix + "/" + node.Name;
if (node.IsExpanded)
_expanded.Add(path);
_expanded.Add(node.Path);
CollectExpandedNodes(node.Children, path);
CollectExpandedNodes(node.Children);
}
}
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool isFiltered, bool bForceExpanded)
private void MakeBranchNode(Models.Branch branch, List<BranchTreeNode> roots, Dictionary<string, BranchTreeNode> folders, string prefix, bool bForceExpanded)
{
var fullpath = $"{prefix}/{branch.Name}";
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
if (sepIdx == -1 || branch.IsDetachedHead)
{
roots.Add(new BranchTreeNode()
{
Name = branch.Name,
Path = fullpath,
Backend = branch,
IsExpanded = false,
IsFiltered = isFiltered,
});
return;
}
@ -156,6 +145,7 @@ namespace SourceGit.ViewModels
lastFolder = new BranchTreeNode()
{
Name = name,
Path = folder,
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
};
roots.Add(lastFolder);
@ -166,6 +156,7 @@ namespace SourceGit.ViewModels
var cur = new BranchTreeNode()
{
Name = name,
Path = folder,
IsExpanded = bForceExpanded || branch.IsCurrent || _expanded.Contains(folder),
};
lastFolder.Children.Add(cur);
@ -179,10 +170,10 @@ namespace SourceGit.ViewModels
lastFolder?.Children.Add(new BranchTreeNode()
{
Name = Path.GetFileName(branch.Name),
Name = System.IO.Path.GetFileName(branch.Name),
Path = fullpath,
Backend = branch,
IsExpanded = false,
IsFiltered = isFiltered,
});
}
@ -206,7 +197,6 @@ namespace SourceGit.ViewModels
private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>();
private readonly List<BranchTreeNode> _remotes = new List<BranchTreeNode>();
private readonly HashSet<string> _expanded = new HashSet<string>();
private readonly List<string> _filters = new List<string>();
}
}
}

View file

@ -64,8 +64,8 @@ namespace SourceGit.ViewModels
CallUIThread(() =>
{
var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch);
if (b != null)
_repo.AutoAddBranchFilterPostCheckout(b);
if (b != null && _repo.HistoriesFilterMode == Models.FilterMode.Included)
_repo.Settings.UpdateHistoriesFilter(b.FullName, Models.FilterType.LocalBranch, Models.FilterMode.Included);
_repo.MarkBranchesDirtyManually();
_repo.SetWatcherEnabled(true);

View file

@ -118,7 +118,7 @@ namespace SourceGit.ViewModels
var trimmedUrl = url;
if (url.EndsWith(".git"))
trimmedUrl = url.Substring(0, url.Length - 4);
if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
WebLinks.Add(new Models.CommitLink() { Name = $"Github ({trimmedUrl.Substring(19)})", URLPrefix = $"{url}/commit/" });
else if (url.StartsWith("https://gitlab.", StringComparison.Ordinal))
@ -169,6 +169,11 @@ namespace SourceGit.ViewModels
SearchChangeFilter = string.Empty;
}
public Models.Commit GetParent(string sha)
{
return new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
}
public List<Models.Object> GetRevisionFilesUnderFolder(string parentFolder)
{
return new Commands.QueryRevisionObjects(_repo.FullPath, _commit.SHA, parentFolder).Result();
@ -288,7 +293,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) =>
{
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _commit.SHA) };
window.Show();
ev.Handled = true;
};
@ -381,10 +386,13 @@ namespace SourceGit.ViewModels
var openWith = new MenuItem();
openWith.Header = App.Text("OpenWith");
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
openWith.IsEnabled = File.Exists(fullPath);
openWith.Click += (_, ev) =>
{
Native.OS.OpenWithDefaultEditor(fullPath);
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.Path, tmpFile);
Native.OS.OpenWithDefaultEditor(tmpFile);
ev.Handled = true;
};
@ -426,7 +434,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) =>
{
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) };
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _commit.SHA) };
window.Show();
ev.Handled = true;
};

View file

@ -125,14 +125,8 @@ namespace SourceGit.ViewModels
CallUIThread(() =>
{
if (CheckoutAfterCreated)
{
_repo.AutoAddBranchFilterPostCheckout(new Models.Branch()
{
FullName = $"refs/heads/{_name}",
Upstream = BasedOn is Models.Branch { IsLocal: false } remoteBranch ? remoteBranch.FullName : string.Empty,
});
}
if (CheckoutAfterCreated && _repo.HistoriesFilterMode == Models.FilterMode.Included)
_repo.Settings.UpdateHistoriesFilter($"refs/heads/{_name}", Models.FilterType.LocalBranch, Models.FilterMode.Included);
_repo.MarkBranchesDirtyManually();
_repo.SetWatcherEnabled(true);

View file

@ -56,7 +56,7 @@ namespace SourceGit.ViewModels
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
{
SetProgressDescription("Deleting tracking remote branch...");
SetProgressDescription("Deleting remote-tracking branch...");
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name);
}
}

View file

@ -57,14 +57,14 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _viewContent, value);
}
public FileHistories(Repository repo, string file)
public FileHistories(Repository repo, string file, string commit = null)
{
_repo = repo;
_file = file;
Task.Run(() =>
{
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 -- \"{file}\"", false).Result();
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 {commit} -- \"{file}\"", false).Result();
Dispatcher.UIThread.Invoke(() =>
{
IsLoading = false;

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
@ -57,10 +58,17 @@ namespace SourceGit.ViewModels
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, _name);
CallUIThread(() =>
{
if (succ && _repo.Settings.Filters.Contains(oldName))
if (succ)
{
_repo.Settings.Filters.Remove(oldName);
_repo.Settings.Filters.Add($"refs/heads/{_name}");
foreach (var filter in _repo.Settings.HistoriesFilters)
{
if (filter.Type == Models.FilterType.LocalBranch &&
filter.Pattern.Equals(oldName, StringComparison.Ordinal))
{
filter.Pattern = $"refs/heads/{_name}";
break;
}
}
}
_repo.MarkBranchesDirtyManually();

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@ -45,6 +46,12 @@ namespace SourceGit.ViewModels
get => _settings;
}
public Models.FilterMode HistoriesFilterMode
{
get => _historiesFilterMode;
private set => SetProperty(ref _historiesFilterMode, value);
}
public bool HasAllowedSignersFile
{
get => _hasAllowedSignersFile;
@ -335,14 +342,7 @@ namespace SourceGit.ViewModels
public InProgressContext InProgressContext
{
get => _inProgressContext;
private set => SetProperty(ref _inProgressContext, value);
}
public bool HasUnsolvedConflicts
{
get => _hasUnsolvedConflicts;
private set => SetProperty(ref _hasUnsolvedConflicts, value);
get => _workingCopy?.InProgressContext;
}
public Models.Commit SearchResultSelectedCommit
@ -389,13 +389,16 @@ namespace SourceGit.ViewModels
App.RaiseException(string.Empty, $"Failed to start watcher for repository: '{_fullpath}'. You may need to press 'F5' to refresh repository manually!\n\nReason: {ex.Message}");
}
if (_settings.HistoriesFilters.Count > 0)
_historiesFilterMode = _settings.HistoriesFilters[0].Mode;
else
_historiesFilterMode = Models.FilterMode.None;
_histories = new Histories(this);
_workingCopy = new WorkingCopy(this);
_stashesPage = new StashesPage(this);
_selectedView = _histories;
_selectedViewIndex = 0;
_inProgressContext = null;
_hasUnsolvedConflicts = false;
_autoFetchTimer = new Timer(AutoFetchImpl, null, 5000, 5000);
RefreshAll();
@ -415,6 +418,7 @@ namespace SourceGit.ViewModels
// Ignore
}
_settings = null;
_historiesFilterMode = Models.FilterMode.None;
_autoFetchTimer.Dispose();
_autoFetchTimer = null;
@ -428,7 +432,6 @@ namespace SourceGit.ViewModels
_histories = null;
_workingCopy = null;
_stashesPage = null;
_inProgressContext = null;
_localChangesCount = 0;
_stashesCount = 0;
@ -455,13 +458,9 @@ namespace SourceGit.ViewModels
_hasAllowedSignersFile = !string.IsNullOrEmpty(allowedSignersFile);
});
Task.Run(() =>
{
RefreshBranches();
RefreshTags();
RefreshCommits();
});
Task.Run(RefreshBranches);
Task.Run(RefreshTags);
Task.Run(RefreshCommits);
Task.Run(RefreshSubmodules);
Task.Run(RefreshWorktrees);
Task.Run(RefreshWorkingCopyChanges);
@ -587,18 +586,6 @@ namespace SourceGit.ViewModels
Filter = string.Empty;
}
public void ClearHistoriesFilter()
{
_settings.Filters.Clear();
Task.Run(() =>
{
RefreshBranches();
RefreshTags();
RefreshCommits();
});
}
public void ClearSearchCommitFilter()
{
SearchCommitFilter = string.Empty;
@ -653,12 +640,8 @@ namespace SourceGit.ViewModels
{
if (_watcher == null)
{
Task.Run(() =>
{
RefreshBranches();
RefreshCommits();
});
Task.Run(RefreshBranches);
Task.Run(RefreshCommits);
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshWorktrees);
}
@ -696,53 +679,95 @@ namespace SourceGit.ViewModels
NavigateToCommit(_currentBranch.Head);
}
public void AutoAddBranchFilterPostCheckout(Models.Branch local)
public void ClearHistoriesFilter()
{
if (_settings.Filters.Count == 0 || _settings.Filters.Contains(local.FullName))
return;
_settings.HistoriesFilters.Clear();
HistoriesFilterMode = Models.FilterMode.None;
var hasLeft = false;
foreach (var b in _branches)
{
if (!b.FullName.Equals(local.FullName, StringComparison.Ordinal) &&
!b.FullName.Equals(local.Upstream, StringComparison.Ordinal) &&
!_settings.Filters.Contains(b.FullName))
{
hasLeft = true;
break;
}
}
if (!hasLeft)
_settings.Filters.Clear();
else if (string.IsNullOrEmpty(local.Upstream) || _settings.Filters.Contains(local.Upstream))
_settings.Filters.Add(local.FullName);
else
_settings.Filters.AddRange([local.FullName, local.Upstream]);
ResetBranchTreeFilterMode(LocalBranchTrees);
ResetBranchTreeFilterMode(RemoteBranchTrees);
ResetTagFilterMode();
Task.Run(RefreshCommits);
}
public void UpdateFilters(List<string> filters, bool toggle)
public void SetTagFilterMode(Models.Tag tag, Models.FilterMode mode)
{
var changed = false;
if (toggle)
var changed = _settings.UpdateHistoriesFilter(tag.Name, Models.FilterType.Tag, mode);
if (changed)
{
foreach (var filter in filters)
if (mode != Models.FilterMode.None || _settings.HistoriesFilters.Count == 0)
HistoriesFilterMode = mode;
RefreshHistoriesFilters();
}
}
public void SetBranchFilterMode(BranchTreeNode node, Models.FilterMode mode)
{
var isLocal = node.Path.StartsWith("refs/heads/", StringComparison.Ordinal);
var tree = isLocal ? _localBranchTrees : _remoteBranchTrees;
if (node.Backend is Models.Branch branch)
{
var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
var changed = _settings.UpdateHistoriesFilter(node.Path, type, mode);
if (!changed)
return;
if (isLocal && !string.IsNullOrEmpty(branch.Upstream) && mode != Models.FilterMode.Excluded)
{
if (!_settings.Filters.Contains(filter))
var upstream = branch.Upstream;
var canUpdateUpstream = true;
foreach (var filter in _settings.HistoriesFilters)
{
_settings.Filters.Add(filter);
changed = true;
bool matched = false;
if (filter.Type == Models.FilterType.RemoteBranch)
matched = filter.Pattern.Equals(upstream, StringComparison.Ordinal);
else if (filter.Type == Models.FilterType.RemoteBranchFolder)
matched = upstream.StartsWith(filter.Pattern, StringComparison.Ordinal);
if (matched && filter.Mode == Models.FilterMode.Excluded)
{
canUpdateUpstream = false;
break;
}
}
if (canUpdateUpstream)
_settings.UpdateHistoriesFilter(upstream, Models.FilterType.RemoteBranch, mode);
}
}
else
{
foreach (var filter in filters)
changed |= _settings.Filters.Remove(filter);
var type = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
var changed = _settings.UpdateHistoriesFilter(node.Path, type, mode);
if (!changed)
return;
_settings.RemoveChildrenBranchFilters(node.Path);
}
if (changed)
Task.Run(RefreshCommits);
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 = FindBranchNode(tree, parentPath);
if (parent == null)
break;
_settings.UpdateHistoriesFilter(parent.Path, parentType, Models.FilterMode.None);
cur = parent;
} while (true);
if (mode != Models.FilterMode.None || _settings.HistoriesFilters.Count == 0)
HistoriesFilterMode = mode;
RefreshHistoriesFilters();
}
public void StashAll(bool autoStart)
@ -756,40 +781,9 @@ namespace SourceGit.ViewModels
SelectedViewIndex = 1;
}
public async void ContinueMerge()
public void AbortMerge()
{
if (_inProgressContext != null)
{
SetWatcherEnabled(false);
var succ = await Task.Run(_inProgressContext.Continue);
if (succ && _workingCopy != null)
{
_workingCopy.CommitMessage = string.Empty;
}
SetWatcherEnabled(true);
}
else
{
MarkWorkingCopyDirtyManually();
}
}
public async void AbortMerge()
{
if (_inProgressContext != null)
{
SetWatcherEnabled(false);
var succ = await Task.Run(_inProgressContext.Abort);
if (succ && _workingCopy != null)
{
_workingCopy.CommitMessage = string.Empty;
}
SetWatcherEnabled(true);
}
else
{
MarkWorkingCopyDirtyManually();
}
_workingCopy?.AbortMerge();
}
public void RefreshBranches()
@ -833,9 +827,6 @@ namespace SourceGit.ViewModels
public void RefreshTags()
{
var tags = new Commands.QueryTags(_fullpath).Result();
foreach (var tag in tags)
tag.IsFiltered = _settings.Filters.Contains(tag.Name);
Dispatcher.UIThread.Invoke(() =>
{
Tags = tags;
@ -847,49 +838,21 @@ namespace SourceGit.ViewModels
{
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
var limits = $"-{Preference.Instance.MaxHistoryCommits} ";
var builder = new StringBuilder();
builder.Append($"-{Preference.Instance.MaxHistoryCommits} ");
if (_enableReflog)
limits += "--reflog ";
builder.Append("--reflog ");
if (_enableFirstParentInHistories)
limits += "--first-parent ";
builder.Append("--first-parent ");
var validFilters = new List<string>();
foreach (var filter in _settings.Filters)
{
if (filter.StartsWith("refs/", StringComparison.Ordinal))
{
if (_branches.FindIndex(x => x.FullName == filter) >= 0)
validFilters.Add(filter);
}
else
{
if (_tags.FindIndex(t => t.Name == filter) >= 0)
validFilters.Add(filter);
}
}
if (validFilters.Count > 0)
{
limits += string.Join(" ", validFilters);
if (_settings.Filters.Count != validFilters.Count)
{
Dispatcher.UIThread.Invoke(() =>
{
_settings.Filters.Clear();
_settings.Filters.AddRange(validFilters);
});
}
}
var invalidFilters = new List<Models.Filter>();
var filters = _settings.BuildHistoriesFilter();
if (string.IsNullOrEmpty(filters))
builder.Append("--branches --remotes --tags");
else
{
if (_settings.Filters.Count != 0)
Dispatcher.UIThread.Invoke(() => _settings.Filters.Clear());
builder.Append(filters);
limits += "--exclude=refs/stash --all";
}
var commits = new Commands.QueryCommits(_fullpath, limits).Result();
var commits = new Commands.QueryCommits(_fullpath, builder.ToString()).Result();
var graph = Models.CommitGraph.Parse(commits, _enableFirstParentInHistories);
Dispatcher.UIThread.Invoke(() =>
@ -921,23 +884,12 @@ namespace SourceGit.ViewModels
if (_workingCopy == null)
return;
var hasUnsolvedConflict = _workingCopy.SetData(changes);
var inProgress = null as InProgressContext;
if (File.Exists(Path.Combine(_gitDir, "CHERRY_PICK_HEAD")))
inProgress = new CherryPickInProgress(_fullpath);
else if (File.Exists(Path.Combine(_gitDir, "REBASE_HEAD")) && Directory.Exists(Path.Combine(_gitDir, "rebase-merge")))
inProgress = new RebaseInProgress(this);
else if (File.Exists(Path.Combine(_gitDir, "REVERT_HEAD")))
inProgress = new RevertInProgress(_fullpath);
else if (File.Exists(Path.Combine(_gitDir, "MERGE_HEAD")))
inProgress = new MergeInProgress(_fullpath);
_workingCopy.SetData(changes);
Dispatcher.UIThread.Invoke(() =>
{
InProgressContext = inProgress;
HasUnsolvedConflicts = hasUnsolvedConflict;
LocalChangesCount = changes.Count;
OnPropertyChanged(nameof(InProgressContext));
});
}
@ -2062,12 +2014,10 @@ namespace SourceGit.ViewModels
private BranchTreeNode.Builder BuildBranchTree(List<Models.Branch> branches, List<Models.Remote> remotes)
{
var builder = new BranchTreeNode.Builder();
builder.SetFilters(_settings.Filters);
if (string.IsNullOrEmpty(_filter))
{
builder.CollectExpandedNodes(_localBranchTrees, true);
builder.CollectExpandedNodes(_remoteBranchTrees, false);
builder.CollectExpandedNodes(_localBranchTrees);
builder.CollectExpandedNodes(_remoteBranchTrees);
builder.Run(branches, remotes, false);
}
else
@ -2082,6 +2032,9 @@ namespace SourceGit.ViewModels
builder.Run(visibles, remotes, true);
}
var historiesFilters = _settings.CollectHistoriesFilters();
UpdateBranchTreeFilterMode(builder.Locals, historiesFilters);
UpdateBranchTreeFilterMode(builder.Remotes, historiesFilters);
return builder;
}
@ -2101,6 +2054,8 @@ namespace SourceGit.ViewModels
}
}
var historiesFilters = _settings.CollectHistoriesFilters();
UpdateTagFilterMode(historiesFilters);
return visible;
}
@ -2122,6 +2077,74 @@ namespace SourceGit.ViewModels
return visible;
}
private void RefreshHistoriesFilters()
{
var filters = _settings.CollectHistoriesFilters();
UpdateBranchTreeFilterMode(LocalBranchTrees, filters);
UpdateBranchTreeFilterMode(RemoteBranchTrees, filters);
UpdateTagFilterMode(filters);
Task.Run(RefreshCommits);
}
private void UpdateBranchTreeFilterMode(List<BranchTreeNode> nodes, Dictionary<string, Models.FilterMode> filters)
{
foreach (var node in nodes)
{
if (filters.TryGetValue(node.Path, out var value))
node.FilterMode = value;
else
node.FilterMode = Models.FilterMode.None;
if (!node.IsBranch)
UpdateBranchTreeFilterMode(node.Children, filters);
}
}
private void UpdateTagFilterMode(Dictionary<string, Models.FilterMode> filters)
{
foreach (var tag in _tags)
{
if (filters.TryGetValue(tag.Name, out var value))
tag.FilterMode = value;
else
tag.FilterMode = Models.FilterMode.None;
}
}
private void ResetBranchTreeFilterMode(List<BranchTreeNode> nodes)
{
foreach (var node in nodes)
{
node.FilterMode = Models.FilterMode.None;
if (!node.IsBranch)
ResetBranchTreeFilterMode(node.Children);
}
}
private void ResetTagFilterMode()
{
foreach (var tag in _tags)
tag.FilterMode = Models.FilterMode.None;
}
private BranchTreeNode FindBranchNode(List<BranchTreeNode> nodes, string path)
{
foreach (var node in nodes)
{
if (node.Path.Equals(path, StringComparison.Ordinal))
return node;
if (path.StartsWith(node.Path, StringComparison.Ordinal))
{
var founded = FindBranchNode(node.Children, path);
if (founded != null)
return founded;
}
}
return null;
}
private void UpdateCurrentRevisionFilesForSearchSuggestion()
{
_revisionFiles.Clear();
@ -2185,6 +2208,7 @@ namespace SourceGit.ViewModels
private string _fullpath = string.Empty;
private string _gitDir = string.Empty;
private Models.RepositorySettings _settings = null;
private Models.FilterMode _historiesFilterMode = Models.FilterMode.None;
private bool _hasAllowedSignersFile = false;
private Models.Watcher _watcher = null;
@ -2227,10 +2251,7 @@ namespace SourceGit.ViewModels
private List<Models.Submodule> _visibleSubmodules = new List<Models.Submodule>();
private bool _includeUntracked = true;
private InProgressContext _inProgressContext = null;
private bool _hasUnsolvedConflicts = false;
private Models.Commit _searchResultSelectedCommit = null;
private Timer _autoFetchTimer = null;
private DateTime _lastFetchTime = DateTime.MinValue;
}

View file

@ -54,7 +54,7 @@ namespace SourceGit.ViewModels
{
Task.Run(() =>
{
var result = new Commands.Statistics(repo).Result();
var result = new Commands.Statistics(repo, Preference.Instance.MaxHistoryCommits).Result();
Dispatcher.UIThread.Invoke(() =>
{
_data = result;

View file

@ -22,16 +22,6 @@ namespace SourceGit.ViewModels
get => Tag == null;
}
public bool IsFiltered
{
get => Tag?.IsFiltered ?? false;
set
{
if (Tag != null)
Tag.IsFiltered = value;
}
}
public bool IsExpanded
{
get => _isExpanded;

View file

@ -56,6 +56,18 @@ namespace SourceGit.ViewModels
}
}
public bool HasUnsolvedConflicts
{
get => _hasUnsolvedConflicts;
set => SetProperty(ref _hasUnsolvedConflicts, value);
}
public InProgressContext InProgressContext
{
get => _inProgressContext;
private set => SetProperty(ref _inProgressContext, value);
}
public bool IsStaging
{
get => _isStaging;
@ -191,6 +203,7 @@ namespace SourceGit.ViewModels
public void Cleanup()
{
_repo = null;
_inProgressContext = null;
_selectedUnstaged.Clear();
OnPropertyChanged(nameof(SelectedUnstaged));
@ -208,7 +221,7 @@ namespace SourceGit.ViewModels
_commitMessage = string.Empty;
}
public bool SetData(List<Models.Change> changes)
public void SetData(List<Models.Change> changes)
{
if (!IsChanged(_cached, changes))
{
@ -221,9 +234,22 @@ namespace SourceGit.ViewModels
SetDetail(_selectedStaged[0], false);
else
SetDetail(null, false);
var inProgress = null as InProgressContext;
if (File.Exists(Path.Combine(_repo.GitDir, "CHERRY_PICK_HEAD")))
inProgress = new CherryPickInProgress(_repo.FullPath);
else if (File.Exists(Path.Combine(_repo.GitDir, "REBASE_HEAD")) && Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")))
inProgress = new RebaseInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REVERT_HEAD")))
inProgress = new RevertInProgress(_repo.FullPath);
else if (File.Exists(Path.Combine(_repo.GitDir, "MERGE_HEAD")))
inProgress = new MergeInProgress(_repo.FullPath);
HasUnsolvedConflicts = _cached.Find(x => x.IsConflit) != null;
InProgressContext = inProgress;
});
return _cached.Find(x => x.IsConflit) != null;
return;
}
_cached = changes;
@ -268,6 +294,7 @@ namespace SourceGit.ViewModels
Dispatcher.UIThread.Invoke(() =>
{
_isLoadingData = true;
HasUnsolvedConflicts = hasConflict;
Unstaged = unstaged;
Staged = staged;
SelectedUnstaged = selectedUnstaged;
@ -281,6 +308,18 @@ namespace SourceGit.ViewModels
else
SetDetail(null, false);
var inProgress = null as InProgressContext;
if (File.Exists(Path.Combine(_repo.GitDir, "CHERRY_PICK_HEAD")))
inProgress = new CherryPickInProgress(_repo.FullPath);
else if (File.Exists(Path.Combine(_repo.GitDir, "REBASE_HEAD")) && Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")))
inProgress = new RebaseInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REVERT_HEAD")))
inProgress = new RevertInProgress(_repo.FullPath);
else if (File.Exists(Path.Combine(_repo.GitDir, "MERGE_HEAD")))
inProgress = new MergeInProgress(_repo.FullPath);
InProgressContext = inProgress;
// Try to load merge message from MERGE_MSG
if (string.IsNullOrEmpty(_commitMessage))
{
@ -289,8 +328,6 @@ namespace SourceGit.ViewModels
CommitMessage = File.ReadAllText(mergeMsgFile);
}
});
return hasConflict;
}
public void OpenAssumeUnchanged()
@ -403,6 +440,52 @@ namespace SourceGit.ViewModels
}
}
public void ContinueMerge()
{
if (_inProgressContext != null)
{
_repo.SetWatcherEnabled(false);
Task.Run(() =>
{
var succ = _inProgressContext.Continue();
Dispatcher.UIThread.Invoke(() =>
{
if (succ)
CommitMessage = string.Empty;
_repo.SetWatcherEnabled(true);
});
});
}
else
{
_repo.MarkWorkingCopyDirtyManually();
}
}
public void AbortMerge()
{
if (_inProgressContext != null)
{
_repo.SetWatcherEnabled(false);
Task.Run(() =>
{
var succ = _inProgressContext.Abort();
Dispatcher.UIThread.Invoke(() =>
{
if (succ)
CommitMessage = string.Empty;
_repo.SetWatcherEnabled(true);
});
});
}
else
{
_repo.MarkWorkingCopyDirtyManually();
}
}
public void Commit()
{
DoCommit(false, false, false);
@ -1475,5 +1558,8 @@ namespace SourceGit.ViewModels
private int _count = 0;
private object _detailContext = null;
private string _commitMessage = string.Empty;
private bool _hasUnsolvedConflicts = false;
private InProgressContext _inProgressContext = null;
}
}

View file

@ -24,6 +24,10 @@
<Style Selector="ListBoxItem" x:DataType="vm:BranchTreeNode">
<Setter Property="CornerRadius" Value="{Binding CornerRadius}"/>
</Style>
<Style Selector="ListBoxItem:pointerover v|FilterModeSwitchButton">
<Setter Property="IsNoneVisible" Value="True"/>
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
@ -67,15 +71,10 @@
Foreground="{DynamicResource Brush.BadgeFG}"
Background="{DynamicResource Brush.Badge}"/>
<!-- Filter Toggle Button -->
<ToggleButton Grid.Column="3"
Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
IsVisible="{Binding IsBranch}"
IsChecked="{Binding IsFiltered}"
Click="OnToggleFilterClicked"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
<!-- Filter Mode Switcher -->
<v:FilterModeSwitchButton Grid.Column="3"
Margin="0,0,8,0"
Mode="{Binding FilterMode}"/>
</Grid>
</Grid>
</DataTemplate>

View file

@ -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<string> 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<ViewModels.BranchTreeNode> rows, List<ViewModels.BranchTreeNode> nodes, int depth)
{
foreach (var node in nodes)
@ -477,23 +455,6 @@ namespace SourceGit.Views
CollectBranchesInNode(outs, sub);
}
private bool UpdateUpstreamFilterState(List<ViewModels.BranchTreeNode> 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;
}
}

View file

@ -117,7 +117,28 @@
TextDecorations="Underline"
Cursor="Hand"
Margin="0,0,16,0"
PointerPressed="OnSHAPressed"/>
PointerEntered="OnSHAPointerEntered"
PointerPressed="OnSHAPressed">
<TextBlock.Styles>
<Style Selector="ToolTip">
<Setter Property="MaxWidth" Value="600"/>
</Style>
</TextBlock.Styles>
<TextBlock.DataTemplates>
<DataTemplate DataType="m:Commit">
<StackPanel MinWidth="400" Orientation="Vertical">
<Grid ColumnDefinitions="Auto,*,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" Classes="primary" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
</Grid>
<TextBlock Classes="primary" Margin="0,8,0,0" Text="{Binding Subject}" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</TextBlock.DataTemplates>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

View file

@ -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, ctl.IsPointerOver);
}
}
}
e.Handled = true;
}
private void OnSHAPressed(object sender, PointerPressedEventArgs e)
{
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })

View file

@ -38,7 +38,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty<IBrush> BackgroundProperty =
AvaloniaProperty.Register<CommitRefsPresenter, IBrush>(nameof(Background), null);
AvaloniaProperty.Register<CommitRefsPresenter, IBrush>(nameof(Background), Brushes.Transparent);
public IBrush Background
{
@ -56,7 +56,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty<bool> UseGraphColorProperty =
AvaloniaProperty.Register<CommitRefsPresenter, bool>(nameof(UseGraphColor), false);
AvaloniaProperty.Register<CommitRefsPresenter, bool>(nameof(UseGraphColor));
public bool UseGraphColor
{
@ -96,7 +96,6 @@ namespace SourceGit.Views
var x = 1.0;
foreach (var item in _items)
{
var iconRect = new RoundedRect(new Rect(x, 0, 16, 16), new CornerRadius(2, 0, 0, 2));
var entireRect = new RoundedRect(new Rect(x, 0, item.Width, 16), new CornerRadius(2));
if (item.IsHead)

View file

@ -34,8 +34,24 @@
<!-- Toolbar Buttons -->
<StackPanel Grid.Column="3" Margin="8,0,0,0" Orientation="Horizontal" VerticalAlignment="Center">
<Button Classes="icon_button"
Width="28"
Click="OnGotoPrevChange"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.Prev}">
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/>
</Button>
<Button Classes="icon_button"
Width="28"
Click="OnGotoNextChange"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.Next}">
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/>
</Button>
<Button Classes="icon_button"
Width="32"
Width="28"
Command="{Binding IncrUnified}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Incr}">
@ -46,7 +62,7 @@
</Button>
<Button Classes="icon_button"
Width="32"
Width="28"
Command="{Binding DecrUnified}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Decr}">
@ -60,9 +76,7 @@
</Button>
<ToggleButton Classes="line_path"
Width="32" Height="18"
Background="Transparent"
Padding="9,6"
Width="28"
Command="{Binding ToggleFullTextDiff}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFullTextDiff, Mode=OneWay}"
IsVisible="{Binding IsTextDiff}"
@ -71,9 +85,8 @@
</ToggleButton>
<ToggleButton Classes="line_path"
Width="32" Height="18"
Width="28"
Background="Transparent"
Padding="9,6"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.SyntaxHighlight}">
@ -81,9 +94,7 @@
</ToggleButton>
<ToggleButton Classes="line_path"
Width="32" Height="18"
Background="Transparent"
Padding="9,6"
Width="28"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Diff.ToggleWordWrap}">
<ToggleButton.IsVisible>
@ -97,14 +108,14 @@
</ToggleButton>
<ToggleButton Classes="line_path"
Width="32"
Width="28"
IsChecked="{Binding IgnoreWhitespace, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Diff.IgnoreWhitespace}">
<Path Width="14" Height="14" Stretch="Uniform" Data="{StaticResource Icons.Whitespace}"/>
</ToggleButton>
<ToggleButton Classes="line_path"
Width="32"
Width="28"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.ShowHiddenSymbols}">
@ -112,16 +123,14 @@
</ToggleButton>
<ToggleButton Classes="line_path"
Width="32" Height="18"
Background="Transparent"
Padding="9,6"
Width="28" Height="18"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.SideBySide}">
<Path Width="12" Height="12" Data="{StaticResource Icons.LayoutHorizontal}" Margin="0,2,0,0"/>
</ToggleButton>
<Button Classes="icon_button" Width="32" Command="{Binding OpenExternalMergeTool}" ToolTip.Tip="{DynamicResource Text.Diff.UseMerger}">
<Button Classes="icon_button" Width="28" Command="{Binding OpenExternalMergeTool}" ToolTip.Tip="{DynamicResource Text.Diff.UseMerger}">
<Path Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.OpenWith}"/>
</Button>
</StackPanel>

View file

@ -1,4 +1,6 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
@ -8,5 +10,31 @@ namespace SourceGit.Views
{
InitializeComponent();
}
private void OnGotoPrevChange(object _, RoutedEventArgs e)
{
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (textDiff == null)
return;
textDiff.GotoPrevChange();
if (textDiff is SingleSideTextDiffPresenter presenter)
presenter.ForceSyncScrollOffset();
e.Handled = true;
}
private void OnGotoNextChange(object _, RoutedEventArgs e)
{
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (textDiff == null)
return;
textDiff.GotoNextChange();
if (textDiff is SingleSideTextDiffPresenter presenter)
presenter.ForceSyncScrollOffset();
e.Handled = true;
}
}
}

View file

@ -0,0 +1,32 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.FilterModeSwitchButton"
x:Name="ThisControl">
<Button Classes="icon_button"
Width="12" Height="12"
Padding="0"
Background="Transparent"
VerticalContentAlignment="Center"
Click="OnChangeFilterModeButtonClicked">
<Grid>
<Path Width="12" Height="12"
Data="{StaticResource Icons.Eye}"
Fill="{DynamicResource Brush.FG2}"
IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.None}}"/>
<Path Width="12" Height="12"
Data="{StaticResource Icons.Filter}"
Fill="{DynamicResource Brush.Accent}"
IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Included}}"/>
<Path Width="12" Height="12"
Data="{StaticResource Icons.EyeClose}"
Fill="{DynamicResource Brush.Accent}"
IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Excluded}}"/>
</Grid>
</Button>
</UserControl>

View file

@ -0,0 +1,167 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
public partial class FilterModeSwitchButton : UserControl
{
public static readonly StyledProperty<Models.FilterMode> ModeProperty =
AvaloniaProperty.Register<FilterModeSwitchButton, Models.FilterMode>(nameof(Mode));
public Models.FilterMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
public static readonly StyledProperty<bool> IsNoneVisibleProperty =
AvaloniaProperty.Register<FilterModeSwitchButton, bool>(nameof(IsNoneVisible));
public bool IsNoneVisible
{
get => GetValue(IsNoneVisibleProperty);
set => SetValue(IsNoneVisibleProperty, value);
}
public static readonly StyledProperty<bool> IsContextMenuOpeningProperty =
AvaloniaProperty.Register<FilterModeSwitchButton, bool>(nameof(IsContextMenuOpening));
public bool IsContextMenuOpening
{
get => GetValue(IsContextMenuOpeningProperty);
set => SetValue(IsContextMenuOpeningProperty, value);
}
public FilterModeSwitchButton()
{
IsVisible = false;
InitializeComponent();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ModeProperty ||
change.Property == IsNoneVisibleProperty ||
change.Property == IsContextMenuOpeningProperty)
{
var visible = (Mode != Models.FilterMode.None || IsNoneVisible || IsContextMenuOpening);
SetCurrentValue(IsVisibleProperty, visible);
}
}
private void OnChangeFilterModeButtonClicked(object sender, RoutedEventArgs e)
{
var repoView = this.FindAncestorOfType<Repository>();
if (repoView == null)
return;
var repo = repoView.DataContext as ViewModels.Repository;
if (repo == null)
return;
var button = sender as Button;
if (button == null)
return;
var menu = new ContextMenu();
var mode = Models.FilterMode.None;
if (DataContext is Models.Tag tag)
{
mode = tag.FilterMode;
if (mode != Models.FilterMode.None)
{
var unset = new MenuItem();
unset.Header = App.Text("Repository.FilterCommits.Default");
unset.Click += (_, ev) =>
{
repo.SetTagFilterMode(tag, Models.FilterMode.None);
ev.Handled = true;
};
menu.Items.Add(unset);
menu.Items.Add(new MenuItem() { Header = "-" });
}
var include = new MenuItem();
include.Icon = App.CreateMenuIcon("Icons.Filter");
include.Header = App.Text("Repository.FilterCommits.Include");
include.IsEnabled = mode != Models.FilterMode.Included;
include.Click += (_, ev) =>
{
repo.SetTagFilterMode(tag, Models.FilterMode.Included);
ev.Handled = true;
};
var exclude = new MenuItem();
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
exclude.Header = App.Text("Repository.FilterCommits.Exclude");
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
exclude.Click += (_, ev) =>
{
repo.SetTagFilterMode(tag, Models.FilterMode.Excluded);
ev.Handled = true;
};
menu.Items.Add(include);
menu.Items.Add(exclude);
}
else if (DataContext is ViewModels.BranchTreeNode node)
{
mode = node.FilterMode;
if (mode != Models.FilterMode.None)
{
var unset = new MenuItem();
unset.Header = App.Text("Repository.FilterCommits.Default");
unset.Click += (_, ev) =>
{
repo.SetBranchFilterMode(node, Models.FilterMode.None);
ev.Handled = true;
};
menu.Items.Add(unset);
menu.Items.Add(new MenuItem() { Header = "-" });
}
var include = new MenuItem();
include.Icon = App.CreateMenuIcon("Icons.Filter");
include.Header = App.Text("Repository.FilterCommits.Include");
include.IsEnabled = mode != Models.FilterMode.Included;
include.Click += (_, ev) =>
{
repo.SetBranchFilterMode(node, Models.FilterMode.Included);
ev.Handled = true;
};
var exclude = new MenuItem();
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
exclude.Header = App.Text("Repository.FilterCommits.Exclude");
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
exclude.Click += (_, ev) =>
{
repo.SetBranchFilterMode(node, Models.FilterMode.Excluded);
ev.Handled = true;
};
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;
}
}
}

View file

@ -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<Models.Hyperlink>();
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);
}
@ -713,9 +730,12 @@ namespace SourceGit.Views
private void OnCommitListDoubleTapped(object sender, TappedEventArgs e)
{
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: 1 } selected })
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: 1 } })
{
histories.DoubleTapped(selected[0] as Models.Commit);
var source = e.Source as Control;
var item = source.FindAncestorOfType<ListBoxItem>();
if (item is { DataContext: Models.Commit commit })
histories.DoubleTapped(commit);
}
e.Handled = true;
}

View file

@ -109,7 +109,7 @@
<ItemsControl ItemsSource="{Binding Notifications}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="m:Notification">
<Border Margin="6" HorizontalAlignment="Stretch" VerticalAlignment="Top" Effect="drop-shadow(0 0 12 #A0000000)">
<Border Margin="6" HorizontalAlignment="Stretch" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #8F000000)">
<Border Padding="8" CornerRadius="6" Background="{DynamicResource Brush.Popup}">
<Grid RowDefinitions="26,Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Margin="8,0">

View file

@ -121,7 +121,7 @@
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Appearance}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.Appearance.Theme}"
HorizontalAlignment="Right"
@ -158,34 +158,43 @@
Text="{Binding MonospaceFontFamily, Mode=TwoWay}"/>
<TextBlock Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Text.Preference.Appearance.DefaultFontSize}"
Text="{DynamicResource Text.Preference.Appearance.FontSize}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<NumericUpDown Grid.Row="3" Grid.Column="1"
<Grid Grid.Row="3" Grid.Column="1" ColumnDefinitions="*,8,*">
<NumericUpDown Grid.Column="0"
Minimum="10" Maximum="18" Increment="0.5"
Height="28"
Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="3"
Value="{Binding DefaultFontSize, Mode=TwoWay}"/>
Value="{Binding DefaultFontSize, Mode=TwoWay}">
<NumericUpDown.InnerLeftContent>
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource Brush.Border1}">
<TextBlock Margin="4,0" Text="{DynamicResource Text.Preference.Appearance.FontSize.Default}"/>
</Border>
</NumericUpDown.InnerLeftContent>
</NumericUpDown>
<NumericUpDown Grid.Column="2"
Minimum="10" Maximum="18" Increment="0.5"
Height="28"
Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="3"
Value="{Binding EditorFontSize, Mode=TwoWay}">
<NumericUpDown.InnerLeftContent>
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource Brush.Border1}">
<TextBlock Margin="4,0" Text="{DynamicResource Text.Preference.Appearance.FontSize.Editor}"/>
</Border>
</NumericUpDown.InnerLeftContent>
</NumericUpDown>
</Grid>
<TextBlock Grid.Row="4" Grid.Column="0"
Text="{DynamicResource Text.Preference.Appearance.EditorFontSize}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<NumericUpDown Grid.Row="4" Grid.Column="1"
Minimum="10" Maximum="18" Increment="0.5"
Height="28"
Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="3"
Value="{Binding EditorFontSize, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="0"
Text="{DynamicResource Text.Preference.Appearance.ThemeOverrides}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<TextBox Grid.Row="5" Grid.Column="1"
<TextBox Grid.Row="4" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding ThemeOverrides, Mode=TwoWay}">
@ -196,16 +205,16 @@
</TextBox.InnerRightContent>
</TextBox>
<CheckBox Grid.Row="6" Grid.Column="1"
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Preference.Appearance.OnlyUseMonoFontInEditor}"
IsChecked="{Binding OnlyUseMonoFontInEditor, Mode=TwoWay}"/>
<CheckBox Grid.Row="7" Grid.Column="1"
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.Appearance.UseFixedTabWidth}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Mode=TwoWay}"/>
<CheckBox Grid.Row="8" Grid.Column="1"
<CheckBox Grid.Row="7" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.Appearance.UseNativeWindowFrame}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSystemWindowFrame, Mode=OneTime}"

View file

@ -256,7 +256,7 @@
<ListBox Grid.Row="7"
x:Name="SubmoduleList"
Height="0"
Margin="8,0,4,0"
Margin="12,0,4,0"
Classes="repo_left_content_list"
ItemsSource="{Binding VisibleSubmodules}"
SelectionMode="Single"
@ -312,7 +312,7 @@
<ListBox Grid.Row="9"
x:Name="WorktreeList"
Height="0"
Margin="8,0,4,0"
Margin="12,0,4,0"
Classes="repo_left_content_list"
ItemsSource="{Binding Worktrees}"
SelectionMode="Single"
@ -524,7 +524,7 @@
<!-- Right -->
<Grid Grid.Column="2" RowDefinitions="Auto,Auto,*">
<Grid Grid.Row="0" Height="28" ColumnDefinitions="*,Auto,Auto,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}">
<Grid Grid.Row="0" Height="28" ColumnDefinitions="*,Auto,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentControl Grid.Column="0" Margin="8,0" Content="{Binding InProgressContext}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:CherryPickInProgress">
@ -557,14 +557,6 @@
</Button.IsVisible>
</Button>
<Button Grid.Column="2"
Classes="flat primary"
FontWeight="Regular"
BorderThickness="0"
Content="{DynamicResource Text.Repository.Continue}"
Padding="8,0" Margin="4,0"
Command="{Binding ContinueMerge}"
IsVisible="{Binding !HasUnsolvedConflicts}"/>
<Button Grid.Column="3"
Classes="flat"
FontWeight="Regular"
BorderThickness="0"
@ -577,14 +569,25 @@
<Border.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="SelectedViewIndex" Converter="{x:Static c:IntConverters.IsZero}"/>
<Binding Path="Settings.Filters.Count" Converter="{x:Static c:IntConverters.IsGreaterThanZero}"/>
<Binding Path="Settings.HistoriesFilters.Count" Converter="{x:Static c:IntConverters.IsGreaterThanZero}"/>
</MultiBinding>
</Border.IsVisible>
<Grid Height="28" ColumnDefinitions="Auto,*,Auto">
<TextBlock Grid.Column="0" Margin="8,0,0,0" Classes="table_header" Text="{DynamicResource Text.Repository.FilterCommitPrefix}"/>
<ItemsControl Grid.Column="1" Margin="8,0,0,0" ItemsSource="{Binding Settings.Filters}">
<Path Grid.Column="0"
Margin="8,0,0,0"
Width="12" Height="12"
Data="{StaticResource Icons.Filter}"
Fill="{DynamicResource Brush.FG2}"
IsVisible="{Binding HistoriesFilterMode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Included}}"/>
<Path Grid.Column="0"
Margin="8,0,0,0"
Width="12" Height="12"
Data="{StaticResource Icons.EyeClose}"
Fill="{DynamicResource Brush.FG2}"
IsVisible="{Binding HistoriesFilterMode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.Excluded}}"/>
<ItemsControl Grid.Column="1" Margin="8,0,0,0" ItemsSource="{Binding Settings.HistoriesFilters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
@ -592,16 +595,24 @@
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Height="20" Margin="0,0,6,0" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" CornerRadius="12">
<TextBlock Classes="primary" Text="{Binding Converter={x:Static c:StringConverters.TrimRefsPrefix}}" Margin="8,0"/>
<DataTemplate DataType="m:Filter">
<Border Height="20"
Margin="0,0,6,0"
CornerRadius="12"
BorderThickness="1"
BorderBrush="{Binding Mode, Converter={x:Static c:FilterModeConverters.ToBorderBrush}}">
<StackPanel Orientation="Horizontal" Margin="8,0">
<Path Width="10" Height="10" Data="{StaticResource Icons.Branch}" IsVisible="{Binding IsBranch}"/>
<Path Width="10" Height="10" Data="{StaticResource Icons.Tag}" IsVisible="{Binding !IsBranch}"/>
<TextBlock Classes="primary" Text="{Binding Pattern, Converter={x:Static c:StringConverters.TrimRefsPrefix}}" Margin="4,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Grid.Column="2" Classes="icon_button" Command="{Binding ClearHistoriesFilter}">
<TextBlock Margin="16,0,8,0" Text="{DynamicResource Text.Repository.ClearAllCommitsFilter}" Foreground="{DynamicResource Brush.Accent}"/>
<Button Grid.Column="2" Classes="icon_button" Command="{Binding ClearHistoriesFilter}" ToolTip.Tip="{DynamicResource Text.Repository.ClearAllCommitsFilter}">
<Path Width="14" Height="14" Margin="16,0,8,0" Data="{StaticResource Icons.RemoveAll}"/>
</Button>
</Grid>
</Border>

View file

@ -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;
}

View file

@ -37,16 +37,19 @@
Margin="0,0,8,0"
Text="{DynamicResource Text.Reset.Mode}"/>
<ComboBox Grid.Row="2" Grid.Column="1"
x:Name="ResetMode"
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding Source={x:Static m:ResetMode.Supported}}"
SelectedItem="{Binding SelectedMode, Mode=TwoWay}">
SelectedItem="{Binding SelectedMode, Mode=TwoWay}"
KeyDown="OnResetModeKeyDown">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:ResetMode">
<Grid ColumnDefinitions="16,60,*">
<Ellipse Grid.Column="0" Width="12" Height="12" Fill="{Binding Color}"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="4,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding Desc}" FontSize="11" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="2,0,0,0"/>
<TextBlock Grid.Column="2" Text="{Binding Desc}" Margin="2,0,16,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
<TextBlock Grid.Column="3" Text="{Binding Key}" FontSize="11" FontWeight="Bold" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>

View file

@ -1,4 +1,6 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
@ -8,5 +10,29 @@ namespace SourceGit.Views
{
InitializeComponent();
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
ResetMode.Focus();
}
private void OnResetModeKeyDown(object sender, KeyEventArgs e)
{
if (sender is ComboBox comboBox)
{
var key = e.Key.ToString();
for (int i = 0; i < Models.ResetMode.Supported.Length; i++)
{
if (key.Equals(Models.ResetMode.Supported[i].Key, System.StringComparison.OrdinalIgnoreCase))
{
comboBox.SelectedIndex = i;
e.Handled = true;
return;
}
}
}
}
}
}

View file

@ -12,6 +12,10 @@
<Style Selector="ListBoxItem">
<Setter Property="CornerRadius" Value="4"/>
</Style>
<Style Selector="ListBoxItem:pointerover v|FilterModeSwitchButton">
<Setter Property="IsNoneVisible" Value="True"/>
</Style>
</UserControl.Styles>
<UserControl.DataTemplates>
@ -43,15 +47,14 @@
Classes="primary"
Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}"
Margin="8,0,0,0"/>
<ToggleButton Grid.Column="3"
Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
Click="OnToggleFilterClicked"
IsChecked="{Binding IsFiltered, Mode=TwoWay}"
IsVisible="{Binding !IsFolder}"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
<ContentControl Grid.Column="3" Content="{Binding Tag}">
<ContentControl.DataTemplates>
<DataTemplate DataType="m:Tag">
<v:FilterModeSwitchButton Mode="{Binding FilterMode}"/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
@ -60,32 +63,28 @@
<DataTemplate DataType="vm:TagCollectionAsList">
<ListBox Classes="repo_left_content_list"
Margin="8,0,0,0"
ItemsSource="{Binding Tags}"
SelectionMode="Single"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Tag">
<Grid ColumnDefinitions="Auto,*,Auto"
<Grid ColumnDefinitions="Auto,*,20"
Background="Transparent"
ContextRequested="OnRowContextRequested"
ToolTip.Tip="{Binding Message}">
<Path Grid.Column="0"
Width="10" Height="10"
Margin="8,0,0,0"
Width="12" Height="12"
Data="{StaticResource Icons.Tag}"/>
<TextBlock Grid.Column="1"
Classes="primary"
Text="{Binding Name}"
Margin="8,0,0,0"/>
Margin="8,0,0,0"
TextTrimming="CharacterEllipsis"/>
<ToggleButton Grid.Column="2"
Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
Click="OnToggleFilterClicked"
IsChecked="{Binding IsFiltered, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
<v:FilterModeSwitchButton Grid.Column="2" Mode="{Binding FilterMode}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

View file

@ -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<ViewModels.TagTreeNode> rows, List<ViewModels.TagTreeNode> nodes)
{
foreach (var node in nodes)

View file

@ -13,27 +13,39 @@
<ContentControl x:Name="Editor">
<ContentControl.DataTemplates>
<DataTemplate DataType="m:TextDiff">
<v:CombinedTextDiffPresenter FileName="{Binding File}"
Foreground="{DynamicResource Brush.FG1}"
LineBrush="{DynamicResource Brush.Border2}"
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
IndicatorForeground="{DynamicResource Brush.FG2}"
FontFamily="{DynamicResource Fonts.Monospace}"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=EditorFontSize}"
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Grid ColumnDefinitions="*,1,8">
<v:CombinedTextDiffPresenter Grid.Column="0"
x:Name="CombinedPresenter"
FileName="{Binding File}"
Foreground="{DynamicResource Brush.FG1}"
LineBrush="{DynamicResource Brush.Border2}"
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
IndicatorForeground="{DynamicResource Brush.FG2}"
FontFamily="{DynamicResource Fonts.Monospace}"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=EditorFontSize}"
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Rectangle Grid.Column="1" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
<v:TextDiffViewMinimap Grid.Column="2"
DisplayRange="{Binding #CombinedPresenter.DisplayRange}"
AddedLineBrush="{DynamicResource Brush.Diff.AddedBG}"
DeletedLineBrush="{DynamicResource Brush.Diff.DeletedBG}"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="vm:TwoSideTextDiff">
<Grid ColumnDefinitions="*,1,*">
<Grid ColumnDefinitions="*,1,*,1,12">
<v:SingleSideTextDiffPresenter Grid.Column="0"
x:Name="LeftSidePresenter"
IsOld="True"
FileName="{Binding File}"
Foreground="{DynamicResource Brush.FG1}"
@ -72,6 +84,13 @@
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Rectangle Grid.Column="3" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
<v:TextDiffViewMinimap Grid.Column="4"
DisplayRange="{Binding #LeftSidePresenter.DisplayRange}"
AddedLineBrush="{DynamicResource Brush.Diff.AddedBG}"
DeletedLineBrush="{DynamicResource Brush.Diff.DeletedBG}"/>
</Grid>
</DataTemplate>
</ContentControl.DataTemplates>

View file

@ -45,6 +45,18 @@ namespace SourceGit.Views
}
}
public record TextDiffViewRange
{
public int StartIdx { get; set; } = 0;
public int EndIdx { get; set; } = 0;
public TextDiffViewRange(int startIdx, int endIdx)
{
StartIdx = startIdx;
EndIdx = endIdx;
}
}
public class ThemedTextDiffPresenter : TextEditor
{
public class VerticalSeperatorMargin : AbstractMargin
@ -210,7 +222,6 @@ namespace SourceGit.Views
if (presenter == null)
return new Size(0, 0);
var maxLineNumber = presenter.GetMaxLineNumber();
var typeface = TextView.CreateTypeface();
var test = new FormattedText(
$"-",
@ -465,6 +476,15 @@ namespace SourceGit.Views
get => GetValue(SelectedChunkProperty);
set => SetValue(SelectedChunkProperty, value);
}
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
AvaloniaProperty.Register<ThemedTextDiffPresenter, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
public TextDiffViewRange DisplayRange
{
get => GetValue(DisplayRangeProperty);
set => SetValue(DisplayRangeProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextEditor);
@ -498,6 +518,78 @@ namespace SourceGit.Views
{
}
public void GotoPrevChange()
{
var firstLineIdx = DisplayRange.StartIdx;
if (firstLineIdx <= 1)
return;
var lines = GetLines();
var firstLineType = lines[firstLineIdx].Type;
var prevLineType = lines[firstLineIdx - 1].Type;
var isChangeFirstLine = firstLineType != Models.TextDiffLineType.Normal && firstLineType != Models.TextDiffLineType.Indicator;
var isChangePrevLine = prevLineType != Models.TextDiffLineType.Normal && prevLineType != Models.TextDiffLineType.Indicator;
if (isChangeFirstLine && isChangePrevLine)
{
for (var i = firstLineIdx - 2; i >= 0; i--)
{
var prevType = lines[i].Type;
if (prevType == Models.TextDiffLineType.Normal || prevType == Models.TextDiffLineType.Indicator)
{
ScrollToLine(i + 2);
return;
}
}
}
var findChange = false;
for (var i = firstLineIdx - 1; i >= 0; i--)
{
var prevType = lines[i].Type;
if (prevType == Models.TextDiffLineType.Normal || prevType == Models.TextDiffLineType.Indicator)
{
if (findChange)
{
ScrollToLine(i + 2);
return;
}
}
else if (!findChange)
{
findChange = true;
}
}
}
public void GotoNextChange()
{
var lines = GetLines();
var lastLineIdx = DisplayRange.EndIdx;
if (lastLineIdx >= lines.Count - 1)
return;
var lastLineType = lines[lastLineIdx].Type;
var findNormalLine = lastLineType == Models.TextDiffLineType.Normal || lastLineType == Models.TextDiffLineType.Indicator;
for (var idx = lastLineIdx + 1; idx < lines.Count; idx++)
{
var nextType = lines[idx].Type;
if (nextType == Models.TextDiffLineType.None ||
nextType == Models.TextDiffLineType.Added ||
nextType == Models.TextDiffLineType.Deleted)
{
if (findNormalLine)
{
ScrollToLine(idx + 1);
return;
}
}
else if (!findNormalLine)
{
findNormalLine = true;
}
}
}
public override void Render(DrawingContext context)
{
base.Render(context);
@ -524,6 +616,7 @@ namespace SourceGit.Views
TextArea.TextView.PointerEntered += OnTextViewPointerChanged;
TextArea.TextView.PointerMoved += OnTextViewPointerChanged;
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
UpdateTextMate();
}
@ -536,6 +629,7 @@ namespace SourceGit.Views
TextArea.TextView.PointerEntered -= OnTextViewPointerChanged;
TextArea.TextView.PointerMoved -= OnTextViewPointerChanged;
TextArea.TextView.PointerWheelChanged -= OnTextViewPointerWheelChanged;
TextArea.TextView.VisualLinesChanged -= OnTextViewVisualLinesChanged;
if (_textMate != null)
{
@ -643,6 +737,34 @@ namespace SourceGit.Views
}
}
private void OnTextViewVisualLinesChanged(object sender, EventArgs e)
{
if (!TextArea.TextView.VisualLinesValid)
{
SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(0, 0));
return;
}
var lines = GetLines();
var start = int.MaxValue;
var count = 0;
foreach (var line in TextArea.TextView.VisualLines)
{
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
continue;
var index = line.FirstDocumentLine.LineNumber - 1;
if (index >= lines.Count)
continue;
count++;
if (start > index)
start = index;
}
SetCurrentValue(DisplayRangeProperty, new TextDiffViewRange(start, start + count));
}
protected void TrySetChunk(TextDiffViewChunk chunk)
{
var old = SelectedChunk;
@ -950,12 +1072,8 @@ namespace SourceGit.Views
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
{
if (EnableChunkSelection && sender is ScrollViewer viewer)
{
var area = viewer.FindDescendantOfType<TextArea>();
if (!area.IsPointerOver)
TrySetChunk(null);
}
if (EnableChunkSelection && !TextArea.IsPointerOver)
TrySetChunk(null);
}
}
@ -968,6 +1086,12 @@ namespace SourceGit.Views
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
}
public void ForceSyncScrollOffset()
{
if (DataContext is ViewModels.TwoSideTextDiff diff)
diff.SyncScrollOffset = _scrollViewer.Offset;
}
public override List<Models.TextDiffLine> GetLines()
{
if (DataContext is ViewModels.TwoSideTextDiff diff)
@ -1171,12 +1295,8 @@ namespace SourceGit.Views
private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
{
if (EnableChunkSelection && sender is ScrollViewer viewer)
{
var area = viewer.FindDescendantOfType<TextArea>();
if (!area.IsPointerOver)
TrySetChunk(null);
}
if (EnableChunkSelection && !TextArea.IsPointerOver)
TrySetChunk(null);
}
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
@ -1193,7 +1313,125 @@ namespace SourceGit.Views
private ScrollViewer _scrollViewer = null;
}
public class TextDiffViewMinimap : Control
{
public static readonly StyledProperty<IBrush> AddedLineBrushProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(AddedLineBrush), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
public IBrush AddedLineBrush
{
get => GetValue(AddedLineBrushProperty);
set => SetValue(AddedLineBrushProperty, value);
}
public static readonly StyledProperty<IBrush> DeletedLineBrushProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, IBrush>(nameof(DeletedLineBrush), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
public IBrush DeletedLineBrush
{
get => GetValue(DeletedLineBrushProperty);
set => SetValue(DeletedLineBrushProperty, value);
}
public static readonly StyledProperty<TextDiffViewRange> DisplayRangeProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, TextDiffViewRange>(nameof(DisplayRange), new TextDiffViewRange(0, 0));
public TextDiffViewRange DisplayRange
{
get => GetValue(DisplayRangeProperty);
set => SetValue(DisplayRangeProperty, value);
}
public static readonly StyledProperty<Color> DisplayRangeColorProperty =
AvaloniaProperty.Register<TextDiffViewMinimap, Color>(nameof(DisplayRangeColor), Colors.RoyalBlue);
public Color DisplayRangeColor
{
get => GetValue(DisplayRangeColorProperty);
set => SetValue(DisplayRangeColorProperty, value);
}
static TextDiffViewMinimap()
{
AffectsRender<TextDiffViewMinimap>(
AddedLineBrushProperty,
DeletedLineBrushProperty,
DisplayRangeProperty,
DisplayRangeColorProperty);
}
public override void Render(DrawingContext context)
{
var total = 0;
if (DataContext is ViewModels.TwoSideTextDiff twoSideDiff)
{
var halfWidth = Bounds.Width * 0.5;
total = Math.Max(twoSideDiff.Old.Count, twoSideDiff.New.Count);
RenderSingleSide(context, twoSideDiff.Old, 0, halfWidth);
RenderSingleSide(context, twoSideDiff.New, halfWidth, halfWidth);
}
else if (DataContext is Models.TextDiff diff)
{
total = diff.Lines.Count;
RenderSingleSide(context, diff.Lines, 0, Bounds.Width);
}
var range = DisplayRange;
if (range.EndIdx == 0)
return;
var startY = range.StartIdx / (total * 1.0) * Bounds.Height;
var endY = range.EndIdx / (total * 1.0) * Bounds.Height;
var color = DisplayRangeColor;
var brush = new SolidColorBrush(color, 0.2);
var pen = new Pen(color.ToUInt32());
var rect = new Rect(0, startY, Bounds.Width, endY - startY);
context.DrawRectangle(brush, null, rect);
context.DrawLine(pen, rect.TopLeft, rect.TopRight);
context.DrawLine(pen, rect.BottomLeft, rect.BottomRight);
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
InvalidateVisual();
}
private void RenderSingleSide(DrawingContext context, List<Models.TextDiffLine> lines, double x, double width)
{
var total = lines.Count;
var lastLineType = Models.TextDiffLineType.Indicator;
var lastLineTypeStart = 0;
for (int i = 0; i < total; i++)
{
var line = lines[i];
if (line.Type != lastLineType)
{
RenderBlock(context, lastLineType, lastLineTypeStart, i - lastLineTypeStart, total, x, width);
lastLineType = line.Type;
lastLineTypeStart = i;
}
}
RenderBlock(context, lastLineType, lastLineTypeStart, total - lastLineTypeStart, total, x, width);
}
private void RenderBlock(DrawingContext context, Models.TextDiffLineType type, int start, int count, int total, double x, double width)
{
if (type == Models.TextDiffLineType.Added || type == Models.TextDiffLineType.Deleted)
{
var brush = type == Models.TextDiffLineType.Added ? AddedLineBrush : DeletedLineBrush;
var y = start / (total * 1.0) * Bounds.Height;
var h = count / (total * 1.0) * Bounds.Height;
context.DrawRectangle(brush, null, new Rect(x, y, width, h));
}
}
}
public partial class TextDiffView : UserControl
{
public static readonly StyledProperty<bool> UseSideBySideDiffProperty =
@ -1277,7 +1515,7 @@ namespace SourceGit.Views
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
RefreshContent(DataContext as Models.TextDiff, true);
RefreshContent(DataContext as Models.TextDiff);
}
protected override void OnPointerExited(PointerEventArgs e)

View file

@ -239,10 +239,21 @@
Margin="8,0,0,0"
HorizontalAlignment="Left"
IsChecked="{Binding UseAmend, Mode=TwoWay}"
IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNull}}"
Content="{DynamicResource Text.WorkingCopy.Amend}"/>
<v:LoadingIcon Grid.Column="5" Width="18" Height="18" IsVisible="{Binding IsCommitting}"/>
<Button Grid.Column="6"
Classes="flat primary"
Content="{DynamicResource Text.Repository.Continue}"
Height="28"
Margin="8,0,0,0"
Padding="8,0"
Command="{Binding ContinueMerge}"
IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}"
IsEnabled="{Binding !HasUnsolvedConflicts}"/>
<Button Grid.Column="6"
Classes="flat primary"
Content="{DynamicResource Text.WorkingCopy.Commit}"
@ -251,6 +262,7 @@
Padding="8,0"
Command="{Binding Commit}"
HotKey="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"
IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNull}}"
ToolTip.Placement="Top"
ToolTip.VerticalOffset="0">
<ToolTip.Tip>