Merge branch 'release/v2025.16'

This commit is contained in:
leo 2025-05-06 09:22:58 +08:00
commit a960e14368
No known key found for this signature in database
55 changed files with 478 additions and 153 deletions

View file

@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository
### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)
### ![de__DE](https://img.shields.io/badge/de__DE-95.19%25-yellow)
### ![de__DE](https://img.shields.io/badge/de__DE-95.07%25-yellow)
<details>
<summary>Missing keys in de_DE.axaml</summary>
@ -37,6 +37,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.Appearance.EditorTabWidth
- Text.Preferences.General.ShowTagsInGraph
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.Search.ByContent
- Text.Repository.ViewLogs
- Text.StashCM.SaveAsPatch
- Text.ViewLogs
@ -53,7 +54,7 @@ This document shows the translation status of each locale file in the repository
### ![es__ES](https://img.shields.io/badge/es__ES-%E2%88%9A-brightgreen)
### ![fr__FR](https://img.shields.io/badge/fr__FR-96.49%25-yellow)
### ![fr__FR](https://img.shields.io/badge/fr__FR-96.37%25-yellow)
<details>
<summary>Missing keys in fr_FR.axaml</summary>
@ -75,6 +76,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.Search.ByContent
- Text.Repository.ViewLogs
- Text.ViewLogs
- Text.ViewLogs.Clear
@ -88,7 +90,7 @@ This document shows the translation status of each locale file in the repository
</details>
### ![it__IT](https://img.shields.io/badge/it__IT-96.23%25-yellow)
### ![it__IT](https://img.shields.io/badge/it__IT-96.11%25-yellow)
<details>
<summary>Missing keys in it_IT.axaml</summary>
@ -112,6 +114,7 @@ This document shows the translation status of each locale file in the repository
- Text.CopyFullPath
- Text.Preferences.General.ShowTagsInGraph
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.Search.ByContent
- Text.Repository.ViewLogs
- Text.ViewLogs
- Text.ViewLogs.Clear
@ -125,7 +128,7 @@ This document shows the translation status of each locale file in the repository
</details>
### ![ja__JP](https://img.shields.io/badge/ja__JP-96.23%25-yellow)
### ![ja__JP](https://img.shields.io/badge/ja__JP-96.11%25-yellow)
<details>
<summary>Missing keys in ja_JP.axaml</summary>
@ -148,6 +151,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.FilterCommits
- Text.Repository.Search.ByContent
- Text.Repository.Tags.OrderByNameDes
- Text.Repository.ViewLogs
- Text.ViewLogs
@ -162,7 +166,7 @@ This document shows the translation status of each locale file in the repository
</details>
### ![pt__BR](https://img.shields.io/badge/pt__BR-87.79%25-yellow)
### ![pt__BR](https://img.shields.io/badge/pt__BR-87.68%25-yellow)
<details>
<summary>Missing keys in pt_BR.axaml</summary>
@ -235,6 +239,7 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.HistoriesOrder
- Text.Repository.Notifications.Clear
- Text.Repository.OnlyHighlightCurrentBranchInHistories
- Text.Repository.Search.ByContent
- Text.Repository.Skip
- Text.Repository.Tags.OrderByCreatorDate
- Text.Repository.Tags.OrderByNameAsc
@ -266,7 +271,7 @@ This document shows the translation status of each locale file in the repository
### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen)
### ![ta__IN](https://img.shields.io/badge/ta__IN-96.49%25-yellow)
### ![ta__IN](https://img.shields.io/badge/ta__IN-96.37%25-yellow)
<details>
<summary>Missing keys in ta_IN.axaml</summary>
@ -288,6 +293,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.Search.ByContent
- Text.Repository.ViewLogs
- Text.UpdateSubmodules.Target
- Text.ViewLogs
@ -301,7 +307,7 @@ This document shows the translation status of each locale file in the repository
</details>
### ![uk__UA](https://img.shields.io/badge/uk__UA-97.66%25-yellow)
### ![uk__UA](https://img.shields.io/badge/uk__UA-97.54%25-yellow)
<details>
<summary>Missing keys in uk_UA.axaml</summary>
@ -319,6 +325,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitMessageTextBox.SubjectCount
- Text.ConfigureWorkspace.Name
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Repository.Search.ByContent
- Text.Repository.ViewLogs
- Text.ViewLogs
- Text.ViewLogs.Clear

View file

@ -1 +1 @@
2025.15
2025.16

View file

@ -552,6 +552,7 @@ namespace SourceGit
_launcher = new ViewModels.Launcher(startupRepo);
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
#if !DISABLE_UPDATE_DETECTION
if (pref.ShouldCheck4UpdateOnStartup())

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = "--no-optional-locks status -uno --ignore-submodules=dirty --porcelain";
Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain";
}
public int Result()

View file

@ -105,7 +105,7 @@ namespace SourceGit.Commands
}
else if (line.StartsWith("-size ", StringComparison.Ordinal))
{
_result.LFSDiff.Old.Size = long.Parse(line.AsSpan().Slice(6));
_result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
}
}
else if (ch == '+')
@ -116,12 +116,12 @@ namespace SourceGit.Commands
}
else if (line.StartsWith("+size ", StringComparison.Ordinal))
{
_result.LFSDiff.New.Size = long.Parse(line.AsSpan().Slice(6));
_result.LFSDiff.New.Size = long.Parse(line.AsSpan(6));
}
}
else if (line.StartsWith(" size ", StringComparison.Ordinal))
{
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan().Slice(6));
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
}
return;
}

View file

@ -8,7 +8,14 @@ namespace SourceGit.Commands
{
var file = Path.Combine(repo, ".gitignore");
if (!File.Exists(file))
{
File.WriteAllLines(file, [pattern]);
return;
}
var org = File.ReadAllText(file);
if (!org.EndsWith('\n'))
File.AppendAllLines(file, ["", pattern]);
else
File.AppendAllLines(file, [pattern]);
}

View file

@ -26,11 +26,7 @@ namespace SourceGit.Commands
{
search += $"-i --committer=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByFile)
{
search += $"-- \"{filter}\"";
}
else
else if (method == Models.CommitSearchMethod.ByMessage)
{
var argsBuilder = new StringBuilder();
argsBuilder.Append(search);
@ -45,10 +41,18 @@ namespace SourceGit.Commands
search = argsBuilder.ToString();
}
else if (method == Models.CommitSearchMethod.ByFile)
{
search += $"-- \"{filter}\"";
}
else
{
search = $"-G\"{filter}\"";
}
WorkingDirectory = repo;
Context = repo;
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search;
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {search}";
_findFirstMerged = false;
}

View file

@ -40,7 +40,7 @@ namespace SourceGit.Commands
if (dateEndIdx == -1)
return;
var dateStr = line.AsSpan().Slice(0, dateEndIdx);
var dateStr = line.AsSpan(0, dateEndIdx);
if (double.TryParse(dateStr, out var date))
statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using Avalonia.Data.Converters;
@ -22,7 +22,7 @@ namespace SourceGit.Converters
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (v.StartsWith(home, StringComparison.Ordinal))
return "~" + v.Substring(prefixLen);
return $"~{v.AsSpan(prefixLen)}";
return v;
});

View file

@ -196,7 +196,7 @@ namespace SourceGit.Models
private string GetEmailHash(string email)
{
var lowered = email.ToLower(CultureInfo.CurrentCulture).Trim();
var hash = MD5.HashData(Encoding.Default.GetBytes(lowered).AsSpan());
var hash = MD5.HashData(Encoding.Default.GetBytes(lowered));
var builder = new StringBuilder(hash.Length * 2);
foreach (var c in hash)
builder.Append(c.ToString("x2"));

View file

@ -14,8 +14,8 @@ namespace SourceGit.Models
public enum BisectCommitFlag
{
None = 0,
Good = 1,
Bad = 2,
Good = 1 << 0,
Bad = 1 << 1,
}
public class Bisect

View file

@ -13,6 +13,7 @@ namespace SourceGit.Models
ByCommitter,
ByMessage,
ByFile,
ByContent,
}
public class Commit

View file

@ -12,7 +12,7 @@ namespace SourceGit.Models
{
get;
set;
} = false;
} = true;
public Change WorkingCopyChange => _workingCopyChange;
public bool IsUnstaged => _isUnstaged;

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
@ -147,7 +147,7 @@ namespace SourceGit.Models
public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output)
{
var isTracked = !string.IsNullOrEmpty(fileBlobGuid);
var fileGuid = isTracked ? fileBlobGuid.Substring(0, 8) : "00000000";
var fileGuid = isTracked ? fileBlobGuid : "00000000";
var builder = new StringBuilder();
builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n');

12
src/Models/DirtyState.cs Normal file
View file

@ -0,0 +1,12 @@
using System;
namespace SourceGit.Models
{
[Flags]
public enum DirtyState
{
None = 0,
HasLocalChanges = 1 << 0,
HasPendingPullOrPush = 1 << 1,
}
}

View file

@ -43,6 +43,7 @@ namespace SourceGit.Models
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\""),
new ExternalMerger(10, "plastic_merge", "Plastic SCM", "mergetool.exe", "-s=\"$REMOTE\" -b=\"$BASE\" -d=\"$LOCAL\" -r=\"$MERGED\" --automatic", "-s=\"$LOCAL\" -d=\"$REMOTE\""),
new ExternalMerger(11, "meld", "Meld", "Meld.exe", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsMacOS())

View file

@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models
{
@ -22,12 +23,12 @@ namespace SourceGit.Models
get
{
if (IsDetached)
return $"deteched HEAD at {Head.Substring(10)}";
return $"deteched HEAD at {Head.AsSpan(10)}";
if (Branch.StartsWith("refs/heads/", System.StringComparison.Ordinal))
if (Branch.StartsWith("refs/heads/", StringComparison.Ordinal))
return Branch.Substring(11);
if (Branch.StartsWith("refs/remotes/", System.StringComparison.Ordinal))
if (Branch.StartsWith("refs/remotes/", StringComparison.Ordinal))
return Branch.Substring(13);
return Branch;

View file

@ -236,7 +236,7 @@
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">ALT</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Kopieren</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Dateimodus geändert</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignoriere Leerzeichenänderungen und EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignoriere Leerzeichenänderungen</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJEKT ÄNDERUNG</x:String>
<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>

View file

@ -253,7 +253,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copy</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">File Mode Changed</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">First Difference</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignore Whitespace Change and EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignore All Whitespace Changes</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Last Difference</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJECT CHANGE</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Next Difference</x:String>
@ -605,6 +605,7 @@
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Search Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Author</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByContent" xml:space="preserve">Content</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">File</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>

View file

@ -257,7 +257,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copiar</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modo de Archivo Cambiado</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Primera Diferencia</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar Cambio de Espacios en Blanco y EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar Cambio de Espacios en Blanco</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Última Diferencia</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">CAMBIO DE OBJETO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Siguiente Diferencia</x:String>
@ -609,6 +609,7 @@
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Buscar Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Autor</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByContent" xml:space="preserve">Contenido</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Archivo</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Mensaje</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>

View file

@ -241,7 +241,7 @@
<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.First" xml:space="preserve">Première différence</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorer les changements d'espaces et EOL</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.Last" xml:space="preserve">Dernière différence</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>

View file

@ -240,7 +240,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copia</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modalità File Modificata</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Prima differenza</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignora Modifiche agli Spazi e EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignora Modifiche agli Spazi</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Ultima differenza</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">MODIFICA OGGETTO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Differenza Successiva</x:String>

View file

@ -241,7 +241,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">コピー</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">ファイルモードが変更されました</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">先頭の差分</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">空白の変更とEOLを無視</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">空白の変更を無視</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最後の差分</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFSオブジェクトの変更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">次の差分</x:String>

View file

@ -217,7 +217,7 @@
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">ANTIGO</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copiar</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modo de Arquivo Alterado</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar mudanças de espaço em branco e EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar mudanças de espaço em branco</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">MUDANÇA DE OBJETO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Próxima Diferença</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL</x:String>

View file

@ -59,7 +59,7 @@
<x:String x:Key="Text.BranchCM.DiscardAll" xml:space="preserve">Отклонить все изменения.</x:String>
<x:String x:Key="Text.BranchCM.FastForward" xml:space="preserve">Перемотать вперёд к ${0}$</x:String>
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Извлечь ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Поток Git - Завершение ${0}$</x:String>
<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.MergeMultiBranches" xml:space="preserve">Влить {0} выделенных веток в текущую</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Загрузить ${0}$</x:String>
@ -195,8 +195,8 @@
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Восстанавливать вкладки при запуске</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">ПРОДОЛЖИТЬ</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">Подготовить все и зафиксировать ревизию</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить все, затем зафиксировать ревизию?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">Сформировать всё и зафиксировать ревизию</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить всё, затем зафиксировать ревизию?</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Общепринятый помощник по ревизии</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Кардинальные изменения:</x:String>
<x:String x:Key="Text.ConventionalCommit.ClosedIssue" xml:space="preserve">Закрытая тема:</x:String>
@ -251,21 +251,21 @@
<x:String x:Key="Text.DeleteTag" xml:space="preserve">Удалить метку</x:String>
<x:String x:Key="Text.DeleteTag.Tag" xml:space="preserve">Метка:</x:String>
<x:String x:Key="Text.DeleteTag.WithRemote" xml:space="preserve">Удалить из внешнего репозитория</x:String>
<x:String x:Key="Text.Diff.Binary" xml:space="preserve">РАЗНИЦА БИНАРНИКОВ</x:String>
<x:String x:Key="Text.Diff.Binary" xml:space="preserve">СРАВНЕНИЕ БИНАРНИКОВ</x:String>
<x:String x:Key="Text.Diff.Binary.New" xml:space="preserve">НОВЫЙ</x:String>
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">СТАРЫЙ</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Копировать</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Режим файла изменён</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Первое различие</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Игнорировать изменение пробелов и EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Последнее различие</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Первое сравнение</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Игнорировать изменения пробелов</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Последнее сравнение</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">ИЗМЕНЕНИЕ ОБЪЕКТА LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Следующее различие</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Следующее сравнение</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">НИКАКИХ ИЗМЕНЕНИЙ ИЛИ МЕНЯЕТСЯ ТОЛЬКО EOL</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Предыдущее различие</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Предыдущее сравнение</x:String>
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Сохранить как заплатку</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Показывать скрытые символы</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Различие рядом</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Сравнение рядом</x:String>
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">ПОДМОДУЛЬ</x:String>
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">НОВЫЙ</x:String>
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Обмен</x:String>
@ -305,41 +305,41 @@
<x:String x:Key="Text.FileCM.OpenWithExternalMerger" xml:space="preserve">Открыть расширенный инструмент слияния</x:String>
<x:String x:Key="Text.FileCM.ResolveUsing" xml:space="preserve">Взять версию ${0}$</x:String>
<x:String x:Key="Text.FileCM.SaveAsPatch" xml:space="preserve">Сохранить как файл заплатки...</x:String>
<x:String x:Key="Text.FileCM.Stage" xml:space="preserve">Подготовить</x:String>
<x:String x:Key="Text.FileCM.StageMulti" xml:space="preserve">Подготовленные {0} файлы</x:String>
<x:String x:Key="Text.FileCM.StageSelectedLines" xml:space="preserve">Подготовленные изменения в выбранной(ых) строке(ах)</x:String>
<x:String x:Key="Text.FileCM.Stage" xml:space="preserve">Сформировать</x:String>
<x:String x:Key="Text.FileCM.StageMulti" xml:space="preserve">Сформированные {0} файлы</x:String>
<x:String x:Key="Text.FileCM.StageSelectedLines" xml:space="preserve">Сформированные изменения в выбранной(ых) строке(ах)</x:String>
<x:String x:Key="Text.FileCM.Stash" xml:space="preserve">Отложить...</x:String>
<x:String x:Key="Text.FileCM.StashMulti" xml:space="preserve">Отложить {0} файлов...</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Снять подготовленный</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Неподготовленные {0} файлы</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Неподготовленные изменения в выбранной(ых) строке(ах)</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Расформировать</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Несформированные {0} файлы</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Несформированные изменения в выбранной(ых) строке(ах)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">Использовать мой (checkout --ours)</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Использовать их (checkout --theirs)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">История файлов</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">ИЗМЕНИТЬ</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">СОДЕРЖИМОЕ</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-поток</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>
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Свойство префикса:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">ПОТОК - Свойства завершения</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">ПОТОК - Закончить исправление</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">ПОТОК - Завершить выпуск</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">ПРОЦЕСС - Свойства завершения</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">ПРОЦЕСС - Закончить исправление</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">ПРОЦЕСС - Завершить выпуск</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Исправление:</x:String>
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Префикс исправлений:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Создать Git-поток</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Создать Git-процесс</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Держать ветку</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Производственная ветка:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Выпуск:</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Префикс выпуска:</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Свойство запуска...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">ПОТОК - Свойство запуска</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">ПРОЦЕСС - Свойство запуска</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Запуск исправлений...</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">ПОТОК - Запуск исправлений</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">ПРОЦЕСС - Запуск исправлений</x:String>
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Ввести имя</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Запуск выпуска...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">ПОТОК - Запуск выпуска</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">ПРОЦЕСС - Запуск выпуска</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Префикс метки версии:</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">Добавить шаблон отслеживания...</x:String>
@ -388,9 +388,9 @@
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Создать новую вкладку</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Открыть диалоговое окно настроек</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">РЕПОЗИТОРИЙ</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Зафиксировать подготовленные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Зафиксировать и выложить подготовленные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Подготовить все изменения и зафиксировать</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Зафиксировать сформированные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Зафиксировать и выложить сформированные изменения</x:String>
<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>
@ -399,7 +399,7 @@
<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.Refresh" 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.StageOrUnstageSelected" xml:space="preserve">Сформированные/Несформированные выбранные изменения</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Переключить на «Изменения»</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Переключить на «Истории»</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Переключить на «Отложенные»</x:String>
@ -409,8 +409,8 @@
<x:String x:Key="Text.Hotkeys.TextEditor.GotoPrevMatch" xml:space="preserve">Найти предыдущее совпадение</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.Search" xml:space="preserve">Открыть панель поиска</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Отклонить</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Подготовить</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Снять из подготовленных</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Сформировать</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Расформировать</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Создать репозиторий</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Путь:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Выполняется частичный перенос ревизий (cherry-pick).</x:String>
@ -463,9 +463,9 @@
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Вчера</x:String>
<x:String x:Key="Text.Preferences" xml:space="preserve">Параметры</x:String>
<x:String x:Key="Text.Preferences.AI" xml:space="preserve">ОТКРЫТЬ ИИ</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Запрос на анализ различий</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Запрос на анализ сравнения</x:String>
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Ключ API</x:String>
<x:String x:Key="Text.Preferences.AI.GenerateSubjectPrompt" xml:space="preserve">Произвести запрос на тему</x:String>
<x:String x:Key="Text.Preferences.AI.GenerateSubjectPrompt" xml:space="preserve">Создать запрос на тему</x:String>
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Модель</x:String>
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Имя:</x:String>
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Сервер</x:String>
@ -482,9 +482,9 @@
<x:String x:Key="Text.Preferences.Appearance.ThemeOverrides" xml:space="preserve">Переопределение темы</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseFixedTabWidth" xml:space="preserve">Использовать фиксированную ширину табуляции в строке заголовка.</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseNativeWindowFrame" xml:space="preserve">Использовать системное окно</x:String>
<x:String x:Key="Text.Preferences.DiffMerge" xml:space="preserve">ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ</x:String>
<x:String x:Key="Text.Preferences.DiffMerge" xml:space="preserve">ИНСТРУМЕНТ СРАВНЕНИЙ/СЛИЯНИЯ</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path" xml:space="preserve">Путь установки</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path.Placeholder" xml:space="preserve">Введите путь для инструмента различия/слияния</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path.Placeholder" xml:space="preserve">Введите путь для инструмента сравнения/слияния</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Type" xml:space="preserve">Инструмент</x:String>
<x:String x:Key="Text.Preferences.General" xml:space="preserve">ОСНОВНЫЕ</x:String>
<x:String x:Key="Text.Preferences.General.Check4UpdatesOnStartup" xml:space="preserve">Проверить обновления при старте</x:String>
@ -501,7 +501,7 @@
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Электроная почта пользователя</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Общая электроная почта пользователя git</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Разрешить (--prune) при скачивании</x:String>
<x:String x:Key="Text.Preferences.Git.IgnoreCRAtEOLInDiff" xml:space="preserve">Разрешить (--ignore-cr-at-eol) в различии</x:String>
<x:String x:Key="Text.Preferences.Git.IgnoreCRAtEOLInDiff" xml:space="preserve">Разрешить (--ignore-cr-at-eol) в сравнении</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Для работы программы требуется версия Git (&gt;= 2.23.0)</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Путь установки</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Разрешить верификацию HTTP SSL</x:String>
@ -609,6 +609,7 @@
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Поиск ревизии</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Автор</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Ревизор</x:String>
<x:String x:Key="Text.Repository.Search.ByContent" xml:space="preserve">Содержимое</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Файл</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Сообщение</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
@ -673,8 +674,8 @@
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Хранить отложенные файлы</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Сообщение:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Имя тайника (необязательно)</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Только подготовленные изменения</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Подготовленные так и неподготовленные изменения выбранных файлов будут сохранены!!!</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Только сформированные изменения</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Сформированные так и несформированные изменения выбранных файлов будут сохранены!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Отложить локальные изменения</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Принять</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Отбросить</x:String>
@ -739,14 +740,14 @@
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">Игнорировать файлы в том же каталоге</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">Игнорировать только эти файлы</x:String>
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">Изменить</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Теперь вы можете подготовить этот файл.</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Теперь вы можете сформировать этот файл.</x:String>
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">ЗАФИКСИРОВАТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">ЗАФИКСИРОВАТЬ и ОТПРАВИТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Шаблон/Истории</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Запустить событие щелчка</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Зафиксировать (Редактировать)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Подготовить все изменения и зафиксировать</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter">Вы подготовили {0} файл(ов), но отображается только {1} файл(ов) ({2} файл(ов) отфильтровано). Вы хотите продолжить?</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Сформировать все изменения и зафиксировать</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter">Вы сформировали {0} файл(ов), но отображается только {1} файл(ов) ({2} файл(ов) отфильтровано). Вы хотите продолжить?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">ОБНАРУЖЕНЫ КОНФЛИКТЫ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">ОТКРЫТЬ ВНЕШНИЙ ИНСТРУМЕНТ СЛИЯНИЯ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts" xml:space="preserve">ОТКРЫТЬ ВСЕ КОНФЛИКТЫ ВО ВНЕШНЕМ ИНСТРУМЕНТЕ СЛИЯНИЯ</x:String>
@ -758,12 +759,12 @@
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" xml:space="preserve">НЕТ ШАБЛОНОВ РЕВИЗИИ</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Щёлкните правой кнопкой мыши выбранный файл(ы) и разрешите конфликты.</x:String>
<x:String x:Key="Text.WorkingCopy.SignOff" xml:space="preserve">Завершение работы</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">ПОДГОТОВЛЕННЫЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">СНЯТЬ ПОДГОТОВЛЕННЫЙ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">СНЯТЬ ВСЕ ПОДГОТОВЛЕННЫЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">НЕПОДГОТОВЛЕННЫЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">ПОДГОТОВИТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">ВСЕ ПОДГОТОВИТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">СФОРМИРОВАННЫЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">РАСФОРМИРОВАТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">РАСФОРМИРОВАТЬ ВСЁ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">НЕСФОРМИРОВАННЫЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">СФОРМИРОВАТЬ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">СФОРМИРОВАТЬ ВСЁ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">ОТКРЫТЬ СПИСОК НЕОТСЛЕЖИВАЕМЫХ ФАЙЛОВ</x:String>
<x:String x:Key="Text.WorkingCopy.UseCommitTemplate" xml:space="preserve">Шаблон: ${0}$</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">РАБОЧЕЕ ПРОСТРАНСТВО: </x:String>

View file

@ -241,7 +241,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">நகல்</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">கோப்பு முறை மாற்றப்பட்டது</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">முதல் வேறுபாடு</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">வெள்ளைவெளி மாற்றத்தை மற்றும் EOL புறக்கணி</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">வெள்ளைவெளி மாற்றத்தை புறக்கணி</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">கடைசி வேறுபாடு</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">பெகோஅ பொருள் மாற்றம்</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">அடுத்த வேறுபாடு</x:String>

View file

@ -257,7 +257,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">复制</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">文件权限已变化</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">首个差异</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符号变化和EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符号变化</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最后一个差异</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS对象变更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">下一个差异</x:String>
@ -609,6 +609,7 @@
<x:String x:Key="Text.Repository.Search" xml:space="preserve">查找提交</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.Repository.Search.ByContent" xml:space="preserve">变更内容</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">文件</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">提交信息</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">提交指纹</x:String>

View file

@ -257,7 +257,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">複製</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">檔案權限已變更</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">第一個差異</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符號變化和 EOL</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符號變化</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最後一個差異</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS 物件變更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">下一個差異</x:String>
@ -609,6 +609,7 @@
<x:String x:Key="Text.Repository.Search" xml:space="preserve">搜尋提交</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.Repository.Search.ByContent" xml:space="preserve">變更內容</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">檔案</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">提交訊息</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">提交編號</x:String>

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
@ -31,7 +32,7 @@ namespace SourceGit.ViewModels
{
_repo = repo;
_revision = commit.SHA;
_saveFile = $"archive-{commit.SHA.Substring(0, 10)}.zip";
_saveFile = $"archive-{commit.SHA.AsSpan(0, 10)}.zip";
BasedOn = commit;
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Threading;
@ -30,7 +31,7 @@ namespace SourceGit.ViewModels
{
_repo = repo;
Title = $"{file} @ {revision.Substring(0, 10)}";
Title = $"{file} @ {revision.AsSpan(0, 10)}";
Task.Run(() =>
{
var result = new Commands.Blame(repo, file, revision).Result();

View file

@ -62,6 +62,8 @@ namespace SourceGit.ViewModels
CallUIThread(() =>
{
ProgressDescription = "Waiting for branch updated...";
var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch);
if (b != null && _repo.HistoriesFilterMode == Models.FilterMode.Included)
_repo.SetBranchFilterMode(b, Models.FilterMode.Included, true, false);
@ -70,6 +72,7 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(true);
});
Task.Delay(400).Wait();
return rs;
});
}

View file

@ -13,15 +13,16 @@ namespace SourceGit.ViewModels
private set;
} = string.Empty;
public DateTime Time
public DateTime StartTime
{
get;
} = DateTime.Now;
public string TimeStr
public DateTime EndTime
{
get => Time.ToString("T");
}
get;
private set;
} = DateTime.Now;
public bool IsComplete
{
@ -69,6 +70,8 @@ namespace SourceGit.ViewModels
_builder.Clear();
_builder = null;
EndTime = DateTime.Now;
OnPropertyChanged(nameof(IsComplete));
if (_onNewLineReceived != null)

View file

@ -642,10 +642,37 @@ namespace SourceGit.ViewModels
rule.Matches(inlines, message);
}
var matches = REG_SHA_FORMAT().Matches(message);
for (int i = 0; i < matches.Count; i++)
var urlMatches = REG_URL_FORMAT().Matches(message);
for (int i = 0; i < urlMatches.Count; i++)
{
var match = matches[i];
var match = urlMatches[i];
if (!match.Success)
continue;
var start = match.Index;
var len = match.Length;
var intersect = false;
foreach (var link in inlines)
{
if (link.Intersect(start, len))
{
intersect = true;
break;
}
}
if (intersect)
continue;
var url = message.Substring(start, len);
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
inlines.Add(new Models.InlineElement(Models.InlineElementType.Link, start, len, url));
}
var shaMatches = REG_SHA_FORMAT().Matches(message);
for (int i = 0; i < shaMatches.Count; i++)
{
var match = shaMatches[i];
if (!match.Success)
continue;
@ -840,6 +867,9 @@ namespace SourceGit.ViewModels
RevisionFileSearchSuggestion = suggestion;
}
[GeneratedRegex(@"\b(https?://|ftp://)[\w\d\._/\-~%@()+:?&=#!]*[\w\d/]")]
private static partial Regex REG_URL_FORMAT();
[GeneratedRegex(@"\b([0-9a-fA-F]{6,40})\b")]
private static partial Regex REG_SHA_FORMAT();

View file

@ -9,7 +9,6 @@ namespace SourceGit.ViewModels
public AvaloniaList<Workspace> Workspaces
{
get;
private set;
}
public Workspace Selected
@ -51,6 +50,36 @@ namespace SourceGit.ViewModels
Workspaces.Remove(_selected);
}
public void MoveSelectedUp()
{
if (_selected == null)
return;
var idx = Workspaces.IndexOf(_selected);
if (idx == 0)
return;
Workspaces.Move(idx - 1, idx);
Preferences.Instance.Workspaces.RemoveAt(idx);
Preferences.Instance.Workspaces.Insert(idx - 1, _selected);
}
public void MoveSelectedDown()
{
if (_selected == null)
return;
var idx = Workspaces.IndexOf(_selected);
if (idx == Workspaces.Count - 1)
return;
Workspaces.Move(idx + 1, idx);
Preferences.Instance.Workspaces.RemoveAt(idx);
Preferences.Instance.Workspaces.Insert(idx + 1, _selected);
}
private Workspace _selected = null;
private bool _canDeleteSelected = false;
}

View file

@ -150,6 +150,12 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(true);
});
if (CheckoutAfterCreated)
{
CallUIThread(() => ProgressDescription = "Waiting for branch updated...");
Task.Delay(400).Wait();
}
return true;
});
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using Avalonia.Collections;
@ -584,7 +584,7 @@ namespace SourceGit.ViewModels
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (path.StartsWith(home, StringComparison.Ordinal))
path = "~" + path.Substring(prefixLen);
path = $"~{path.AsSpan(prefixLen)}";
}
Title = $"[{workspace}] {name} ({path})";

View file

@ -1,5 +1,8 @@
using System;
using Avalonia.Collections;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
@ -18,6 +21,12 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _data, value);
}
public IBrush DirtyBrush
{
get => _dirtyBrush;
private set => SetProperty(ref _dirtyBrush, value);
}
public Popup Popup
{
get => _popup;
@ -56,6 +65,26 @@ namespace SourceGit.ViewModels
App.CopyText(_node.Id);
}
public void ChangeDirtyState(Models.DirtyState flag, bool remove)
{
if (remove)
{
if (_dirtyState.HasFlag(flag))
_dirtyState -= flag;
}
else
{
_dirtyState |= flag;
}
if (_dirtyState.HasFlag(Models.DirtyState.HasLocalChanges))
DirtyBrush = Brushes.Gray;
else if (_dirtyState.HasFlag(Models.DirtyState.HasPendingPullOrPush))
DirtyBrush = Brushes.RoyalBlue;
else
DirtyBrush = null;
}
public bool CanCreatePopup()
{
return _popup == null || !_popup.InProgress;
@ -104,6 +133,8 @@ namespace SourceGit.ViewModels
private RepositoryNode _node = null;
private object _data = null;
private IBrush _dirtyBrush = null;
private Models.DirtyState _dirtyState = Models.DirtyState.None;
private Popup _popup = null;
}
}

View file

@ -58,12 +58,15 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
var isCurrent = Target.IsCurrent;
var oldName = Target.FullName;
var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, fixedName, log);
log.Complete();
CallUIThread(() =>
{
ProgressDescription = "Waiting for branch updated...";
if (succ)
{
foreach (var filter in _repo.Settings.HistoriesFilters)
@ -80,6 +83,10 @@ namespace SourceGit.ViewModels
_repo.MarkBranchesDirtyManually();
_repo.SetWatcherEnabled(true);
});
if (isCurrent)
Task.Delay(400).Wait();
return succ;
});
}

View file

@ -994,6 +994,8 @@ namespace SourceGit.ViewModels
if (_workingCopy != null)
_workingCopy.HasRemotes = remotes.Count > 0;
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !CurrentBranch.TrackStatus.IsVisible);
});
}
@ -1101,6 +1103,7 @@ namespace SourceGit.ViewModels
{
LocalChangesCount = changes.Count;
OnPropertyChanged(nameof(InProgressContext));
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0);
});
}

View file

@ -38,6 +38,12 @@ namespace SourceGit.ViewModels
IgnoreInaccessible = true,
});
// Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly.
var remain = 500 - (int)watch.Elapsed.TotalMilliseconds;
watch.Stop();
if (remain > 0)
Task.Delay(remain).Wait();
Dispatcher.UIThread.Invoke(() =>
{
var normalizedRoot = rootDir.FullName.Replace("\\", "/");
@ -61,12 +67,6 @@ namespace SourceGit.ViewModels
Welcome.Instance.Refresh();
});
// Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly.
var remain = 500 - (int)watch.Elapsed.TotalMilliseconds;
watch.Stop();
if (remain > 0)
Task.Delay(remain).Wait();
return true;
});
}

View file

@ -635,7 +635,7 @@ namespace SourceGit.ViewModels
}
else if (_inProgressContext is RevertInProgress revert)
{
useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)");
useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan(0, 10)} (revert)");
useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name);
}
else if (_inProgressContext is MergeInProgress merge)
@ -993,7 +993,7 @@ namespace SourceGit.ViewModels
}
else if (_inProgressContext is RevertInProgress revert)
{
useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)");
useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan(0, 10)} (revert)");
useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name);
}
else if (_inProgressContext is MergeInProgress merge)
@ -1417,7 +1417,7 @@ namespace SourceGit.ViewModels
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (gitTemplate.StartsWith(home, StringComparison.Ordinal))
friendlyName = $"~{gitTemplate.AsSpan().Slice(prefixLen)}";
friendlyName = $"~{gitTemplate.AsSpan(prefixLen)}";
}
var gitTemplateItem = new MenuItem();

View file

@ -39,12 +39,12 @@
<!-- AI response -->
<v:AIResponseView Grid.Row="1"
x:Name="TxtResponse"
Margin="8"
Height="320"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}"/>
Background="{DynamicResource Brush.Contents}"
Content="{Binding Text}"/>
<!-- Options -->
<Border Grid.Row="2" Margin="0,0,0,8">

View file

@ -15,6 +15,15 @@ namespace SourceGit.Views
{
public class AIResponseView : TextEditor
{
public static readonly StyledProperty<string> ContentProperty =
AvaloniaProperty.Register<AIResponseView, string>(nameof(Content), string.Empty);
public string Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextEditor);
public AIResponseView() : base(new TextArea(), new TextDocument())
@ -58,6 +67,16 @@ namespace SourceGit.Views
GC.Collect();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ContentProperty)
{
Text = Content;
}
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{
var selected = SelectedText;

View file

@ -0,0 +1,80 @@
using System;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
namespace SourceGit.Views
{
public class CommandLogTime : TextBlock
{
public static readonly StyledProperty<ViewModels.CommandLog> LogProperty =
AvaloniaProperty.Register<CommandLogTime, ViewModels.CommandLog>(nameof(Log), null);
public ViewModels.CommandLog Log
{
get => GetValue(LogProperty);
set => SetValue(LogProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextBlock);
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
StopTimer();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == LogProperty)
{
StopTimer();
if (change.NewValue is ViewModels.CommandLog log)
SetupCommandLog(log);
else
Text = string.Empty;
}
}
private void SetupCommandLog(ViewModels.CommandLog log)
{
Text = GetDisplayText(log);
if (log.IsComplete)
return;
_refreshTimer = new Timer(_ =>
{
Dispatcher.UIThread.Invoke(() =>
{
Text = GetDisplayText(log);
if (log.IsComplete)
StopTimer();
});
}, null, 0, 100);
}
private void StopTimer()
{
if (_refreshTimer is { })
{
_refreshTimer.Dispose();
_refreshTimer = null;
}
}
private string GetDisplayText(ViewModels.CommandLog log)
{
var endTime = log.IsComplete ? log.EndTime : DateTime.Now;
var duration = (endTime - log.StartTime).ToString(@"hh\:mm\:ss\.fff");
return $"{log.StartTime:T} ({duration})";
}
private Timer _refreshTimer = null;
}
}

View file

@ -178,6 +178,7 @@ namespace SourceGit.Views
foreach (var rule in rules)
rule.Matches(_elements, subject);
_elements.Sort((l, r) => l.Start - r.Start);
_needRebuildInlines = true;
InvalidateVisual();
}
@ -318,7 +319,6 @@ namespace SourceGit.Views
foreground);
_inlines.Add(new Inline(x, normal, null));
x += normal.WidthIncludingTrailingWhitespace;
}
}

View file

@ -79,19 +79,39 @@
<Rectangle Grid.Row="1" Height="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" Background="{DynamicResource Brush.ToolBar}">
<Button Classes="icon_button" Command="{Binding Add}">
<Grid Grid.Row="2" ColumnDefinitions="Auto,Auto,*,Auto,Auto" Background="{DynamicResource Brush.ToolBar}">
<Button Grid.Column="0"
Classes="icon_button"
Width="28" Height="28"
Command="{Binding Add}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Plus}"/>
</Button>
<Rectangle Width="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
<Button Classes="icon_button" Command="{Binding Delete}" IsEnabled="{Binding CanDeleteSelected}">
<Button Grid.Column="1"
Classes="icon_button"
Width="28" Height="28"
Command="{Binding Delete}"
IsEnabled="{Binding CanDeleteSelected}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Window.Minimize}"/>
</Button>
<Rectangle Width="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
</StackPanel>
<Button Grid.Column="3"
Classes="icon_button"
Width="28" Height="28"
Command="{Binding MoveSelectedUp}"
IsVisible="{Binding Selected, Converter={x:Static ObjectConverters.IsNotNull}}">
<Path Width="14" Height="14"
Margin="0,6,0,0"
Data="{StaticResource Icons.Up}"/>
</Button>
<Button Grid.Column="4"
Classes="icon_button"
Width="28" Height="28"
Command="{Binding MoveSelectedDown}"
IsVisible="{Binding Selected, Converter={x:Static ObjectConverters.IsNotNull}}">
<Path Width="14" Height="14"
Margin="0,6,0,0"
Data="{StaticResource Icons.Down}"/>
</Button>
</Grid>
</Grid>
</Border>

View file

@ -155,7 +155,6 @@
<ToggleButton Classes="line_path"
Width="28"
IsChecked="{Binding IgnoreWhitespace, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.IgnoreWhitespace}">
<Path Width="14" Height="14" Stretch="Uniform" Data="{StaticResource Icons.Whitespace}"/>
</ToggleButton>

View file

@ -24,7 +24,7 @@
</v:HistoriesLayout.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<Grid RowDefinitions="24,*" Grid.IsSharedSizeScope="True">
<Grid RowDefinitions="24,*" Grid.IsSharedSizeScope="True" ClipToBounds="True">
<!-- Headers -->
<Border Grid.Row="0"
Background="{DynamicResource Brush.Window}"
@ -32,11 +32,11 @@
BorderBrush="{DynamicResource Brush.Border0}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="{Binding #ThisControl.AuthorNameColumnWidth, Mode=TwoWay}" MinWidth="80"/>
<ColumnDefinition SharedSizeGroup="SHA"/>
<ColumnDefinition SharedSizeGroup="Time"/>
<ColumnDefinition SharedSizeGroup="SHA" MinWidth="100"/>
<ColumnDefinition SharedSizeGroup="Time" MinWidth="160"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Classes="table_header" Text="{DynamicResource Text.Histories.Header.GraphAndSubject}" HorizontalAlignment="Center"/>
@ -121,8 +121,8 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="{Binding #ThisControl.AuthorNameColumnWidth, Mode=OneWay}"/>
<ColumnDefinition SharedSizeGroup="SHA" Width="Auto" MinWidth="100"/>
<ColumnDefinition SharedSizeGroup="Time" Width="Auto" MinWidth="160"/>
<ColumnDefinition SharedSizeGroup="SHA" Width="Auto"/>
<ColumnDefinition SharedSizeGroup="Time" Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Subject & REFS -->

View file

@ -205,7 +205,7 @@ namespace SourceGit.Views
foreach (var item in selected)
{
if (item is Models.Commit commit)
builder.AppendLine($"{commit.SHA.Substring(0, 10)} - {commit.Subject}");
builder.AppendLine($"{commit.SHA.AsSpan(0, 10)} - {commit.Subject}");
}
App.CopyText(builder.ToString());

View file

@ -68,14 +68,29 @@
Data="{StaticResource Icons.Repositories}"
IsVisible="{Binding !Node.IsRepository}"
IsHitTestVisible="False"/>
<TextBlock Grid.Column="1"
Classes="primary"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
TextAlignment="Center"
Text="{Binding Node.Name}"
IsVisible="{Binding Node.IsRepository}"
IsHitTestVisible="False"/>
<Grid Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Center"
ColumnDefinitions="Auto,*"
IsHitTestVisible="False"
IsVisible="{Binding Node.IsRepository}">
<Ellipse Grid.Column="0"
Width="8" Height="8"
Margin="0,0,6,0"
VerticalAlignment="Center"
IsVisible="{Binding DirtyBrush, Converter={x:Static ObjectConverters.IsNotNull}}"
Fill="{Binding DirtyBrush}"/>
<TextBlock Grid.Column="1"
Classes="primary"
VerticalAlignment="Center"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
TextAlignment="Center"
Text="{Binding Node.Name}"
IsVisible="{Binding Node.IsRepository}"
IsHitTestVisible="False"/>
</Grid>
<TextBlock Grid.Column="1"
Classes="primary"
HorizontalAlignment="Stretch" VerticalAlignment="Center"

View file

@ -21,6 +21,15 @@ namespace SourceGit.Views
InitializeComponent();
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
_isUnloading = false;
if (IsVisible)
StartAnim();
}
protected override void OnUnloaded(RoutedEventArgs e)
{
_isUnloading = true;

View file

@ -495,6 +495,7 @@
<TextBlock Text="{DynamicResource Text.Repository.Search.ByCommitter}"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByMessage}"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByFile}"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByContent}"/>
</ComboBox.Items>
</ComboBox>

View file

@ -1,4 +1,5 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@ -33,5 +34,13 @@ namespace SourceGit.Views
e.Handled = true;
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled && e.Key == Key.Escape)
Close();
}
}
}

View file

@ -126,7 +126,7 @@ namespace SourceGit.Views
typeface,
presenter.FontSize,
presenter.Foreground);
context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - txt.Height * 0.5));
context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - (txt.Height * 0.5)));
}
}
}
@ -212,7 +212,7 @@ namespace SourceGit.Views
}
if (indicator != null)
context.DrawText(indicator, new Point(0, y - indicator.Height * 0.5));
context.DrawText(indicator, new Point(0, y - (indicator.Height * 0.5)));
}
}
}
@ -1047,7 +1047,8 @@ namespace SourceGit.Views
// The first selected line (partial selection)
if (i == startIdx && startPosition.Column > 1)
{
builder.AppendLine(line.Content.Substring(startPosition.Column - 1));
builder.Append(line.Content.AsSpan(startPosition.Column - 1));
builder.Append(Environment.NewLine);
continue;
}
@ -1061,7 +1062,14 @@ namespace SourceGit.Views
// For the last line (selection range is within original source)
if (i == endIdx)
{
builder.Append(endPosition.Column - 1 < line.Content.Length ? line.Content.Substring(0, endPosition.Column - 1) : line.Content);
if (endPosition.Column - 1 < line.Content.Length)
{
builder.Append(line.Content.AsSpan(0, endPosition.Column - 1));
}
else
{
builder.Append(line.Content);
}
break;
}
@ -1251,7 +1259,7 @@ namespace SourceGit.Views
{
if (line.Content.Length > 10000)
{
builder.Append(line.Content.Substring(0, 1000));
builder.Append(line.Content.AsSpan(0, 1000));
builder.Append($"...({line.Content.Length - 1000} character trimmed)");
}
else
@ -1741,7 +1749,7 @@ namespace SourceGit.Views
}
var top = chunk.Y + (chunk.Height >= 36 ? 16 : 4);
var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : v.Bounds.Width * 0.5f + 16;
var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : (v.Bounds.Width * 0.5f) + 16;
v.Popup.Margin = new Thickness(0, top, right, 0);
v.Popup.IsVisible = true;
});

View file

@ -12,7 +12,7 @@
Title="{DynamicResource Text.ViewLogs}"
Icon="/App.ico"
Width="800" Height="500"
CanResize="False"
CanResize="True"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,*,Auto">
<!-- TitleBar -->
@ -38,7 +38,13 @@
</Grid>
<!-- Body -->
<Grid Grid.Row="1" ColumnDefinitions="300,4,*" Margin="8">
<Grid Grid.Row="1" Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" MaxWidth="500" MinWidth="250"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"
Padding="4"
Background="{DynamicResource Brush.Contents}"
@ -71,7 +77,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="SearchCommitTimeColumn"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="TimeColumn"/>
</Grid.ColumnDefinitions>
<v:LoadingIcon Grid.Column="0"
Width="14" Height="14"
@ -85,12 +91,12 @@
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="2"
Classes="primary"
Margin="4,0"
Foreground="{DynamicResource Brush.FG2}"
Text="{Binding TimeStr}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
<v:CommandLogTime Grid.Column="2"
Classes="primary"
Margin="4,0"
Foreground="{DynamicResource Brush.FG2}"
Log="{Binding}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
@ -103,6 +109,12 @@
Fill="{DynamicResource Brush.FG2}"
IsVisible="{Binding Logs.Count, Converter={x:Static c:IntConverters.IsZero}}"/>
<GridSplitter Grid.Column="1"
MinWidth="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="0"/>
<Border Grid.Column="2"
BorderBrush="{DynamicResource Brush.Border2}"
BorderThickness="1"