Merge branch 'release/v8.31'

This commit is contained in:
leo 2024-09-23 09:30:12 +08:00
commit 718dd322cf
No known key found for this signature in database
50 changed files with 4375 additions and 266 deletions

View file

@ -7,7 +7,7 @@ Opensource Git GUI client.
* Supports Windows/macOS/Linux * Supports Windows/macOS/Linux
* Opensource/Free * Opensource/Free
* Fast * Fast
* English/Français/Deutsch/Português/简体中文/繁體中文 * English/Français/Deutsch/Português/Русский/简体中文/繁體中文
* Built-in light/dark themes * Built-in light/dark themes
* Customize theme * Customize theme
* Visual commit graph * Visual commit graph
@ -97,7 +97,7 @@ For `OpenAI`:
For other AI service: For other AI service:
* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions` * The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate`
* The `API Key` is optional that depends on the service * The `API Key` is optional that depends on the service
## External Tools ## External Tools
@ -111,6 +111,7 @@ This app supports open repository in external tools listed in the table below.
| VSCodium | YES | YES | YES | VSCODIUM | | VSCodium | YES | YES | YES | VSCODIUM |
| JetBrains Fleet | YES | YES | YES | FLEET | | JetBrains Fleet | YES | YES | YES | FLEET |
| Sublime Text | YES | YES | YES | SUBLIME_TEXT | | Sublime Text | YES | YES | YES | SUBLIME_TEXT |
| Zed | NO | YES | YES | ZED |
> [!NOTE] > [!NOTE]
> This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app. > This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app.

View file

@ -1 +1 @@
8.30.1 8.31

View file

@ -1,13 +1,16 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
set -o
set -u
set pipefail
if [ -z "$VERSION" ]; then if [[ -z "$VERSION" ]]; then
echo "Provide the version as environment variable VERSION" echo "Provide the version as environment variable VERSION"
exit 1 exit 1
fi fi
if [ -z "$RUNTIME" ]; then if [[ -z "$RUNTIME" ]]; then
echo "Provide the runtime as environment variable RUNTIME" echo "Provide the runtime as environment variable RUNTIME"
exit 1 exit 1
fi fi
@ -33,7 +36,7 @@ APPIMAGETOOL_URL=https://github.com/AppImage/appimagetool/releases/download/cont
cd build cd build
if [ ! -f "appimagetool" ]; then if [[ ! -f "appimagetool" ]]; then
curl -o appimagetool -L "$APPIMAGETOOL_URL" curl -o appimagetool -L "$APPIMAGETOOL_URL"
chmod +x appimagetool chmod +x appimagetool
fi fi

View file

@ -1,13 +1,16 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
set -o
set -u
set pipefail
if [ -z "$VERSION" ]; then if [[ -z "$VERSION" ]]; then
echo "Provide the version as environment variable VERSION" echo "Provide the version as environment variable VERSION"
exit 1 exit 1
fi fi
if [ -z "$RUNTIME" ]; then if [[ -z "$RUNTIME" ]]; then
echo "Provide the runtime as environment variable RUNTIME" echo "Provide the runtime as environment variable RUNTIME"
exit 1 exit 1
fi fi

View file

@ -1,13 +1,16 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
set -o
set -u
set pipefail
if [ -z "$VERSION" ]; then if [[ -z "$VERSION" ]]; then
echo "Provide the version as environment variable VERSION" echo "Provide the version as environment variable VERSION"
exit 1 exit 1
fi fi
if [ -z "$RUNTIME" ]; then if [[ -z "$RUNTIME" ]]; then
echo "Provide the runtime as environment variable RUNTIME" echo "Provide the runtime as environment variable RUNTIME"
exit 1 exit 1
fi fi

View file

@ -15,6 +15,7 @@
<ResourceInclude x:Key="en_US" Source="/Resources/Locales/en_US.axaml"/> <ResourceInclude x:Key="en_US" Source="/Resources/Locales/en_US.axaml"/>
<ResourceInclude x:Key="fr_FR" Source="/Resources/Locales/fr_FR.axaml"/> <ResourceInclude x:Key="fr_FR" Source="/Resources/Locales/fr_FR.axaml"/>
<ResourceInclude x:Key="pt_BR" Source="/Resources/Locales/pt_BR.axaml"/> <ResourceInclude x:Key="pt_BR" Source="/Resources/Locales/pt_BR.axaml"/>
<ResourceInclude x:Key="ru_RU" Source="/Resources/Locales/ru_RU.axaml"/>
<ResourceInclude x:Key="zh_CN" Source="/Resources/Locales/zh_CN.axaml"/> <ResourceInclude x:Key="zh_CN" Source="/Resources/Locales/zh_CN.axaml"/>
<ResourceInclude x:Key="zh_TW" Source="/Resources/Locales/zh_TW.axaml"/> <ResourceInclude x:Key="zh_TW" Source="/Resources/Locales/zh_TW.axaml"/>
</ResourceDictionary> </ResourceDictionary>

View file

@ -521,6 +521,9 @@ namespace SourceGit
return false; return false;
var param = args[0]; var param = args[0];
if (Directory.Exists(param))
return false;
if (!param.StartsWith("enter passphrase", StringComparison.OrdinalIgnoreCase) && if (!param.StartsWith("enter passphrase", StringComparison.OrdinalIgnoreCase) &&
!param.Contains(" password", StringComparison.OrdinalIgnoreCase)) !param.Contains(" password", StringComparison.OrdinalIgnoreCase))
return false; return false;

View file

@ -59,9 +59,14 @@ namespace SourceGit.Commands
// If an SSH private key was provided, sets the environment. // If an SSH private key was provided, sets the environment.
if (!string.IsNullOrEmpty(SSHKey)) if (!string.IsNullOrEmpty(SSHKey))
{
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'"); start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'");
}
else else
{
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new");
start.Arguments += "-c credential.helper=manager "; start.Arguments += "-c credential.helper=manager ";
}
// Force using en_US.UTF-8 locale to avoid GCM crash // Force using en_US.UTF-8 locale to avoid GCM crash
if (OperatingSystem.IsLinux()) if (OperatingSystem.IsLinux())

View file

@ -1,4 +1,5 @@
using System.IO; using System;
using System.IO;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
@ -7,9 +8,23 @@ namespace SourceGit.Converters
public static class PathConverters public static class PathConverters
{ {
public static readonly FuncValueConverter<string, string> PureFileName = public static readonly FuncValueConverter<string, string> PureFileName =
new FuncValueConverter<string, string>(fullpath => Path.GetFileName(fullpath) ?? ""); new(v => Path.GetFileName(v) ?? "");
public static readonly FuncValueConverter<string, string> PureDirectoryName = public static readonly FuncValueConverter<string, string> PureDirectoryName =
new FuncValueConverter<string, string>(fullpath => Path.GetDirectoryName(fullpath) ?? ""); new(v => Path.GetDirectoryName(v) ?? "");
public static readonly FuncValueConverter<string, string> RelativeToHome =
new(v =>
{
if (OperatingSystem.IsWindows())
return v;
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;
});
} }
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -20,6 +21,7 @@ namespace SourceGit.Models
public class Job public class Job
{ {
public string IndexLockFile = string.Empty;
public Commands.Fetch Cmd = null; public Commands.Fetch Cmd = null;
public DateTime NextRunTimepoint = DateTime.MinValue; public DateTime NextRunTimepoint = DateTime.MinValue;
} }
@ -75,8 +77,11 @@ namespace SourceGit.Models
foreach (var job in uptodate) foreach (var job in uptodate)
{ {
job.Cmd.Exec(); if (!File.Exists(job.IndexLockFile))
job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); {
job.Cmd.Exec();
job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval));
}
} }
Thread.Sleep(2000); Thread.Sleep(2000);
@ -86,10 +91,11 @@ namespace SourceGit.Models
}); });
} }
public void AddRepository(string repo) public void AddRepository(string repo, string gitDir)
{ {
var job = new Job var job = new Job
{ {
IndexLockFile = Path.Combine(gitDir, "index.lock"),
Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false }, Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false },
NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)), NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)),
}; };

View file

@ -1,9 +1,17 @@
using CommunityToolkit.Mvvm.ComponentModel; using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models namespace SourceGit.Models
{ {
public class CommitTemplate : ObservableObject public partial class CommitTemplate : ObservableObject
{ {
[GeneratedRegex(@"\$\{files(\:\d+)?\}")]
private static partial Regex REG_COMMIT_TEMPLATE_FILES();
public string Name public string Name
{ {
get => _name; get => _name;
@ -16,6 +24,56 @@ namespace SourceGit.Models
set => SetProperty(ref _content, value); set => SetProperty(ref _content, value);
} }
public string Apply(List<Change> changes)
{
var content = _content.Replace("${files_num}", $"{changes.Count}");
var matches = REG_COMMIT_TEMPLATE_FILES().Matches(content);
if (matches.Count == 0)
return content;
var builder = new StringBuilder();
var last = 0;
for (int i = 0; i < matches.Count; i++)
{
var match = matches[i];
if (!match.Success)
continue;
var start = match.Index;
if (start != last)
builder.Append(content.Substring(last, start - last));
var countStr = match.Groups[1].Value;
var paths = new List<string>();
var more = string.Empty;
if (countStr is { Length: <= 1 })
{
foreach (var c in changes)
paths.Add(c.Path);
}
else
{
var count = Math.Min(int.Parse(countStr.Substring(1)), changes.Count);
for (int j = 0; j < count; j++)
paths.Add(changes[i].Path);
if (count < changes.Count)
more = $" and {changes.Count - count} other files";
}
builder.Append(string.Join(", ", paths));
if (!string.IsNullOrEmpty(more))
builder.Append(more);
last = start + match.Length;
}
if (last != content.Length - 1)
builder.Append(content.Substring(last));
return builder.ToString();
}
private string _name = string.Empty; private string _name = string.Empty;
private string _content = string.Empty; private string _content = string.Empty;
} }

View file

@ -149,6 +149,11 @@ namespace SourceGit.Models
TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT", platformFinder); TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT", platformFinder);
} }
public void Zed(Func<string> platformFinder)
{
TryAdd("Zed", "zed", "\"{0}\"", "ZED", platformFinder);
}
public void FindJetBrainsFromToolbox(Func<string> platformFinder) public void FindJetBrainsFromToolbox(Func<string> platformFinder)
{ {
var exclude = new List<string> { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" }; var exclude = new List<string> { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" };

View file

@ -12,6 +12,7 @@ namespace SourceGit.Models
new Locale("Deutsch", "de_DE"), new Locale("Deutsch", "de_DE"),
new Locale("Français", "fr_FR"), new Locale("Français", "fr_FR"),
new Locale("Português (Brasil)", "pt_BR"), new Locale("Português (Brasil)", "pt_BR"),
new Locale("Русский", "ru_RU"),
new Locale("简体中文", "zh_CN"), new Locale("简体中文", "zh_CN"),
new Locale("繁體中文", "zh_TW"), new Locale("繁體中文", "zh_TW"),
}; };

View file

@ -54,6 +54,8 @@ namespace SourceGit.Models
new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"), new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"),
new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"), new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"),
new ShellOrTerminal("foot", "Foot", "foot"), new ShellOrTerminal("foot", "Foot", "foot"),
new ShellOrTerminal("wezterm", "WezTerm", "wezterm"),
new ShellOrTerminal("custom", "Custom", ""),
}; };
} }
} }

View file

@ -17,94 +17,92 @@ using TextMateSharp.Themes;
namespace SourceGit.Models namespace SourceGit.Models
{ {
public class RegistryOptionsWrapper : IRegistryOptions public static class GrammarUtility
{ {
public RegistryOptionsWrapper(ThemeName defaultTheme) private static readonly ExtraGrammar[] s_extraGrammars =
[
new ExtraGrammar("source.toml", ".toml", "toml.json"),
new ExtraGrammar("source.kotlin", ".kotlin", "kotlin.json"),
new ExtraGrammar("source.hx", ".hx", "haxe.json"),
new ExtraGrammar("source.hxml", ".hxml", "hxml.json"),
];
public static string GetScope(string file, RegistryOptions reg)
{ {
_backend = new RegistryOptions(defaultTheme); var extension = Path.GetExtension(file);
_extraGrammars = new List<IRawGrammar>();
string[] extraGrammarFiles = ["toml.json"];
foreach (var file in extraGrammarFiles)
{
var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{file}",
UriKind.RelativeOrAbsolute));
try
{
var grammar = GrammarReader.ReadGrammarSync(new StreamReader(asset));
_extraGrammars.Add(grammar);
}
catch
{
// ignore
}
}
}
public IRawTheme GetTheme(string scopeName)
{
return _backend.GetTheme(scopeName);
}
public IRawGrammar GetGrammar(string scopeName)
{
var grammar = _extraGrammars.Find(x => x.GetScopeName().Equals(scopeName, StringComparison.Ordinal));
return grammar ?? _backend.GetGrammar(scopeName);
}
public ICollection<string> GetInjections(string scopeName)
{
return _backend.GetInjections(scopeName);
}
public IRawTheme GetDefaultTheme()
{
return _backend.GetDefaultTheme();
}
public IRawTheme LoadTheme(ThemeName name)
{
return _backend.LoadTheme(name);
}
public string GetScopeByFileName(string filename)
{
var extension = Path.GetExtension(filename);
var grammar = _extraGrammars.Find(x => x.GetScopeName().EndsWith(extension, StringComparison.OrdinalIgnoreCase));
if (grammar != null)
return grammar.GetScopeName();
if (extension == ".h") if (extension == ".h")
extension = ".cpp"; extension = ".cpp";
else if (extension == ".resx" || extension == ".plist" || extension == ".manifest") else if (extension == ".resx" || extension == ".plist" || extension == ".manifest")
extension = ".xml"; extension = ".xml";
else if (extension == ".command") else if (extension == ".command")
extension = ".sh"; extension = ".sh";
else if (extension == ".kt" || extension == ".kts")
extension = ".kotlin";
foreach (var grammar in s_extraGrammars)
{
if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
return grammar.Scope;
}
return _backend.GetScopeByExtension(extension); return reg.GetScopeByExtension(extension);
} }
private readonly RegistryOptions _backend; public static IRawGrammar GetGrammar(string scopeName, RegistryOptions reg)
private readonly List<IRawGrammar> _extraGrammars; {
foreach (var grammar in s_extraGrammars)
{
if (grammar.Scope.Equals(scopeName, StringComparison.OrdinalIgnoreCase))
{
var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{grammar.File}",
UriKind.RelativeOrAbsolute));
try
{
return GrammarReader.ReadGrammarSync(new StreamReader(asset));
}
catch
{
break;
}
}
}
return reg.GetGrammar(scopeName);
}
private record ExtraGrammar(string Scope, string Extension, string File)
{
public readonly string Scope = Scope;
public readonly string Extension = Extension;
public readonly string File = File;
}
}
public class RegistryOptionsWrapper(ThemeName defaultTheme) : IRegistryOptions
{
public IRawTheme GetTheme(string scopeName) => _backend.GetTheme(scopeName);
public IRawTheme GetDefaultTheme() => _backend.GetDefaultTheme();
public IRawTheme LoadTheme(ThemeName name) => _backend.LoadTheme(name);
public ICollection<string> GetInjections(string scopeName) => _backend.GetInjections(scopeName);
public IRawGrammar GetGrammar(string scopeName) => GrammarUtility.GetGrammar(scopeName, _backend);
public string GetScope(string filename) => GrammarUtility.GetScope(filename, _backend);
private readonly RegistryOptions _backend = new(defaultTheme);
} }
public static class TextMateHelper public static class TextMateHelper
{ {
public static TextMate.Installation CreateForEditor(TextEditor editor) public static TextMate.Installation CreateForEditor(TextEditor editor)
{ {
if (Application.Current?.ActualThemeVariant == ThemeVariant.Dark) return editor.InstallTextMate(Application.Current?.ActualThemeVariant == ThemeVariant.Dark ?
return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.DarkPlus)); new RegistryOptionsWrapper(ThemeName.DarkPlus) :
new RegistryOptionsWrapper(ThemeName.LightPlus));
return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.LightPlus));
} }
public static void SetThemeByApp(TextMate.Installation installation) public static void SetThemeByApp(TextMate.Installation installation)
{ {
if (installation == null) if (installation is { RegistryOptions: RegistryOptionsWrapper reg })
return;
if (installation.RegistryOptions is RegistryOptionsWrapper reg)
{ {
var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark;
installation.SetTheme(reg.LoadTheme(isDark ? ThemeName.DarkPlus : ThemeName.LightPlus)); installation.SetTheme(reg.LoadTheme(isDark ? ThemeName.DarkPlus : ThemeName.LightPlus));
@ -115,7 +113,7 @@ namespace SourceGit.Models
{ {
if (installation is { RegistryOptions: RegistryOptionsWrapper reg }) if (installation is { RegistryOptions: RegistryOptionsWrapper reg })
{ {
installation.SetGrammar(reg.GetScopeByFileName(filePath)); installation.SetGrammar(reg.GetScope(filePath));
GC.Collect(); GC.Collect();
} }
} }

View file

@ -26,16 +26,10 @@ namespace SourceGit.Native
public string FindTerminal(Models.ShellOrTerminal shell) public string FindTerminal(Models.ShellOrTerminal shell)
{ {
var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; if (shell.Type.Equals("custom", StringComparison.Ordinal))
var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); return string.Empty;
foreach (var path in pathes)
{
var test = Path.Combine(path, shell.Exec);
if (File.Exists(test))
return test;
}
return string.Empty; return FindExecutable(shell.Exec);
} }
public List<Models.ExternalTool> FindExternalTools() public List<Models.ExternalTool> FindExternalTools()
@ -47,6 +41,7 @@ namespace SourceGit.Native
finder.Fleet(FindJetBrainsFleet); finder.Fleet(FindJetBrainsFleet);
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox"); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox");
finder.SublimeText(() => FindExecutable("subl")); finder.SublimeText(() => FindExecutable("subl"));
finder.Zed(() => FindExecutable("zeditor"));
return finder.Founded; return finder.Founded;
} }
@ -71,16 +66,24 @@ namespace SourceGit.Native
public void OpenTerminal(string workdir) public void OpenTerminal(string workdir)
{ {
if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal)) var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
{ var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured.");
return;
}
var startInfo = new ProcessStartInfo(); var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? "~" : workdir; startInfo.WorkingDirectory = cwd;
startInfo.FileName = OS.ShellOrTerminal; startInfo.FileName = OS.ShellOrTerminal;
Process.Start(startInfo);
if (OS.ShellOrTerminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"start --cwd \"{cwd}\"";
try
{
Process.Start(startInfo);
}
catch (Exception e)
{
App.RaiseException(workdir, $"Failed to start '{OS.ShellOrTerminal}'. Reason: {e.Message}");
}
} }
public void OpenWithDefaultEditor(string file) public void OpenWithDefaultEditor(string file)

View file

@ -34,7 +34,7 @@ namespace SourceGit.Native
return "iTerm"; return "iTerm";
} }
return "InvalidTerminal"; return string.Empty;
} }
public List<Models.ExternalTool> FindExternalTools() public List<Models.ExternalTool> FindExternalTools()
@ -46,6 +46,7 @@ namespace SourceGit.Native
finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Applications/Fleet.app/Contents/MacOS/Fleet"); finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Applications/Fleet.app/Contents/MacOS/Fleet");
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Application Support/JetBrains/Toolbox"); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Application Support/JetBrains/Toolbox");
finder.SublimeText(() => "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl"); finder.SublimeText(() => "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl");
finder.Zed(() => File.Exists("/usr/local/bin/zed") ? "/usr/local/bin/zed" : "/Applications/Zed.app/Contents/MacOS/cli");
return finder.Founded; return finder.Founded;
} }

View file

@ -74,12 +74,17 @@ namespace SourceGit.Native
return _backend.FindGitExecutable(); return _backend.FindGitExecutable();
} }
public static void SetShellOrTerminal(Models.ShellOrTerminal shellOrTerminal) public static bool TestShellOrTerminal(Models.ShellOrTerminal shell)
{ {
if (shellOrTerminal == null) return !string.IsNullOrEmpty(_backend.FindTerminal(shell));
}
public static void SetShellOrTerminal(Models.ShellOrTerminal shell)
{
if (shell == null)
ShellOrTerminal = string.Empty; ShellOrTerminal = string.Empty;
else else
ShellOrTerminal = _backend.FindTerminal(shellOrTerminal); ShellOrTerminal = _backend.FindTerminal(shell);
} }
public static void OpenInFileManager(string path, bool select = false) public static void OpenInFileManager(string path, bool select = false)
@ -95,7 +100,7 @@ namespace SourceGit.Native
public static void OpenTerminal(string workdir) public static void OpenTerminal(string workdir)
{ {
if (string.IsNullOrEmpty(ShellOrTerminal)) if (string.IsNullOrEmpty(ShellOrTerminal))
App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured."); App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured.");
else else
_backend.OpenTerminal(workdir); _backend.OpenTerminal(workdir);
} }

View file

@ -26,23 +26,11 @@ namespace SourceGit.Native
internal string szCSDVersion; internal string szCSDVersion;
} }
[StructLayout(LayoutKind.Sequential)]
internal struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs);
[DllImport("ntdll")] [DllImport("ntdll")]
private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation); private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);
[DllImport("dwmapi.dll")] [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
private static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs);
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)] [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
private static extern IntPtr ILCreateFromPathW(string pszPath); private static extern IntPtr ILCreateFromPathW(string pszPath);
@ -60,8 +48,8 @@ namespace SourceGit.Native
v.dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOEX>(); v.dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOEX>();
if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000)) if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000))
{ {
Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w)); Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, _) => FixWindowFrameOnWin10(w));
Control.LoadedEvent.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w)); Control.LoadedEvent.AddClassHandler<Window>((w, _) => FixWindowFrameOnWin10(w));
} }
} }
@ -158,15 +146,20 @@ namespace SourceGit.Native
public void OpenTerminal(string workdir) public void OpenTerminal(string workdir)
{ {
if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal)) if (!File.Exists(OS.ShellOrTerminal))
{ {
App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured."); App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured.");
return; return;
} }
var startInfo = new ProcessStartInfo(); var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = workdir; startInfo.WorkingDirectory = workdir;
startInfo.FileName = OS.ShellOrTerminal; startInfo.FileName = OS.ShellOrTerminal;
// Directly launching `Windows Terminal` need to specify the `-d` parameter
if (OS.ShellOrTerminal.EndsWith("wt.exe", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"-d \"{workdir}\"";
Process.Start(startInfo); Process.Start(startInfo);
} }
@ -206,14 +199,12 @@ namespace SourceGit.Native
Process.Start(start); Process.Start(start);
} }
private void ExtendWindowFrame(Window w) private void FixWindowFrameOnWin10(Window w)
{ {
var platformHandle = w.TryGetPlatformHandle(); if (w.WindowState != WindowState.Normal)
if (platformHandle == null) w.SystemDecorations = SystemDecorations.Full;
return; else
w.SystemDecorations = SystemDecorations.BorderOnly;
var margins = new MARGINS { cxLeftWidth = 1, cxRightWidth = 1, cyTopHeight = 1, cyBottomHeight = 1 };
DwmExtendFrameIntoClientArea(platformHandle.Handle, ref margins);
} }
#region EXTERNAL_EDITOR_FINDER #region EXTERNAL_EDITOR_FINDER

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
{
"information_for_contributors": [
"This file has been copied from https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/hxml.tmLanguage",
"and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage"
],
"fileTypes": [
"hxml"
],
"foldingStartMarker": "--next",
"foldingStopMarker": "\\n\\n",
"keyEquivalent": "^@H",
"name": "Hxml",
"patterns": [
{
"captures": {
"1": {
"name": "punctuation.definition.comment.hxml"
}
},
"match": "(#).*$\\n?",
"name": "comment.line.number-sign.hxml"
},
{
"begin": "(?<!\\w)(--macro)\\b",
"beginCaptures": {
"1": {
"name": "keyword.other.hxml"
}
},
"end": "\\n",
"patterns": [
{
"include": "source.hx#block-contents"
}
]
},
{
"match": "(?<!\\w)(-m|-main|--main|--run)\\b\\s*\\b(?:(([a-z][a-zA-Z0-9]*\\.)*)(_*[A-Z]\\w*))?\\b",
"captures": {
"1": {
"name": "keyword.other.hxml"
},
"2": {
"name": "support.package.hx"
},
"4": {
"name": "entity.name.type.hx"
}
}
},
{
"match": "(?<!\\w)(-cppia|-cpp?|-js|-as3|-swf-(header|version|lib(-extern)?)|-swf9?|-neko|-python|-php|-cs|-java-lib|-java|-xml|-lua|-hl|-x|-lib|-D|-resource|-exclude|-version|-v|-debug|-prompt|-cmd|-dce\\s+(std|full|no)?|--flash-strict|--no-traces|--flash-use-stage|--neko-source|--gen-hx-classes|-net-lib|-net-std|-c-arg|--each|--next|--display|--no-output|--times|--no-inline|--no-opt|--php-front|--php-lib|--php-prefix|--remap|--help-defines|--help-metas|-help|--help|-java|-cs|--js-modern|--interp|--eval|--dce|--wait|--connect|--cwd|--run).*$",
"captures": {
"1": {
"name": "keyword.other.hxml"
}
}
},
{
"match": "(?<!\\w)(--js(on)?|--lua|--swf-(header|version|lib(-extern)?)|--swf|--as3|--neko|--php|--cppia|--cpp|--cppia|--cs|--java-lib(-extern)?|--java|--jvm|--python|--hl|-p|--class-path|-L|--library|--define|-r|--resource|--cmd|-C|--verbose|--debug|--prompt|--xml|--json|--net-lib|--net-std|--c-arg|--version|--haxelib-global|-h|--main|--server-connect|--server-listen).*$",
"captures": {
"1": {
"name": "keyword.other.hxml"
}
}
}
],
"scopeName": "source.hxml",
"uuid": "CB1B853A-C4C8-42C3-BA70-1B1605BE51C1"
}

View file

@ -0,0 +1,701 @@
{
"information_for_contributors": [
"This file has been copied from https://github.com/eclipse/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/org.eclipse.buildship.kotlindsl.provider/kotlin.tmLanguage.json"
],
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Kotlin",
"scopeName": "source.kotlin",
"patterns": [
{
"include": "#import"
},
{
"include": "#package"
},
{
"include": "#code"
}
],
"fileTypes": [
"kts"
],
"repository": {
"import": {
"begin": "\\b(import)\\b\\s?([\\w+.]*\\w+)?\\s*",
"beginCaptures": {
"1": {
"name": "storage.type.import.kotlin"
},
"2": {
"name": "storage.modifier.import.kotlin"
}
},
"end": ";|$",
"name": "meta.import.kotlin",
"contentName": "entity.name.package.kotlin",
"patterns": [
{
"include": "#comments"
},
{
"include": "#hard-keywords"
},
{
"match": "\\*",
"name": "variable.language.wildcard.kotlin"
}
]
},
"package": {
"begin": "\\b(package)\\b\\s*",
"beginCaptures": {
"1": {
"name": "storage.type.package.kotlin"
}
},
"end": ";|$",
"name": "meta.package.kotlin",
"contentName": "entity.name.package.kotlin",
"patterns": [
{
"include": "#comments"
}
]
},
"code": {
"patterns": [
{
"include": "#comments"
},
{
"include": "#keywords"
},
{
"include": "#annotation-simple"
},
{
"include": "#annotation-site-list"
},
{
"include": "#annotation-site"
},
{
"include": "#class-declaration"
},
{
"include": "#object-declaration"
},
{
"include": "#type-alias"
},
{
"include": "#function-declaration"
},
{
"include": "#variable-declaration"
},
{
"include": "#constant-declaration"
},
{
"include": "#variable"
},
{
"include": "#object"
},
{
"include": "#type-constraint"
},
{
"include": "#type-annotation"
},
{
"include": "#function-call"
},
{
"include": "#property.reference"
},
{
"include": "#method-reference"
},
{
"include": "#key"
},
{
"include": "#string"
},
{
"include": "#string-empty"
},
{
"include": "#string-multiline"
},
{
"include": "#character"
},
{
"include": "#lambda-arrow"
},
{
"include": "#operators"
},
{
"include": "#self-reference"
},
{
"include": "#decimal-literal"
},
{
"include": "#hex-literal"
},
{
"include": "#binary-literal"
},
{
"include": "#boolean-literal"
},
{
"include": "#null-literal"
},
{
"match": ",",
"name": "punctuation.separator.delimiter.kotlin"
},
{
"match": "\\.",
"name": "punctuation.separator.period.kotlin"
},
{
"match": "\\?\\.",
"name": "punctuation.accessor.optional.kotlin"
}
]
},
"comments": {
"patterns": [
{
"include": "#comment-line"
},
{
"include": "#comment-block"
},
{
"include": "#comment-javadoc"
}
]
},
"comment-line": {
"begin": "//",
"end": "$",
"name": "comment.line.double-slash.kotlin"
},
"comment-block": {
"begin": "/\\*(?!\\*)",
"end": "\\*/",
"name": "comment.block.kotlin"
},
"comment-javadoc": {
"patterns": [
{
"begin": "/\\*\\*",
"end": "\\*/",
"name": "comment.block.javadoc.kotlin",
"patterns": [
{
"match": "@(author|deprecated|return|see|serial|since|version)\\b",
"name": "keyword.other.documentation.javadoc.kotlin"
},
{
"match": "(@param)\\s+(\\S+)",
"captures": {
"1": {
"name": "keyword.other.documentation.javadoc.kotlin"
},
"2": {
"name": "variable.parameter.kotlin"
}
}
},
{
"match": "(@(?:exception|throws))\\s+(\\S+)",
"captures": {
"1": {
"name": "keyword.other.documentation.javadoc.kotlin"
},
"2": {
"name": "entity.name.type.class.kotlin"
}
}
},
{
"match": "{(@link)\\s+(\\S+)?#([\\w$]+\\s*\\([^\\(\\)]*\\)).*}",
"captures": {
"1": {
"name": "keyword.other.documentation.javadoc.kotlin"
},
"2": {
"name": "entity.name.type.class.kotlin"
},
"3": {
"name": "variable.parameter.kotlin"
}
}
}
]
}
]
},
"keywords": {
"patterns": [
{
"include": "#prefix-modifiers"
},
{
"include": "#postfix-modifiers"
},
{
"include": "#soft-keywords"
},
{
"include": "#hard-keywords"
},
{
"include": "#control-keywords"
},
{
"include": "#map-keywords"
}
]
},
"prefix-modifiers": {
"match": "\\b(abstract|final|enum|open|annotation|sealed|data|override|final|lateinit|private|protected|public|internal|inner|companion|noinline|crossinline|vararg|reified|tailrec|operator|infix|inline|external|const|suspend|value)\\b",
"name": "storage.modifier.other.kotlin"
},
"postfix-modifiers": {
"match": "\\b(where|by|get|set)\\b",
"name": "storage.modifier.other.kotlin"
},
"soft-keywords": {
"match": "\\b(catch|finally|field)\\b",
"name": "keyword.soft.kotlin"
},
"hard-keywords": {
"match": "\\b(as|typeof|is|in)\\b",
"name": "keyword.hard.kotlin"
},
"control-keywords": {
"match": "\\b(if|else|while|do|when|try|throw|break|continue|return|for)\\b",
"name": "keyword.control.kotlin"
},
"map-keywords": {
"match": "\\b(to)\\b",
"name": "keyword.map.kotlin"
},
"annotation-simple": {
"match": "(?<!\\w)@[\\w\\.]+\\b(?!:)",
"name": "entity.name.type.annotation.kotlin"
},
"annotation-site-list": {
"begin": "(?<!\\w)(@\\w+):\\s*\\[",
"end": "\\]",
"beginCaptures": {
"1": {
"name": "entity.name.type.annotation-site.kotlin"
}
},
"patterns": [
{
"include": "#unescaped-annotation"
}
]
},
"annotation-site": {
"begin": "(?<!\\w)(@\\w+):\\s*(?!\\[)",
"end": "$",
"beginCaptures": {
"1": {
"name": "entity.name.type.annotation-site.kotlin"
}
},
"patterns": [
{
"include": "#unescaped-annotation"
}
]
},
"unescaped-annotation": {
"match": "\\b[\\w\\.]+\\b",
"name": "entity.name.type.annotation.kotlin"
},
"class-declaration": {
"match": "\\b(class|interface)\\s+(\\b\\w+\\b|`[^`]+`)\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?",
"captures": {
"1": {
"name": "storage.type.class.kotlin"
},
"2": {
"name": "entity.name.type.class.kotlin"
},
"3": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"object-declaration": {
"match": "\\b(object)\\s+(\\b\\w+\\b|`[^`]+`)",
"captures": {
"1": {
"name": "storage.type.object.kotlin"
},
"2": {
"name": "entity.name.type.object.kotlin"
}
}
},
"type-alias": {
"match": "\\b(typealias)\\s+(\\b\\w+\\b|`[^`]+`)\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?",
"captures": {
"1": {
"name": "storage.type.alias.kotlin"
},
"2": {
"name": "entity.name.type.kotlin"
},
"3": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"function-declaration": {
"begin": "\\b(fun)\\b\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?\\s*(?:(\\w+)\\.)?(\\b\\w+\\b|`[^`]+`)\\(",
"beginCaptures": {
"1": {
"name": "storage.type.function.kotlin"
},
"2": {
"patterns": [
{
"include": "#type-parameter"
}
]
},
"4": {
"name": "entity.name.type.class.extension.kotlin"
},
"5": {
"name": "entity.name.function.declaration.kotlin"
}
},
"end": "\\)",
"endCaptures": {
"1": {
"name": "keyword.operator.assignment.type.kotlin"
}
},
"patterns": [
{
"include": "#parameter-declaration"
}
]
},
"parameter-declaration": {
"match": "\\b(\\w+)\\s*(:)\\s*(\\w+)(\\?)?(,)?",
"captures": {
"1": {
"name": "variable.parameter.kotlin"
},
"2": {
"name": "keyword.operator.assignment.type.kotlin"
},
"3": {
"name": "entity.name.type.kotlin"
},
"4": {
"name": "keyword.operator.optional"
},
"5": {
"name": "punctuation.separator.delimiter.kotlin"
}
}
},
"variable-declaration": {
"match": "\\b(var)\\b\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?",
"captures": {
"1": {
"name": "storage.type.variable.kotlin"
},
"2": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"constant-declaration": {
"match": "\\b(val)\\b\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?",
"captures": {
"1": {
"name": "storage.type.variable.readonly.kotlin"
},
"2": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"variable" : {
"match": "\\b(\\w+)(?=\\s*[:=])",
"captures": {
"1": {
"name": "variable.other.definition.kotlin"
}
}
},
"object" : {
"match": "\\b(\\w+)(?=\\.)",
"captures": {
"1": {
"name": "variable.other.object.kotlin"
}
}
},
"type-parameter": {
"patterns": [
{
"match": "(:)?\\s*(\\b\\w+\\b)(\\?)?",
"captures": {
"1": {
"name": "keyword.operator.assignment.kotlin"
},
"2": {
"name": "entity.name.type.kotlin"
},
"3": {
"name": "keyword.operator.optional"
}
}
},
{
"match": "\\b(in|out)\\b",
"name": "storage.modifier.kotlin"
}
]
},
"type-annotation": {
"match": "(?<![:?]):\\s*(\\w|\\?|\\s|->|(?<GROUP>[<(]([^<>()\"']|\\g<GROUP>)+[)>]))+",
"captures": {
"0": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"function-call": {
"match": "(?:(\\?\\.)|(\\.))?(\\b\\w+\\b|`[^`]+`)\\s*(?<GROUP><([^<>]|\\g<GROUP>)+>)?\\s*(?=[({])",
"captures": {
"1": {
"name": "punctuation.accessor.optional.kotlin"
},
"2": {
"name": "punctuation.separator.period.kotlin"
},
"3": {
"name": "entity.name.function.call.kotlin"
},
"4": {
"patterns": [
{
"include": "#type-parameter"
}
]
}
}
},
"property.reference": {
"match": "(?:(\\?\\.)|(\\.))(\\w+)\\b",
"captures": {
"1": {
"name": "punctuation.accessor.optional.kotlin"
},
"2": {
"name": "punctuation.separator.period.kotlin"
},
"3": {
"name": "variable.other.property.kotlin"
}
}
},
"method-reference": {
"match": "\\??::(\\b\\w+\\b|`[^`]+`)",
"captures": {
"1": {
"name": "entity.name.function.reference.kotlin"
}
}
},
"key": {
"match": "\\b(\\w=)\\s*(=)",
"captures": {
"1": {
"name": "variable.parameter.kotlin"
},
"2": {
"name": "keyword.operator.assignment.kotlin"
}
}
},
"string-empty": {
"match": "(?<!\")\"\"(?!\")",
"name": "string.quoted.double.kotlin"
},
"string": {
"begin": "(?<!\")\"(?!\")",
"end": "\"",
"name": "string.quoted.double.kotlin",
"patterns": [
{
"match": "\\\\.",
"name": "constant.character.escape.kotlin"
},
{
"include": "#string-escape-simple"
},
{
"include": "#string-escape-bracketed"
}
]
},
"string-multiline": {
"begin": "\"\"\"",
"end": "\"\"\"",
"name": "string.quoted.double.kotlin",
"patterns": [
{
"match": "\\\\.",
"name": "constant.character.escape.kotlin"
},
{
"include": "#string-escape-simple"
},
{
"include": "#string-escape-bracketed"
}
]
},
"string-escape-simple": {
"match": "(?<!\\\\)\\$\\w+\\b",
"name": "variable.string-escape.kotlin"
},
"string-escape-bracketed": {
"begin": "(?<!\\\\)(\\$\\{)",
"end": "(\\})",
"name": "meta.template.expression.kotlin",
"beginCaptures": {
"1": {
"name": "punctuation.definition.template-expression.begin"
}
},
"endCaptures": {
"1": {
"name": "punctuation.definition.template-expression.end"
}
},
"patterns": [
{
"include": "#code"
}
]
},
"character": {
"begin": "'",
"end": "'",
"name": "string.quoted.single.kotlin",
"patterns": [
{
"match": "\\\\.",
"name": "constant.character.escape.kotlin"
}
]
},
"decimal-literal": {
"match": "\\b\\d[\\d_]*(\\.[\\d_]+)?((e|E)\\d+)?(u|U)?(L|F|f)?\\b",
"name": "constant.numeric.decimal.kotlin"
},
"hex-literal": {
"match": "0(x|X)[A-Fa-f0-9][A-Fa-f0-9_]*(u|U)?",
"name": "constant.numeric.hex.kotlin"
},
"binary-literal": {
"match": "0(b|B)[01][01_]*",
"name": "constant.numeric.binary.kotlin"
},
"boolean-literal": {
"match": "\\b(true|false)\\b",
"name": "constant.language.boolean.kotlin"
},
"null-literal": {
"match": "\\bnull\\b",
"name": "constant.language.null.kotlin"
},
"lambda-arrow": {
"match": "->",
"name": "storage.type.function.arrow.kotlin"
},
"operators": {
"patterns": [
{
"match": "(===?|\\!==?|<=|>=|<|>)",
"name": "keyword.operator.comparison.kotlin"
},
{
"match": "(\\?:)",
"name": "keyword.operator.elvis.kotlin"
},
{
"match": "([+*/%-]=)",
"name": "keyword.operator.assignment.arithmetic.kotlin"
},
{
"match": "(=)",
"name": "keyword.operator.assignment.kotlin"
},
{
"match": "([+*/%-])",
"name": "keyword.operator.arithmetic.kotlin"
},
{
"match": "(!|&&|\\|\\|)",
"name": "keyword.operator.logical.kotlin"
},
{
"match": "(--|\\+\\+)",
"name": "keyword.operator.increment-decrement.kotlin"
},
{
"match": "(\\.\\.)",
"name": "keyword.operator.range.kotlin"
}
]
},
"self-reference": {
"match": "\\b(this|super)(@\\w+)?\\b",
"name": "variable.language.this.kotlin"
}
}
}

View file

@ -85,6 +85,7 @@
<StreamGeometry x:Key="Icons.Relation">m224 154a166 166 0 00-166 166v192a166 166 0 00166 166h64v-76h-64a90 90 0 01-90-90v-192a90 90 0 0190-90h320a90 90 0 0190 90v192a90 90 0 01-90 90h-128v77h128a166 166 0 00166-167v-192a166 166 0 00-166-166h-320zm166 390a90 90 0 0190-90h128v-76h-128a166 166 0 00-166 166v192a166 166 0 00166 166h320a166 166 0 00166-166v-192a166 166 0 00-166-166h-64v77h64a90 90 0 0190 90v192a90 90 0 01-90 90h-320a90 90 0 01-90-90v-192z</StreamGeometry> <StreamGeometry x:Key="Icons.Relation">m224 154a166 166 0 00-166 166v192a166 166 0 00166 166h64v-76h-64a90 90 0 01-90-90v-192a90 90 0 0190-90h320a90 90 0 0190 90v192a90 90 0 01-90 90h-128v77h128a166 166 0 00166-167v-192a166 166 0 00-166-166h-320zm166 390a90 90 0 0190-90h128v-76h-128a166 166 0 00-166 166v192a166 166 0 00166 166h320a166 166 0 00166-166v-192a166 166 0 00-166-166h-64v77h64a90 90 0 0190 90v192a90 90 0 01-90 90h-320a90 90 0 01-90-90v-192z</StreamGeometry>
<StreamGeometry x:Key="Icons.Remote">M706 302a289 289 0 00-173 44 27 27 0 1029 46 234 234 0 01125-36c23 0 45 3 66 9 93 28 161 114 161 215C914 704 813 805 687 805H337C211 805 110 704 110 580c0-96 61-178 147-210C282 263 379 183 495 183a245 245 0 01210 119z</StreamGeometry> <StreamGeometry x:Key="Icons.Remote">M706 302a289 289 0 00-173 44 27 27 0 1029 46 234 234 0 01125-36c23 0 45 3 66 9 93 28 161 114 161 215C914 704 813 805 687 805H337C211 805 110 704 110 580c0-96 61-178 147-210C282 263 379 183 495 183a245 245 0 01210 119z</StreamGeometry>
<StreamGeometry x:Key="Icons.Remote.Add">M364 512h67v108h108v67h-108v108h-67v-108h-108v-67h108v-108zm298-64A107 107 0 01768 555C768 614 720 660 660 660h-108v-54h-108v-108h-94v108h-94c4-21 22-47 44-51l-1-12a75 75 0 0171-75a128 128 0 01239-7a106 106 0 0153-14z</StreamGeometry> <StreamGeometry x:Key="Icons.Remote.Add">M364 512h67v108h108v67h-108v108h-67v-108h-108v-67h108v-108zm298-64A107 107 0 01768 555C768 614 720 660 660 660h-108v-54h-108v-108h-94v108h-94c4-21 22-47 44-51l-1-12a75 75 0 0171-75a128 128 0 01239-7a106 106 0 0153-14z</StreamGeometry>
<StreamGeometry x:Key="Icons.Remotes">M115 386l19 33c17 29 44 50 76 60l116 33c34 10 58 41 58 77v80c0 22 12 42 32 52s32 30 32 52v78c0 31 30 54 60 45 32-9 57-35 65-68l6-22c8-34 30-63 61-80l16-9c30-17 48-49 48-83v-17c0-25-10-50-28-68l-8-8c-18-18-42-28-68-28H514c-22 0-44-6-64-17l-69-39c-9-5-15-13-18-22-6-19 2-40 20-49l12-6c13-7 29-8 43-3l46 15c16 5 34-1 44-15 9-14 8-33-2-46l-27-33c-20-24-20-59 1-83l31-37c18-21 20-50 7-73l-5-8c-7-0-14-1-21-1-186 0-343 122-396 290zM928 512c0-74-19-143-53-203L824 330c-31 13-48 48-37 80l34 101c7 21 24 37 45 42l58 15c2-18 4-36 4-55zM0 512a512 512 0 111024 0 512 512 0 11-1024 0z</StreamGeometry>
<StreamGeometry x:Key="Icons.RemoveAll">M1024 64v704h-128v128h-128v128h-768v-704h128v-128h128v-128zM64 960h640v-576h-640zM320 128v64h576v512h64v-576zM192 256v64h576v512h64v-576zM432 688L576 832H480L384 736 288 832H192l144-144L192 544h96L384 640l96-96H576z</StreamGeometry> <StreamGeometry x:Key="Icons.RemoveAll">M1024 64v704h-128v128h-128v128h-768v-704h128v-128h128v-128zM64 960h640v-576h-640zM320 128v64h576v512h64v-576zM192 256v64h576v512h64v-576zM432 688L576 832H480L384 736 288 832H192l144-144L192 544h96L384 640l96-96H576z</StreamGeometry>
<StreamGeometry x:Key="Icons.Rename">M853 256h-43v512h43c47 0 85-38 85-85v-341c0-47-38-85-85-85zM725 768V171h128V85h-341v85H640v85H171c-47 0-85 38-85 85v341c0 47 38 85 85 85h469V853h-128v85h341v-85H725v-86zm-469-171v-171h384v171H256z</StreamGeometry> <StreamGeometry x:Key="Icons.Rename">M853 256h-43v512h43c47 0 85-38 85-85v-341c0-47-38-85-85-85zM725 768V171h128V85h-341v85H640v85H171c-47 0-85 38-85 85v341c0 47 38 85 85 85h469V853h-128v85h341v-85H725v-86zm-469-171v-171h384v171H256z</StreamGeometry>
<StreamGeometry x:Key="Icons.Repositories">M960 146v91C960 318 759 384 512 384S64 318 64 238V146C64 66 265 0 512 0s448 66 448 146zM960 352v206C960 638 759 704 512 704S64 638 64 558V352c96 66 272 97 448 97S864 418 960 352zm0 320v206C960 958 759 1024 512 1024S64 958 64 878V672c96 66 272 97 448 97S864 738 960 672z</StreamGeometry> <StreamGeometry x:Key="Icons.Repositories">M960 146v91C960 318 759 384 512 384S64 318 64 238V146C64 66 265 0 512 0s448 66 448 146zM960 352v206C960 638 759 704 512 704S64 638 64 558V352c96 66 272 97 448 97S864 418 960 352zm0 320v206C960 958 759 1024 512 1024S64 958 64 878V672c96 66 272 97 448 97S864 738 960 672z</StreamGeometry>
@ -101,9 +102,11 @@
<StreamGeometry x:Key="Icons.Stopwatch">M576 160H448c-18 0-32-14-32-32s14-32 32-32h128c18 0 32 14 32 32s-14 32-32 32zm243 186 36-36c13-13 13-33 0-45s-33-13-45 0l-33 33C708 233 614 192 512 192c-212 0-384 172-384 384s172 384 384 384 384-172 384-384c0-86-29-166-77-230zM544 894V864c0-18-14-32-32-32s-32 14-32 32v30C329 879 209 759 194 608H224c18 0 32-14 32-32s-14-32-32-32h-30C209 393 329 273 480 258V288c0 18 14 32 32 32s32-14 32-32v-30C695 273 815 393 830 544H800c-18 0-32 14-32 32s14 32 32 32h30C815 759 695 879 544 894zm108-471-160 128c-14 11-16 31-5 45 6 8 16 12 25 12 7 0 14-2 20-7l160-128c14-11 16-31 5-45-11-14-31-16-45-5z</StreamGeometry> <StreamGeometry x:Key="Icons.Stopwatch">M576 160H448c-18 0-32-14-32-32s14-32 32-32h128c18 0 32 14 32 32s-14 32-32 32zm243 186 36-36c13-13 13-33 0-45s-33-13-45 0l-33 33C708 233 614 192 512 192c-212 0-384 172-384 384s172 384 384 384 384-172 384-384c0-86-29-166-77-230zM544 894V864c0-18-14-32-32-32s-32 14-32 32v30C329 879 209 759 194 608H224c18 0 32-14 32-32s-14-32-32-32h-30C209 393 329 273 480 258V288c0 18 14 32 32 32s32-14 32-32v-30C695 273 815 393 830 544H800c-18 0-32 14-32 32s14 32 32 32h30C815 759 695 879 544 894zm108-471-160 128c-14 11-16 31-5 45 6 8 16 12 25 12 7 0 14-2 20-7l160-128c14-11 16-31 5-45-11-14-31-16-45-5z</StreamGeometry>
<StreamGeometry x:Key="Icons.Submodule">M558 545 790 403c24-15 31-47 16-71-15-24-46-31-70-17L507 457 277 315c-24-15-56-7-71 17-15 24-7 56 17 71l232 143V819c0 28 23 51 51 51 28 0 51-23 51-51V545h0zM507 0l443 256v512L507 1024 63 768v-512L507 0z</StreamGeometry> <StreamGeometry x:Key="Icons.Submodule">M558 545 790 403c24-15 31-47 16-71-15-24-46-31-70-17L507 457 277 315c-24-15-56-7-71 17-15 24-7 56 17 71l232 143V819c0 28 23 51 51 51 28 0 51-23 51-51V545h0zM507 0l443 256v512L507 1024 63 768v-512L507 0z</StreamGeometry>
<StreamGeometry x:Key="Icons.Submodule.Add">M770 320a41 41 0 00-56-14l-252 153L207 306a41 41 0 10-43 70l255 153 2 296a41 41 0 0082 0l-2-295 255-155a41 41 0 0014-56zM481 935a42 42 0 01-42 0L105 741a42 42 0 01-21-36v-386a42 42 0 0121-36L439 89a42 42 0 0142 0l335 193a42 42 0 0121 36v87h84v-87a126 126 0 00-63-109L523 17a126 126 0 00-126 0L63 210a126 126 0 00-63 109v386a126 126 0 0063 109l335 193a126 126 0 00126 0l94-54-42-72zM1029 700h-126v-125a42 42 0 00-84 0v126h-126a42 42 0 000 84h126v126a42 42 0 1084 0v-126h126a42 42 0 000-84z</StreamGeometry> <StreamGeometry x:Key="Icons.Submodule.Add">M770 320a41 41 0 00-56-14l-252 153L207 306a41 41 0 10-43 70l255 153 2 296a41 41 0 0082 0l-2-295 255-155a41 41 0 0014-56zM481 935a42 42 0 01-42 0L105 741a42 42 0 01-21-36v-386a42 42 0 0121-36L439 89a42 42 0 0142 0l335 193a42 42 0 0121 36v87h84v-87a126 126 0 00-63-109L523 17a126 126 0 00-126 0L63 210a126 126 0 00-63 109v386a126 126 0 0063 109l335 193a126 126 0 00126 0l94-54-42-72zM1029 700h-126v-125a42 42 0 00-84 0v126h-126a42 42 0 000 84h126v126a42 42 0 1084 0v-126h126a42 42 0 000-84z</StreamGeometry>
<StreamGeometry x:Key="Icons.Submodules">M416 587c21 0 37 17 37 37v299A37 37 0 01416 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zm448 0c21 0 37 17 37 37v299A37 37 0 01864 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zM758 91l183 189a37 37 0 010 52l-182 188a37 37 0 01-53 1l-183-189a37 37 0 010-52l182-188a37 37 0 0153-1zM416 139c21 0 37 17 37 37v299A37 37 0 01416 512h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299z</StreamGeometry>
<StreamGeometry x:Key="Icons.SyntaxHighlight">M875 128h-725A107 107 0 0043 235v555A107 107 0 00149 896h725a107 107 0 00107-107v-555A107 107 0 00875 128zm-115 640h-183v-58l25-3c15 0 19-8 14-24l-22-61H419l-28 82 39 2V768h-166v-58l18-3c18-2 22-11 26-24l125-363-40-4V256h168l160 448 39 3zM506 340l-72 218h145l-71-218h-2z</StreamGeometry> <StreamGeometry x:Key="Icons.SyntaxHighlight">M875 128h-725A107 107 0 0043 235v555A107 107 0 00149 896h725a107 107 0 00107-107v-555A107 107 0 00875 128zm-115 640h-183v-58l25-3c15 0 19-8 14-24l-22-61H419l-28 82 39 2V768h-166v-58l18-3c18-2 22-11 26-24l125-363-40-4V256h168l160 448 39 3zM506 340l-72 218h145l-71-218h-2z</StreamGeometry>
<StreamGeometry x:Key="Icons.Tag">M177 156c-22 5-33 17-36 37c-10 57-33 258-13 278l445 445c23 23 61 23 84 0l246-246c23-23 23-61 0-84l-445-445C437 120 231 145 177 156zM331 344c-26 26-69 26-95 0c-26-26-26-69 0-95s69-26 95 0C357 276 357 318 331 344z</StreamGeometry> <StreamGeometry x:Key="Icons.Tag">M177 156c-22 5-33 17-36 37c-10 57-33 258-13 278l445 445c23 23 61 23 84 0l246-246c23-23 23-61 0-84l-445-445C437 120 231 145 177 156zM331 344c-26 26-69 26-95 0c-26-26-26-69 0-95s69-26 95 0C357 276 357 318 331 344z</StreamGeometry>
<StreamGeometry x:Key="Icons.Tag.Add">M683 537h-144v-142h-142V283H239a44 44 0 00-41 41v171a56 56 0 0014 34l321 321a41 41 0 0058 0l174-174a41 41 0 000-58zm-341-109a41 41 0 110-58a41 41 0 010 58zM649 284V142h-69v142h-142v68h142v142h69v-142h142v-68h-142z</StreamGeometry> <StreamGeometry x:Key="Icons.Tag.Add">M683 537h-144v-142h-142V283H239a44 44 0 00-41 41v171a56 56 0 0014 34l321 321a41 41 0 0058 0l174-174a41 41 0 000-58zm-341-109a41 41 0 110-58a41 41 0 010 58zM649 284V142h-69v142h-142v68h142v142h69v-142h142v-68h-142z</StreamGeometry>
<StreamGeometry x:Key="Icons.Tags">M996 452 572 28A96 96 0 00504 0H96C43 0 0 43 0 96v408a96 96 0 0028 68l424 424c37 37 98 37 136 0l408-408c37-37 37-98 0-136zM224 320c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96zm1028 268L844 996c-37 37-98 37-136 0l-1-1L1055 647c34-34 53-79 53-127s-19-93-53-127L663 0h97a96 96 0 0168 28l424 424c37 37 37 98 0 136z</StreamGeometry>
<StreamGeometry x:Key="Icons.Target">M765 118 629 239l-16 137-186 160 54 59 183-168 144 4 136-129 47-43-175-12L827 67zM489 404c-66 0-124 55-124 125s54 121 124 121c66 0 120-55 120-121H489l23-121c-8-4-16-4-23-4zM695 525c0 114-93 207-206 207s-206-94-206-207 93-207 206-207c16 0 27 0 43 4l43-207c-27-4-54-8-85-8-229 0-416 188-416 419s187 419 416 419c225 0 408-180 416-403v-12l-210-4z</StreamGeometry> <StreamGeometry x:Key="Icons.Target">M765 118 629 239l-16 137-186 160 54 59 183-168 144 4 136-129 47-43-175-12L827 67zM489 404c-66 0-124 55-124 125s54 121 124 121c66 0 120-55 120-121H489l23-121c-8-4-16-4-23-4zM695 525c0 114-93 207-206 207s-206-94-206-207 93-207 206-207c16 0 27 0 43 4l43-207c-27-4-54-8-85-8-229 0-416 188-416 419s187 419 416 419c225 0 408-180 416-403v-12l-210-4z</StreamGeometry>
<StreamGeometry x:Key="Icons.Terminal">M144 112h736c18 0 32 14 32 32v736c0 18-14 32-32 32H144c-18 0-32-14-32-32V144c0-18 14-32 32-32zm112 211v72a9 9 0 003 7L386 509 259 615a9 9 0 00-3 7v72a9 9 0 0015 7L493 516a9 9 0 000-14l-222-186a9 9 0 00-15 7zM522 624a10 10 0 00-10 10v60a10 10 0 0010 10h237a10 10 0 0010-10v-60a10 10 0 00-10-10H522z</StreamGeometry> <StreamGeometry x:Key="Icons.Terminal">M144 112h736c18 0 32 14 32 32v736c0 18-14 32-32 32H144c-18 0-32-14-32-32V144c0-18 14-32 32-32zm112 211v72a9 9 0 003 7L386 509 259 615a9 9 0 00-3 7v72a9 9 0 0015 7L493 516a9 9 0 000-14l-222-186a9 9 0 00-15 7zM522 624a10 10 0 00-10 10v60a10 10 0 0010 10h237a10 10 0 0010-10v-60a10 10 0 00-10-10H522z</StreamGeometry>
<StreamGeometry x:Key="Icons.Track">M897 673v13c0 51-42 93-93 93h-10c-1 0-2 0-2 0H220c-23 0-42 19-42 42v13c0 23 19 42 42 42h552c14 0 26 12 26 26 0 14-12 26-26 26H220c-51 0-93-42-93-93v-13c0-51 42-93 93-93h20c1-0 2-0 2-0h562c23 0 42-19 42-42v-13c0-11-5-22-13-29-8-7-17-11-28-10H660c-14 0-26-12-26-26 0-14 12-26 26-26h144c24-1 47 7 65 24 18 17 29 42 29 67zM479 98c-112 0-203 91-203 203 0 44 14 85 38 118l132 208c15 24 50 24 66 0l133-209c23-33 37-73 37-117 0-112-91-203-203-203zm0 327c-68 0-122-55-122-122s55-122 122-122 122 55 122 122-55 122-122 122z</StreamGeometry> <StreamGeometry x:Key="Icons.Track">M897 673v13c0 51-42 93-93 93h-10c-1 0-2 0-2 0H220c-23 0-42 19-42 42v13c0 23 19 42 42 42h552c14 0 26 12 26 26 0 14-12 26-26 26H220c-51 0-93-42-93-93v-13c0-51 42-93 93-93h20c1-0 2-0 2-0h562c23 0 42-19 42-42v-13c0-11-5-22-13-29-8-7-17-11-28-10H660c-14 0-26-12-26-26 0-14 12-26 26-26h144c24-1 47 7 65 24 18 17 29 42 29 67zM479 98c-112 0-203 91-203 203 0 44 14 85 38 118l132 208c15 24 50 24 66 0l133-209c23-33 37-73 37-117 0-112-91-203-203-203zm0 327c-68 0-122-55-122-122s55-122 122-122 122 55 122 122-55 122-122 122z</StreamGeometry>
@ -121,6 +124,7 @@
<StreamGeometry x:Key="Icons.Window.Restore">M256 128l0 192L64 320l0 576 704 0 0-192 192 0L960 128 256 128zM704 832 128 832 128 384l576 0L704 832zM896 640l-128 0L768 320 320 320 320 192l576 0L896 640z</StreamGeometry> <StreamGeometry x:Key="Icons.Window.Restore">M256 128l0 192L64 320l0 576 704 0 0-192 192 0L960 128 256 128zM704 832 128 832 128 384l576 0L704 832zM896 640l-128 0L768 320 320 320 320 192l576 0L896 640z</StreamGeometry>
<StreamGeometry x:Key="Icons.WordWrap">M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z</StreamGeometry> <StreamGeometry x:Key="Icons.WordWrap">M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z</StreamGeometry>
<StreamGeometry x:Key="Icons.Workspace">M128 691H6V38h838v160h-64V102H70v525H128zM973 806H154V250h819v557zm-755-64h691V314H218v429zM365 877h448v64h-448z</StreamGeometry> <StreamGeometry x:Key="Icons.Workspace">M128 691H6V38h838v160h-64V102H70v525H128zM973 806H154V250h819v557zm-755-64h691V314H218v429zM365 877h448v64h-448z</StreamGeometry>
<StreamGeometry x:Key="Icons.Worktree">M512 0C229 0 0 72 0 160v128C0 376 229 448 512 448s512-72 512-160v-128C1024 72 795 0 512 0zM512 544C229 544 0 472 0 384v192c0 88 229 160 512 160s512-72 512-160V384c0 88-229 160-512 160zM512 832c-283 0-512-72-512-160v192C0 952 229 1024 512 1024s512-72 512-160v-192c0 88-229 160-512 160z</StreamGeometry> <StreamGeometry x:Key="Icons.Worktree">M853 267H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v555c0 41 34 75 75 75h683c41 0 75-34 75-75V341c0-41-34-75-75-75zm-683-43h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H853c6 0 11 4 11 11v75h-704V235c0-6 4-11 11-11zm683 576H171c-6 0-11-4-11-11V480h704V789c0 6-4 11-11 11z</StreamGeometry>
<StreamGeometry x:Key="Icons.Worktree.Add">M640 725 768 725 768 597 853 597 853 725 981 725 981 811 853 811 853 939 768 939 768 811 640 811 640 725M384 128C573 128 725 204 725 299 725 393 573 469 384 469 195 469 43 393 43 299 43 204 195 128 384 128M43 384C43 478 195 555 384 555 573 555 725 478 725 384L725 512 683 512 683 595C663 612 640 627 610 640L555 640 555 660C504 675 446 683 384 683 195 683 43 606 43 512L43 384M43 597C43 692 195 768 384 768 446 768 504 760 555 745L555 873C504 888 446 896 384 896 195 896 43 820 43 725L43 597Z</StreamGeometry> <StreamGeometry x:Key="Icons.Worktree.Add">M896 96 614 96c-58 0-128-19-179-51C422 38 390 19 358 19L262 19 128 19c-70 0-128 58-128 128l0 736c0 70 58 128 128 128l768 0c70 0 128-58 128-128L1024 224C1024 154 966 96 896 96zM704 685 544 685l0 160c0 19-13 32-32 32s-32-13-32-32l0-160L320 685c-19 0-32-13-32-32 0-19 13-32 32-32l160 0L480 461c0-19 13-32 32-32s32 13 32 32l0 160L704 621c19 0 32 13 32 32C736 666 723 685 704 685zM890 326 102 326 102 250c0-32 32-64 64-64l659 0c38 0 64 32 64 64L890 326z</StreamGeometry>
<StreamGeometry x:Key="Icons.Worktrees">M1182 527a91 91 0 00-88-117H92a91 91 0 00-88 117l137 441A80 80 0 00217 1024h752a80 80 0 0076-56zM133 295a31 31 0 0031 31h858a31 31 0 0031-31A93 93 0 00959 203H226a93 93 0 00-94 92zM359 123h467a31 31 0 0031-31A92 92 0 00765 0H421a92 92 0 00-92 92 31 31 0 0031 31z</StreamGeometry>
</ResourceDictionary> </ResourceDictionary>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -150,8 +150,8 @@
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String> <x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Arbeitsplätze</x:String> <x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Arbeitsplätze</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Name</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Farbe</x:String> <x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Farbe</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String> <x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String> <x:String x:Key="Text.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String> <x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>

View file

@ -149,8 +149,8 @@
<x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">User name for this repository</x:String> <x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">User name for this repository</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Workspaces</x:String> <x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Workspaces</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Name</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String> <x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restore tabs on startup</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Copy</x:String> <x:String x:Key="Text.Copy" xml:space="preserve">Copy</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Copy All Text</x:String> <x:String x:Key="Text.CopyAllText" xml:space="preserve">Copy All Text</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COPY MESSAGE</x:String> <x:String x:Key="Text.CopyMessage" xml:space="preserve">COPY MESSAGE</x:String>

View file

@ -0,0 +1,645 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="Text.About" xml:space="preserve">О программе</x:String>
<x:String x:Key="Text.About.Menu" xml:space="preserve">О SourceGit</x:String>
<x:String x:Key="Text.About.BuildWith" xml:space="preserve">• Сборка с </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">• Текстовый редактор от </x:String>
<x:String x:Key="Text.About.Fonts" xml:space="preserve">• Моноширинные шрифты взяты из </x:String>
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Исходный код можно найти по адресу </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Бесплатный графический клиент Git с исходным кодом</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Добавить рабочее дерево</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Что проверить:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Существующую ветку</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Создать новую ветку</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Расположение:</x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">Путь к этому рабочему дереву. Поддерживается относительный путью</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Имя ветки:</x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Необязательно. По умолчанию используется имя целевой папки.</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Отслеживание ветки:</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Отслеживание внешней ветки</x:String>
<x:String x:Key="Text.AIAssistant" xml:space="preserve">OpenAI Ассистент</x:String>
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Использовать OpenAI для создания сообщения о фиксации</x:String>
<x:String x:Key="Text.Apply" xml:space="preserve">Исправить </x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">Ошибка</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">Выдает ошибки и отказывается применять исправление</x:String>
<x:String x:Key="Text.Apply.ErrorAll" xml:space="preserve">Все ошибки</x:String>
<x:String x:Key="Text.Apply.ErrorAll.Desc" xml:space="preserve">Аналогично "ошибке", но показывает больше</x:String>
<x:String x:Key="Text.Apply.File" xml:space="preserve">Файл исправлений:</x:String>
<x:String x:Key="Text.Apply.File.Placeholder" xml:space="preserve">Выберите файл .patch для применения</x:String>
<x:String x:Key="Text.Apply.IgnoreWS" xml:space="preserve">Игнорировать изменения пробелов</x:String>
<x:String x:Key="Text.Apply.NoWarn" xml:space="preserve">Нет предупреждений</x:String>
<x:String x:Key="Text.Apply.NoWarn.Desc" xml:space="preserve">Отключает предупреждение о пробелах в конце</x:String>
<x:String x:Key="Text.Apply.Title" xml:space="preserve">Применить исправление</x:String>
<x:String x:Key="Text.Apply.Warn" xml:space="preserve">Предупреждение</x:String>
<x:String x:Key="Text.Apply.Warn.Desc" xml:space="preserve">Выдает предупреждения о нескольких таких ошибках, но применяет</x:String>
<x:String x:Key="Text.Apply.WS" xml:space="preserve">Пробел:</x:String>
<x:String x:Key="Text.Archive" xml:space="preserve">Архивировать...</x:String>
<x:String x:Key="Text.Archive.File" xml:space="preserve">Сохранить архив в:</x:String>
<x:String x:Key="Text.Archive.File.Placeholder" xml:space="preserve">Выберите путь к архивному файлу</x:String>
<x:String x:Key="Text.Archive.Revision" xml:space="preserve">Ревизия:</x:String>
<x:String x:Key="Text.Archive.Title" xml:space="preserve">Архив</x:String>
<x:String x:Key="Text.Askpass" xml:space="preserve">Спросить разрешения SourceGit</x:String>
<x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">ФАЙЛЫ СЧИТАЮТСЯ НЕИЗМЕНЕННЫМИ</x:String>
<x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">НИ ОДИН ФАЙЛ НЕ СЧИТАЕТСЯ НЕИЗМЕНЕННЫМ</x:String>
<x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">УДАЛИТЬ</x:String>
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">ДВОИЧНЫЙ ФАЙЛ НЕ ПОДДЕРЖИВАЕТСЯ!!!</x:String>
<x:String x:Key="Text.Blame" xml:space="preserve">Обвинение</x:String>
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">ОБВИНЕНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!!</x:String>
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Проверить ${0}$...</x:String>
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Сравнить в веткой</x:String>
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Сравнить в заголовком</x:String>
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Сравнить в рабочим деревом</x:String>
<x:String x:Key="Text.BranchCM.CopyName" xml:space="preserve">Копировать имя ветки</x:String>
<x:String x:Key="Text.BranchCM.Delete" xml:space="preserve">Удалить ${0}$...</x:String>
<x:String x:Key="Text.BranchCM.DeleteMultiBranches" xml:space="preserve">Удалить выбранные {0} ветки</x:String>
<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.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.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>
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">Установить отслеживание ветки</x:String>
<x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">Отключить основной поток</x:String>
<x:String x:Key="Text.BranchCompare" xml:space="preserve">Сравнение ветвей</x:String>
<x:String x:Key="Text.Bytes" xml:space="preserve">Байты</x:String>
<x:String x:Key="Text.Cancel" xml:space="preserve">ОТМЕНА</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Сбросить эту ревизию</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Сбросить родительскую ревизию</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">ИЗМЕНИТЬ РЕЖИМ ОТОБРАЖЕНИЯ</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Показывать в виде списка файлов и каталогов</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Показать в виде списка путей</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Показать в виде дерева файловой системы</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Проверить ветку</x:String>
<x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Проверить фиксацию</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Предупреждение: При выполнении проверки фиксации ваша голова будет отсоединена</x:String>
<x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Фиксация:</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Ветка:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Локальные изменения:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Отклонить</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Ничего не делать</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Отложить и примненить повторно</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve"> Частичный выбор</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Фиксация(и):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Фиксировать все изменения.</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Очистить отложенные</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Вы пытаетесь очистить все отложенные. Вы уверены, что будете продолжать?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Клонировать внешнее хранилище</x:String>
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">Расширенные параметры:</x:String>
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">Дополнительные аргументы для клонирования хранилища. Необязательно.</x:String>
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Локальное имя:</x:String>
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Имя хранилища. Необязательно.</x:String>
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Родительский каталог:</x:String>
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">Адрес хранилища:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">ЗАКРЫТЬ</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Редактор</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Выбрать из списка эту фиксацию</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Список выбора ...</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Проверить фиксацию</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Сравнить в заголовком</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Сравнить с рабочим деревом</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Копировать информацию</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Копировать SHA</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Интерактивное перемещение ${0}$ сюда</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Переместить ${0}$ сюда</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Сбросить ${0}$ сюда</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Вернуть фиксацию</x:String>
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Переформулировать</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Сохранить как исправление...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Уплотнить в родительскую</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Уплотнить дочерную фиксацию сюда</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">ИЗМЕНЕНИЯ</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Найти изменения....</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">ФАЙЛЫ</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">Файл ХБФ</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Подмодуль</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">ИНФОРМАЦИЯ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">АВТОР</x:String>
<x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">ИЗМЕНЁННЫЙ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">ФИКСАТОР</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn" xml:space="preserve">Проверить ссылки, содержащие эту фиксацию</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn.Title" xml:space="preserve">ФИКСАЦИЯ СОДЕРЖИТСЯ В</x:String>
<x:String x:Key="Text.CommitDetail.Info.GotoChangesPage" xml:space="preserve">Отображаются только первые 100 изменений. Смотрите все изменения на вкладке ИЗМЕНЕНИЯ.</x:String>
<x:String x:Key="Text.CommitDetail.Info.Message" xml:space="preserve">СООБЩЕНИЕ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">РОДИТЕЛИ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">ССЫЛКИ</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Открыть в браузере</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Введите тему фиксации</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Описание</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Настройка хранилища</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">ШАБЛОН ФИКСАЦИИ</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Имя шаблона:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Шаблон содержания:</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Адрес электронной почты</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Адрес электронной почты</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ОТСЛЕЖИВАНИЕ ПРОБЛЕМ</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Добавить пример правила для Git</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Добавить пример правила Jira</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Новое правило</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Проблема с регулярным выражением:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Имя правила:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Адрес результата:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Пожалуйста, используйте $1, $2 для доступа к значениям групп регулярных выражений.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP-прокси</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP-прокси, используемый этим хранилищем</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Имя пользовтаеля</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Имя пользователя для этого хранилища</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Рабочие пространства</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Имя</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Цвет</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Копировать</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Копировать весь текст</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">КОПИРОВАТЬ СООБЩЕНИЕ</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Копировать путь</x:String>
<x:String x:Key="Text.CopyFileName" xml:space="preserve">Копировать имя файла</x:String>
<x:String x:Key="Text.CreateBranch" xml:space="preserve">Создать ветку...</x:String>
<x:String x:Key="Text.CreateBranch.BasedOn" xml:space="preserve">Основан на:</x:String>
<x:String x:Key="Text.CreateBranch.Checkout" xml:space="preserve">Проверить созданную ветку</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges" xml:space="preserve">Локальные изменения:</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.Discard" xml:space="preserve">Отклонить</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.DoNothing" xml:space="preserve">Ничего не делать</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Отложить и применить повторно</x:String>
<x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">Имя новой ветки:</x:String>
<x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Ввести имя ветки.</x:String>
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Создать локальную ветку</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">Создать тег...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">Новый тег у:</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">Подпись GPG</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">Сообщение с тегом:</x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">Необязательно.</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">Имя тега:</x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">Рекомендуемый формат: v1.0.0-alpha</x:String>
<x:String x:Key="Text.CreateTag.PushToAllRemotes" xml:space="preserve">Выложить на все внешние хранилища после создания</x:String>
<x:String x:Key="Text.CreateTag.Title" xml:space="preserve">Создать новый тег</x:String>
<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.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>
<x:String x:Key="Text.DeleteBranch.IsRemoteTip" xml:space="preserve">Вы собираетесь удалить удаленную ветку!!!</x:String>
<x:String x:Key="Text.DeleteBranch.WithTrackingRemote" xml:space="preserve">Также удалите удаленную ветку ${0}$</x:String>
<x:String x:Key="Text.DeleteMultiBranch" xml:space="preserve">Удаление нескольких веток</x:String>
<x:String x:Key="Text.DeleteMultiBranch.Tip" xml:space="preserve">Вы пытаетесь удалить несколько веток одновременно. Обязательно перепроверьте, прежде чем предпринимать какие-либо действия!</x:String>
<x:String x:Key="Text.DeleteRemote" xml:space="preserve">Удалить внешнее хранилище</x:String>
<x:String x:Key="Text.DeleteRemote.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.Target" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForGroup" xml:space="preserve">Подтвердите удаление группы</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForRepository" xml:space="preserve">Подтвердите удаление хранилища</x:String>
<x:String x:Key="Text.DeleteSubmodule" xml:space="preserve">Удалить подмодуль</x:String>
<x:String x:Key="Text.DeleteSubmodule.Path" xml:space="preserve">Путь подмодуля:</x:String>
<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.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.LFS" 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.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.SyntaxHighlight" xml:space="preserve">Подсветка синтаксиса </x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Перенос слов в строке</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Открыть в инструменте слияния </x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Уменьшить количество видимых линий</x:String>
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Увеличить количество видимых линий</x:String>
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">ВЫБРАТЬ ФАЙЛ ДЛЯ ПРОСМОТРА ИЗМЕНЕНИЙ</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Показать скрытые символы</x:String>
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Обмен</x:String>
<x:String x:Key="Text.DiffWithMerger" xml:space="preserve">Открыть в инструменте слияния</x:String>
<x:String x:Key="Text.Discard" xml:space="preserve">Отклонить изменения</x:String>
<x:String x:Key="Text.Discard.All" xml:space="preserve">Все локальные изменения в рабочей копии.</x:String>
<x:String x:Key="Text.Discard.Changes" xml:space="preserve">Изменения:</x:String>
<x:String x:Key="Text.Discard.Total" xml:space="preserve">Всего {0} изменений будут отменены</x:String>
<x:String x:Key="Text.Discard.Warning" xml:space="preserve">Вы не можете отменить это действие!!!</x:String>
<x:String x:Key="Text.EditRepositoryNode.Bookmark" xml:space="preserve">Закладка:</x:String>
<x:String x:Key="Text.EditRepositoryNode.Name" xml:space="preserve">Новое имя:</x:String>
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Редактировать выбранную группу</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Редактировать выбранное хранилище</x:String>
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Быстрая перемотка вперёд (без проверки)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Извлечь</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Извлечь все внешние хранилища</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Извлечь без тегов</x:String>
<x:String x:Key="Text.Fetch.Prune" xml:space="preserve">Удалить внешние мёртвые ветки</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Извлечь внешние изменения</x:String>
<x:String x:Key="Text.FileCM.AssumeUnchanged" xml:space="preserve">Допустить без изменений</x:String>
<x:String x:Key="Text.FileCM.Discard" xml:space="preserve">Отклонить...</x:String>
<x:String x:Key="Text.FileCM.DiscardMulti" xml:space="preserve">Отклонить {0} файлов...</x:String>
<x:String x:Key="Text.FileCM.DiscardSelectedLines" xml:space="preserve">Отклонить изменения в выбранной(ых) строке(ах)</x:String>
<x:String x:Key="Text.FileCM.OpenWithExternalMerger" xml:space="preserve">Открыть расширенный инструмент слияния</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.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.UseTheirs" xml:space="preserve">Использовать их (checkout --theirs)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">Использовать мой (checkout --ours)</x:String>
<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>
<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.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.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.StartHotfix" 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.TagPrefix" xml:space="preserve">Префикс тега версии:</x:String>
<x:String x:Key="Text.GitLFS" xml:space="preserve">Git хранилища больших файлов</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern" xml:space="preserve">Добавить шаблон отслеживания...</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Шаблон — это имя файла</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Изменить шаблон:</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Добавить шаблон отслеживания в ХБФ Git</x:String>
<x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Извлечь</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Извлечь объекты ХБФ</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Запустите `git lfs fetch", чтобы загрузить объекты ХБФ Git. При этом рабочая копия не обновляется.</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Установить перехват ХБФ Git</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Показать блокировки</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Нет заблокированных файлов</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Блокировка</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">Блокировки ХБФ</x:String>
<x:String x:Key="Text.GitLFS.Locks.Unlock" xml:space="preserve">Разблокировка</x:String>
<x:String x:Key="Text.GitLFS.Locks.UnlockForce" xml:space="preserve">Принудительная разблокировка</x:String>
<x:String x:Key="Text.GitLFS.Prune" xml:space="preserve">Обрезка</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Запустите `git lfs prune", чтобы удалить старые файлы ХБФ из локального хранилища</x:String>
<x:String x:Key="Text.GitLFS.Pull" xml:space="preserve">Забрать</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Забрать объекты ХБФ</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Запустите `git lfs pull", чтобы загрузить все файлы ХБФ Git для текущей ссылки и проверить</x:String>
<x:String x:Key="Text.GitLFS.Push" xml:space="preserve">Выложить</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Выложить объекты ХБФ</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Отправляйте большие файлы, помещенные в очередь, в конечную точку ХБФ Git</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Отслеживать файлы с именем '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Отслеживать все *{0} файлов</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Истории</x:String>
<x:String x:Key="Text.Histories.DisplayMode" xml:space="preserve">Переключение горизонтального/вертикального расположения</x:String>
<x:String x:Key="Text.Histories.GraphMode" xml:space="preserve">Переключение режима построения кривой/полилинии</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">АВТОР</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">ГРАФ И СУБЪЕКТ</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">ВРЕМЯ ФИКСАЦИИ</x:String>
<x:String x:Key="Text.Histories.Search" xml:space="preserve">ПОИСК SHA/СУБЪЕКТ/АВТОР. НАЖМИТЕ ВВОД ДЛЯ ПОИСКА, ESC ДЛЯ ВЫХОДА</x:String>
<x:String x:Key="Text.Histories.SearchClear" xml:space="preserve">ОЧИСТИТЬ</x:String>
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">ВЫБРАННЫЕ {0} ФИКСАЦИИ</x:String>
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Ссылка на сочетания клавиш</x:String>
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">ОБЩЕЕ</x:String>
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Отменить текущее всплывающее окно</x:String>
<x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Закрыть текущее окно</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Перейти на предыдущую страницу</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Перейти на следующую страницу</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Создать новую страницу</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreference" 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.DiscardSelected" 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.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>
<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>
<x:String x:Key="Text.Hotkeys.TextEditor" xml:space="preserve">ТЕКСТОВЫЙ РЕДАКТОР</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.CloseSearch" xml:space="preserve">Закрыть панель поиска</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.GotoNextMatch" xml:space="preserve">Найти следующее совпадение</x:String>
<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.Stage" xml:space="preserve">Подготовить</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Снять из подготовленных</x:String>
<x:String x:Key="Text.Hunk.Discard" 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">Выполняется частичный забор. Нажмите 'Отбой' для восстановления заголовка.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Выполняет запрос слияния. Нажмите 'Отбой' для восстановления заголовка.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Выполняется перенос. Нажмите 'Отбой' для восстановления заголовка.</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Выполняется возврат. Нажмите 'Отбой' для восстановления заголовка.</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Интерактивное перемещение</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">целевая ветка:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">На:</x:String>
<x:String x:Key="Text.InteractiveRebase.MoveUp" xml:space="preserve">Вверх</x:String>
<x:String x:Key="Text.InteractiveRebase.MoveDown" xml:space="preserve">Вниз</x:String>
<x:String x:Key="Text.Launcher" xml:space="preserve">Source Git</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">ОШИБКА</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">УВЕДОМЛЕНИЕ</x:String>
<x:String x:Key="Text.Launcher.Menu" xml:space="preserve">Открыть главное меню</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Слить ветку</x:String>
<x:String x:Key="Text.Merge.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Опции слияния:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Исходная ветка:</x:String>
<x:String x:Key="Text.MoveRepositoryNode" xml:space="preserve">Переместить узел хранилища</x:String>
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Выбрать родительский узел для:</x:String>
<x:String x:Key="Text.Name" xml:space="preserve">Имя:</x:String>
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git НЕ был настроен. Пожалуйста, перейдите в [Настройки] и сначала настройте его.</x:String>
<x:String x:Key="Text.Notice" xml:space="preserve">УВЕДОМЛЕНИЕ</x:String>
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Открыть приложение каталогов данных</x:String>
<x:String x:Key="Text.OpenFolder" xml:space="preserve">ВЫБОР КАТАЛОГА</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Окрыть с...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Необязательно.</x:String>
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Создать новую страницу</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Закладка</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Закрыть вкладку</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Закрыть другие вкладки</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseRight" xml:space="preserve">Закрыть вкладки справа</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CopyPath" xml:space="preserve">Копировать путь хранилища</x:String>
<x:String x:Key="Text.PageTabBar.Welcome.Title" xml:space="preserve">Хранилища</x:String>
<x:String x:Key="Text.Paste" xml:space="preserve">Вставить</x:String>
<x:String x:Key="Text.Period.JustNow" xml:space="preserve">Сейчас</x:String>
<x:String x:Key="Text.Period.MinutesAgo" xml:space="preserve">{0} минут назад</x:String>
<x:String x:Key="Text.Period.HoursAgo" xml:space="preserve">{0} часов назад</x:String>
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Вчера</x:String>
<x:String x:Key="Text.Period.DaysAgo" xml:space="preserve">{0} дней назад</x:String>
<x:String x:Key="Text.Period.LastMonth" xml:space="preserve">Последний месяц</x:String>
<x:String x:Key="Text.Period.MonthsAgo" xml:space="preserve">{0} месяцев назад</x:String>
<x:String x:Key="Text.Period.LastYear" xml:space="preserve">В пролому году</x:String>
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">{0} лет назад</x:String>
<x:String x:Key="Text.Preference" xml:space="preserve">Параметры</x:String>
<x:String x:Key="Text.Preference.AI" xml:space="preserve">ОТКРЫТЬ ВИ</x:String>
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Сервер</x:String>
<x:String x:Key="Text.Preference.AI.ApiKey" xml:space="preserve">Ключ API</x:String>
<x:String x:Key="Text.Preference.AI.Model" 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.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>
<x:String x:Key="Text.Preference.Appearance.ThemeOverrides" xml:space="preserve">Переопределение темы</x:String>
<x:String x:Key="Text.Preference.Appearance.UseFixedTabWidth" xml:space="preserve">Использовать фиксированную ширину табуляции в строке заголовка.</x:String>
<x:String x:Key="Text.Preference.Appearance.UseNativeWindowFrame" xml:space="preserve">Использовать системное окно</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">Путь установки</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">Введите путь для инструмента различия/слияния</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">Инструмент</x:String>
<x:String x:Key="Text.Preference.General" xml:space="preserve">ГЛАВНЫЙ</x:String>
<x:String x:Key="Text.Preference.General.Check4UpdatesOnStartup" xml:space="preserve">Проверить обновления при старте</x:String>
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Язык</x:String>
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">История фиксаций</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Длина темы фиксации</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Автоматическое извлечение внешних хранилищ</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Интервал автоматического извлечения</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Минут(а/ы)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Включить автозавершение CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Каталог клонирования по-умолчанию</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Электроная почта пользователя</x:String>
<x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">Общая электроная почта пользователя git</x:String>
<x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">Путь установки</x:String>
<x:String x:Key="Text.Preference.Git.User" xml:space="preserve">Имя пользователя</x:String>
<x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">общее имя пользователя git</x:String>
<x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Версия Git</x:String>
<x:String x:Key="Text.Preference.Git.Invalid" xml:space="preserve">Git (>= 2.23.0) требуется для этого приложения</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">ПОДПИСЬ GPG</x:String>
<x:String x:Key="Text.Preference.GPG.CommitEnabled" xml:space="preserve">Фиксация подписи GPG</x:String>
<x:String x:Key="Text.Preference.GPG.TagEnabled" xml:space="preserve">Тег подписи GPG</x:String>
<x:String x:Key="Text.Preference.GPG.Format" xml:space="preserve">Формат GPG</x:String>
<x:String x:Key="Text.Preference.GPG.Path" xml:space="preserve">Путь установки программы</x:String>
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">Введите путь для установленной программы GPG</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">Ключ подписи пользователя</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">Ключ подписи GPG пользователя</x:String>
<x:String x:Key="Text.Preference.Integration" xml:space="preserve">ВНЕДРЕНИЕ</x:String>
<x:String x:Key="Text.Preference.Shell" xml:space="preserve">ОБОЛОЧКА/ТЕРМИНАЛ</x:String>
<x:String x:Key="Text.Preference.Shell.Type" xml:space="preserve">Оболочка/Терминал</x:String>
<x:String x:Key="Text.Preference.Shell.Path" xml:space="preserve">Путь</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Удалить внешнее хранилище</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Удалить рабочее дерево</x:String>
<x:String x:Key="Text.PruneWorktrees.Tip" xml:space="preserve">Информация об обрезке рабочего дерева в `$GIT_DIR/worktrees`</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Забрать</x:String>
<x:String x:Key="Text.Pull.Branch" xml:space="preserve">Ветка:</x:String>
<x:String x:Key="Text.Pull.FetchAllBranches" xml:space="preserve">Извлечь все ветки</x:String>
<x:String x:Key="Text.Pull.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.Pull.LocalChanges" xml:space="preserve">Локальные изменения:</x:String>
<x:String x:Key="Text.Pull.LocalChanges.Discard" xml:space="preserve">Отклонить</x:String>
<x:String x:Key="Text.Pull.LocalChanges.DoNothing" xml:space="preserve">Ничего не делать</x:String>
<x:String x:Key="Text.Pull.LocalChanges.StashAndReply" xml:space="preserve">Отложить и применить повторно</x:String>
<x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Забрать без тегов</x:String>
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.Pull.Title" xml:space="preserve">Забрать (Получить и слить)</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Использовать перемещение вместо слияния</x:String>
<x:String x:Key="Text.Push" xml:space="preserve">Выложить</x:String>
<x:String x:Key="Text.Push.CheckSubmodules" xml:space="preserve">Убедитесь, что подмодули были вставлены</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Принудительно выложить</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Локальная ветка:</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Выложить изменения на внешнее хранилище</x:String>
<x:String x:Key="Text.Push.To" xml:space="preserve">Ветка внешнего хранилища:</x:String>
<x:String x:Key="Text.Push.Tracking" xml:space="preserve">Установить в качестве ветки отслеживания</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Выложить все теги</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">Выложить тег на внешнее хранилище</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Выложить на все внешние хранилища</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Внешнее хранилище:</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Тег:</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Выйти</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Перемещение текущей ветки</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Отложить и применить повторно локальные изменения</x:String>
<x:String x:Key="Text.Rebase.On" xml:space="preserve">На:</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Переместить:</x:String>
<x:String x:Key="Text.RefetchAvatar" xml:space="preserve">Обновить</x:String>
<x:String x:Key="Text.Remote.AddTitle" xml:space="preserve">Добавить внешнее хранилище</x:String>
<x:String x:Key="Text.Remote.EditTitle" xml:space="preserve">Редактировать внешнее хранилище</x:String>
<x:String x:Key="Text.Remote.Name" xml:space="preserve">Имя:</x:String>
<x:String x:Key="Text.Remote.Name.Placeholder" xml:space="preserve">Имя внешнего хранилища</x:String>
<x:String x:Key="Text.Remote.URL" xml:space="preserve">Адрес хранилища:</x:String>
<x:String x:Key="Text.Remote.URL.Placeholder" xml:space="preserve">Адрес внешнего хранилища git</x:String>
<x:String x:Key="Text.RemoteCM.CopyURL" xml:space="preserve">Копировать адрес</x:String>
<x:String x:Key="Text.RemoteCM.Delete" xml:space="preserve">Удалить...</x:String>
<x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Редактировать...</x:String>
<x:String x:Key="Text.RemoteCM.Fetch" xml:space="preserve">Извлечь</x:String>
<x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Открыть в браузере</x:String>
<x:String x:Key="Text.RemoteCM.Prune" xml:space="preserve">Удалить</x:String>
<x:String x:Key="Text.RemoteCM.Prune.Target" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Подтвердить удаление рабочего дерева</x:String>
<x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Включить опцию `--force`</x:String>
<x:String x:Key="Text.RemoveWorktree.Target" xml:space="preserve">Цель:</x:String>
<x:String x:Key="Text.RenameBranch" xml:space="preserve">Переименовать ветку</x:String>
<x:String x:Key="Text.RenameBranch.Name" xml:space="preserve">Новое имя:</x:String>
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Уникальное имя для данной ветки</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Ветка:</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">ОТБОЙ</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Очистка (Сбор мусора и удаление) </x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Запустить команду `git gc` для данного хранилища.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Очистить всё</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Настройка этого хранилища</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">ПРОДОЛЖИТЬ</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.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>
<x:String x:Key="Text.Repository.NewBranch" xml:space="preserve">Создать ветку</x:String>
<x:String x:Key="Text.Repository.OpenIn" xml:space="preserve">Открыть в {0}</x:String>
<x:String x:Key="Text.Repository.OpenWithExternalTools" xml:space="preserve">Открыть в расширенном инструменте</x:String>
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Обновить</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">ВНЕШНИЕ ХРАНИЛИЩА</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ДОБАВИТЬ ВНЕШНЕЕ ХРАНИЛИЩЕ</x:String>
<x:String x:Key="Text.Repository.Resolve" xml:space="preserve">РАЗРЕШИТЬ</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Поиск фиксации</x:String>
<x:String x:Key="Text.Repository.Search.By" 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>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Автор и фиксатор</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Показать теги как дерево</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Статистики </x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">ПОДМОДУЛИ</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">ДОБАВИТЬ ПОДМОДУЛЬ</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">ОБНОВИТЬ ПОДМОДУЛЬ</x:String>
<x:String x:Key="Text.Repository.Tags" xml:space="preserve">ТЕГИ</x:String>
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">НОВЫЙ ТЕГ</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Открыть в терминале</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">РАБОЧИЕ ДЕРЕВЬЯ</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">ДОБАВИТЬ РАБОЧЕЕ ДЕРЕВО</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">ОБРЕЗКА</x:String>
<x:String x:Key="Text.RepositoryURL" xml:space="preserve">Адрес хранилища Git</x:String>
<x:String x:Key="Text.Reset" xml:space="preserve">Сбросить текущую втеку до версии</x:String>
<x:String x:Key="Text.Reset.Mode" xml:space="preserve">Режим сброса:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Переместить в:</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Текущая ветка:</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Раскрыть в файловом менеджере</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Отменить фиксацию</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">Фиксация:</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Отмена изменений фиксации</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">Переформулировать сообщение фиксации</x:String>
<x:String x:Key="Text.Reword.Tip" xml:space="preserve">Использовать "Shift+Enter" для ввода новой строки. "Enter" - это горячая клавиша кнопки OK</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">Запуск. Подождите пожалуйста...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">СОХРАНИТЬ</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Сохранить как...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Исправление успешно сохранено!</x:String>
<x:String x:Key="Text.ScanRepositories" xml:space="preserve">Сканирование хранилищ</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">Корневой каталог:</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">Проверка для обновления...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">Доступна новая версия этого программного обеспечения: </x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">Не удалось проверить наличие обновлений!</x:String>
<x:String x:Key="Text.SelfUpdate.GotoDownload" xml:space="preserve">Загрузка</x:String>
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Пропустить эту версию</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Обновление ПО</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">В настоящее время обновления недоступны.</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Уплотнить фиксации</x:String>
<x:String x:Key="Text.Squash.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">Частный ключ SSH:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Путь хранения частного ключа SSH</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">ЗАПУСК</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Отложить</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" 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.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>
<x:String x:Key="Text.StashCM.Pop" xml:space="preserve">Применить</x:String>
<x:String x:Key="Text.StashDropConfirm" xml:space="preserve">Отрбосить тайник</x:String>
<x:String x:Key="Text.StashDropConfirm.Label" xml:space="preserve">Отбросить:</x:String>
<x:String x:Key="Text.Stashes" xml:space="preserve">Отложенные</x:String>
<x:String x:Key="Text.Stashes.Changes" xml:space="preserve">ИЗМЕНЕНИЯ</x:String>
<x:String x:Key="Text.Stashes.Stashes" xml:space="preserve">ОТЛОЖЕННЫЕ</x:String>
<x:String x:Key="Text.Statistics" xml:space="preserve">Статистики</x:String>
<x:String x:Key="Text.Statistics.CommitAmount" xml:space="preserve">ФИКСАЦИИ</x:String>
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">ФИКСАТОРЫ</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">МЕСЯЦ</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">НЕДЕЛЯ</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">ГОД</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">ФИКСАЦИИ: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">АВТОРЫ: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">ПОДМОДУЛИ</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Добавить подмодули</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Копировать относительный путь</x:String>
<x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Извлечение вложенных подмодулей</x:String>
<x:String x:Key="Text.Submodule.Open" xml:space="preserve">Открыть подмодуль хранилища</x:String>
<x:String x:Key="Text.Submodule.RelativePath" xml:space="preserve">Относительный путь:</x:String>
<x:String x:Key="Text.Submodule.RelativePath.Placeholder" xml:space="preserve">Относительный каталог для хранения подмодуля.</x:String>
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">удалить подмодуль</x:String>
<x:String x:Key="Text.Sure" xml:space="preserve">ОК</x:String>
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Копировать имя тега</x:String>
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Удалить ${0}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Выложить ${0}$...</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">Сетевой адрес:</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Обновление подмодулей</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Все подмодули</x:String>
<x:String x:Key="Text.UpdateSubmodules.Init" xml:space="preserve">Инициализировать по необходимости</x:String>
<x:String x:Key="Text.UpdateSubmodules.Recursive" xml:space="preserve">Рекурсивно</x:String>
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Подмодуль:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Использовать опцию --remote</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">Предупреждение</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">Приветствие</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Создать группу</x:String>
<x:String x:Key="Text.Welcome.AddSubFolder" xml:space="preserve">Создать подгруппу</x:String>
<x:String x:Key="Text.Welcome.Clone" xml:space="preserve">Клонировать хранилище</x:String>
<x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Удалить</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">ПОДДЕРЖИВАЕТСЯ: ПЕРЕТАСКИВАНИЕ КАТАЛОГОВ, ПОЛЬЗОВАТЕЛЬСКАЯ ГРУППИРОВКА.</x:String>
<x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Редактировать</x:String>
<x:String x:Key="Text.Welcome.Move" xml:space="preserve">Перейти в другую группу</x:String>
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Открыть все хранилища</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Открыть хранилище</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">Открыть терминал</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">Повторное сканирование хранилищ в каталоге клонирования по-умолчанию</x:String>
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">Поиск хранилищ...</x:String>
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">Сортировка</x:String>
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">Изменения</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore" xml:space="preserve">Игнорировать Git</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.Extension" xml:space="preserve">Игнорировать все *{0} файлы</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">Игнорировать *{0} файлы в том же каталоге</x:String>
<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.AutoStage" 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">CTRL + Enter</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">ОБНАРУЖЕНЫ КОНФЛИКТЫ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">КОНФЛИКТЫ ФАЙЛОВ РАЗРЕШЕНЫ</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">ВКЛЮЧИТЬ НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">НЕТ ПОСЛЕДНИХ ВХОДНЫХ СООБЩЕНИЙ</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" 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.WorkingCopy.ResolveTip" xml:space="preserve">Щёлкните правой кнопкой мыши выбранный файл(ы) и сделайте свой выбор для разрешения конфликтов.</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">РАБОЧЕЕ ПРОСТРАНСТВО: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Настройка рабочего пространства...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">РАБОЧЕЕ ДЕРЕВО</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Копировать путь</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Заблокировать</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Удалить</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Разблокировать</x:String>
</ResourceDictionary>

View file

@ -152,8 +152,8 @@
<x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">应用于本仓库的用户名</x:String> <x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">应用于本仓库的用户名</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作区</x:String> <x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作区</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名称</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">颜色</x:String> <x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">颜色</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">启动时恢复打开的仓库</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">复制</x:String> <x:String x:Key="Text.Copy" xml:space="preserve">复制</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">复制全部文本</x:String> <x:String x:Key="Text.CopyAllText" xml:space="preserve">复制全部文本</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">复制内容</x:String> <x:String x:Key="Text.CopyMessage" xml:space="preserve">复制内容</x:String>

View file

@ -152,8 +152,8 @@
<x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">用於本存放庫的使用者名稱</x:String> <x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">用於本存放庫的使用者名稱</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作區</x:String> <x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作區</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名稱</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">顏色</x:String> <x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">顏色</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">啟動時還原上次開啟的存放庫</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">複製</x:String> <x:String x:Key="Text.Copy" xml:space="preserve">複製</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">複製全部內容</x:String> <x:String x:Key="Text.CopyAllText" xml:space="preserve">複製全部內容</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">複製內容</x:String> <x:String x:Key="Text.CopyMessage" xml:space="preserve">複製內容</x:String>

View file

@ -120,7 +120,7 @@ namespace SourceGit.ViewModels
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 isFiltered, bool bForceExpanded)
{ {
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal); var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
if (sepIdx == -1) if (sepIdx == -1 || branch.IsDetachedHead)
{ {
roots.Add(new BranchTreeNode() roots.Add(new BranchTreeNode()
{ {

View file

@ -36,10 +36,7 @@ namespace SourceGit.ViewModels
public void Add() public void Add()
{ {
var workspace = new Workspace(); var workspace = new Workspace() { Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}" };
workspace.Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
workspace.Color = 4278221015;
Preference.Instance.Workspaces.Add(workspace); Preference.Instance.Workspaces.Add(workspace);
Workspaces.Add(workspace); Workspaces.Add(workspace);
Selected = workspace; Selected = workspace;

View file

@ -113,11 +113,19 @@ namespace SourceGit.ViewModels
public void NavigateTo(string commitSHA) public void NavigateTo(string commitSHA)
{ {
var commit = _commits.Find(x => x.SHA.StartsWith(commitSHA, StringComparison.Ordinal)); var commit = _commits.Find(x => x.SHA.StartsWith(commitSHA, StringComparison.Ordinal));
if (commit != null) if (commit == null)
{
AutoSelectedCommit = null;
commit = new Commands.QuerySingleCommit(_repo.FullPath, commitSHA).Result();
}
else
{ {
AutoSelectedCommit = commit; AutoSelectedCommit = commit;
NavigationId = _navigationId + 1; NavigationId = _navigationId + 1;
}
if (commit != null)
{
if (_detailContext is CommitDetail detail) if (_detailContext is CommitDetail detail)
{ {
detail.Commit = commit; detail.Commit = commit;
@ -129,6 +137,10 @@ namespace SourceGit.ViewModels
DetailContext = commitDetail; DetailContext = commitDetail;
} }
} }
else
{
DetailContext = null;
}
} }
public void Select(IList commits) public void Select(IList commits)

View file

@ -81,7 +81,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
ActiveWorkspace = new Workspace() { Name = "Unnamed", Color = 4278221015 }; ActiveWorkspace = new Workspace() { Name = "Unnamed" };
foreach (var w in pref.Workspaces) foreach (var w in pref.Workspaces)
w.IsActive = false; w.IsActive = false;
@ -271,7 +271,7 @@ namespace SourceGit.ViewModels
repo.Open(); repo.Open();
ActiveWorkspace.AddRepository(repo.FullPath); ActiveWorkspace.AddRepository(repo.FullPath);
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath); Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir);
if (page == null) if (page == null)
{ {

View file

@ -18,32 +18,13 @@ namespace SourceGit.ViewModels
if (_instance == null) if (_instance == null)
{ {
_isLoading = true; _isLoading = true;
_instance = Load();
var path = Path.Combine(Native.OS.DataDir, "preference.json");
if (!File.Exists(path))
{
_instance = new Preference();
}
else
{
try
{
_instance = JsonSerializer.Deserialize(File.ReadAllText(path), JsonCodeGen.Default.Preference);
}
catch
{
_instance = new Preference();
}
}
_isLoading = false; _isLoading = false;
} }
if (!_instance.IsGitConfigured()) _instance.PrepareGit();
_instance.GitInstallPath = Native.OS.FindGitExecutable(); _instance.PrepareShellOrTerminal();
_instance.PrepareWorkspaces();
if (_instance.Workspaces.Count == 0)
_instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 });
return _instance; return _instance;
} }
} }
@ -498,6 +479,63 @@ namespace SourceGit.ViewModels
File.WriteAllText(file, data); File.WriteAllText(file, data);
} }
private static Preference Load()
{
var path = Path.Combine(Native.OS.DataDir, "preference.json");
if (!File.Exists(path))
return new Preference();
try
{
return JsonSerializer.Deserialize(File.ReadAllText(path), JsonCodeGen.Default.Preference);
}
catch
{
return new Preference();
}
}
private void PrepareGit()
{
var path = Native.OS.GitExecutable;
if (string.IsNullOrEmpty(path) || !File.Exists(path))
GitInstallPath = Native.OS.FindGitExecutable();
}
private void PrepareShellOrTerminal()
{
if (_shellOrTerminal >= 0)
return;
for (int i = 0; i < Models.ShellOrTerminal.Supported.Count; i++)
{
var shell = Models.ShellOrTerminal.Supported[i];
if (Native.OS.TestShellOrTerminal(shell))
{
ShellOrTerminal = i;
break;
}
}
}
private void PrepareWorkspaces()
{
if (Workspaces.Count == 0)
{
Workspaces.Add(new Workspace() { Name = "Default" });
return;
}
foreach (var workspace in Workspaces)
{
if (!workspace.RestoreOnStartup)
{
workspace.Repositories.Clear();
workspace.ActiveIdx = 0;
}
}
}
private RepositoryNode FindNodeRecursive(string id, List<RepositoryNode> collection) private RepositoryNode FindNodeRecursive(string id, List<RepositoryNode> collection)
{ {
foreach (var node in collection) foreach (var node in collection)
@ -536,7 +574,7 @@ namespace SourceGit.ViewModels
return true; return true;
} }
foreach (RepositoryNode one in collection) foreach (var one in collection)
{ {
if (RemoveNodeRecursive(node, one.SubNodes)) if (RemoveNodeRecursive(node, one.SubNodes))
return true; return true;

View file

@ -780,13 +780,9 @@ namespace SourceGit.ViewModels
foreach (var change in _selectedUnstaged) foreach (var change in _selectedUnstaged)
{ {
if (change.IsConflit) if (change.IsConflit)
{
hasConflicts = true; hasConflicts = true;
}
else else
{
hasNoneConflicts = true; hasNoneConflicts = true;
}
} }
if (hasConflicts) if (hasConflicts)
@ -1160,7 +1156,7 @@ namespace SourceGit.ViewModels
item.Icon = App.CreateMenuIcon("Icons.Code"); item.Icon = App.CreateMenuIcon("Icons.Code");
item.Click += (_, e) => item.Click += (_, e) =>
{ {
CommitMessage = template.Content; CommitMessage = template.Apply(_staged);
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(item); menu.Items.Add(item);

View file

@ -1,8 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization;
using Avalonia.Media; using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
@ -21,7 +18,7 @@ namespace SourceGit.ViewModels
set set
{ {
if (SetProperty(ref _color, value)) if (SetProperty(ref _color, value))
Brush = new SolidColorBrush(value); OnPropertyChanged(nameof(Brush));
} }
} }
@ -43,11 +40,15 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _isActive, value); set => SetProperty(ref _isActive, value);
} }
[JsonIgnore] public bool RestoreOnStartup
{
get => _restoreOnStartup;
set => SetProperty(ref _restoreOnStartup, value);
}
public IBrush Brush public IBrush Brush
{ {
get => _brush; get => new SolidColorBrush(_color);
private set => SetProperty(ref _brush, value);
} }
public void AddRepository(string repo) public void AddRepository(string repo)
@ -57,8 +58,8 @@ namespace SourceGit.ViewModels
} }
private string _name = string.Empty; private string _name = string.Empty;
private uint _color = 0; private uint _color = 4278221015;
private bool _isActive = false; private bool _isActive = false;
private IBrush _brush = null; private bool _restoreOnStartup = true;
} }
} }

View file

@ -33,7 +33,16 @@ namespace SourceGit.Views
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
if (e.Key != Key.Space) if (SelectedItems is [ViewModels.ChangeTreeNode { IsFolder: true } node] && e.KeyModifiers == KeyModifiers.None)
{
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
{
this.FindAncestorOfType<ChangeCollectionView>()?.ToggleNodeIsExpanded(node);
e.Handled = true;
}
}
if (!e.Handled && e.Key != Key.Space)
base.OnKeyDown(e); base.OnKeyDown(e);
} }
} }
@ -157,13 +166,11 @@ namespace SourceGit.Views
{ {
if (lastUnselected == -1) if (lastUnselected == -1)
continue; continue;
else
break; break;
}
else
{
lastUnselected = i;
} }
lastUnselected = i;
} }
} }
@ -179,13 +186,11 @@ namespace SourceGit.Views
{ {
if (lastUnselected == -1) if (lastUnselected == -1)
continue; continue;
else
break; break;
}
else
{
lastUnselected = i;
} }
lastUnselected = i;
} }
if (lastUnselected != -1) if (lastUnselected != -1)
@ -239,9 +244,9 @@ namespace SourceGit.Views
_disableSelectionChangingEvent = true; _disableSelectionChangingEvent = true;
var selected = new List<Models.Change>(); var selected = new List<Models.Change>();
if (sender is ListBox list) if (sender is ListBox { SelectedItems: {} selectedItems })
{ {
foreach (var item in list.SelectedItems) foreach (var item in selectedItems)
{ {
if (item is Models.Change c) if (item is Models.Change c)
selected.Add(c); selected.Add(c);

View file

@ -148,7 +148,7 @@ namespace SourceGit.Views
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new Size(256, 256); return new Size(256, 240);
} }
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerPressed(PointerPressedEventArgs e)

View file

@ -46,7 +46,7 @@
</Grid> </Grid>
<!-- BODY --> <!-- BODY -->
<Grid Grid.Row="1" ColumnDefinitions="200,16,256" Height="324" Margin="8"> <Grid Grid.Row="1" ColumnDefinitions="200,16,256" MinHeight="340" Margin="8">
<Border Grid.Column="0" <Border Grid.Column="0"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}"> Background="{DynamicResource Brush.Contents}">
@ -107,11 +107,12 @@
<ContentControl Grid.Column="2" Content="{Binding Selected}"> <ContentControl Grid.Column="2" Content="{Binding Selected}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>
<DataTemplate DataType="vm:Workspace"> <DataTemplate DataType="vm:Workspace">
<Grid RowDefinitions="Auto,Auto,Auto,Auto"> <Grid RowDefinitions="32,32,Auto,Auto">
<TextBlock Grid.Row="0" Text="{DynamicResource Text.ConfigureWorkspace.Name}"/> <TextBox Grid.Row="0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/>
<TextBox Grid.Row="1" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/> <CheckBox Grid.Row="1"
Content="{DynamicResource Text.ConfigureWorkspace.Restore}"
<TextBlock Grid.Row="2" Margin="0,12,0,4" Text="{DynamicResource Text.ConfigureWorkspace.Color}"/> IsChecked="{Binding RestoreOnStartup, Mode=TwoWay}"/>
<TextBlock Grid.Row="2" Margin="0,16,0,4" Text="{DynamicResource Text.ConfigureWorkspace.Color}"/>
<v:ColorPicker Grid.Row="3" HorizontalAlignment="Left" Value="{Binding Color, Mode=TwoWay}"/> <v:ColorPicker Grid.Row="3" HorizontalAlignment="Left" Value="{Binding Color, Mode=TwoWay}"/>
</Grid> </Grid>
</DataTemplate> </DataTemplate>

View file

@ -451,7 +451,7 @@ namespace SourceGit.Views
return; return;
// Calculate drawing area. // Calculate drawing area.
double width = Bounds.Width - 156 - 96 - histories.AuthorNameColumnWidth.Value; double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value;
double height = Bounds.Height; double height = Bounds.Height;
double startY = list.Scroll?.Offset.Y ?? 0; double startY = list.Scroll?.Offset.Y ?? 0;
double endY = startY + height + 28; double endY = startY + height + 28;

View file

@ -1,17 +1,7 @@
using System;
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Imaging;
namespace SourceGit.Views namespace SourceGit.Views
{ {
public partial class ImageDiffView : UserControl public partial class ImageDiffView : UserControl
{ {
public ImageDiffView() public ImageDiffView()

View file

@ -163,7 +163,10 @@
<Grid Grid.Row="2" x:Name="LeftSidebarGroups" Margin="0,4,0,0" RowDefinitions="28,Auto,28,Auto,28,Auto,28,Auto,28,Auto" SizeChanged="OnLeftSidebarSizeChanged"> <Grid Grid.Row="2" x:Name="LeftSidebarGroups" Margin="0,4,0,0" RowDefinitions="28,Auto,28,Auto,28,Auto,28,Auto,28,Auto" SizeChanged="OnLeftSidebarSizeChanged">
<!-- Local Branches --> <!-- Local Branches -->
<ToggleButton Grid.Row="0" Classes="group_expander" IsChecked="{Binding IsLocalBranchGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="0" Classes="group_expander" IsChecked="{Binding IsLocalBranchGroupExpanded, Mode=TwoWay}">
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.LocalBranches}"/> <Grid ColumnDefinitions="16,*">
<Path Grid.Column="0" Width="11" Height="11" HorizontalAlignment="Left" Data="{StaticResource Icons.Local}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Grid.Column="1" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.LocalBranches}"/>
</Grid>
</ToggleButton> </ToggleButton>
<v:BranchTree Grid.Row="1" <v:BranchTree Grid.Row="1"
x:Name="LocalBranchTree" x:Name="LocalBranchTree"
@ -176,9 +179,10 @@
<!-- Remotes --> <!-- Remotes -->
<ToggleButton Grid.Row="2" Classes="group_expander" IsChecked="{Binding IsRemoteGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="2" Classes="group_expander" IsChecked="{Binding IsRemoteGroupExpanded, Mode=TwoWay}">
<Grid ColumnDefinitions="*,Auto"> <Grid ColumnDefinitions="16,*,Auto">
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Remotes}"/> <Path Grid.Column="0" Width="12" Height="12" HorizontalAlignment="Left" Data="{StaticResource Icons.Remotes}" Fill="{DynamicResource Brush.FG2}"/>
<Button Grid.Column="1" Classes="icon_button" Width="14" Margin="8,0" Command="{Binding AddRemote}" ToolTip.Tip="{DynamicResource Text.Repository.Remotes.Add}"> <TextBlock Grid.Column="1" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Remotes}"/>
<Button Grid.Column="2" Classes="icon_button" Width="14" Margin="8,0" Command="{Binding AddRemote}" ToolTip.Tip="{DynamicResource Text.Repository.Remotes.Add}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Remote.Add}"/> <Path Width="12" Height="12" Data="{StaticResource Icons.Remote.Add}"/>
</Button> </Button>
</Grid> </Grid>
@ -194,15 +198,16 @@
<!-- Tags --> <!-- Tags -->
<ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}">
<Grid ColumnDefinitions="Auto,*,Auto,Auto"> <Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/> <Path Grid.Column="0" Width="11" Height="11" Margin="2,1,0,0" HorizontalAlignment="Left" Data="{StaticResource Icons.Tags}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Grid.Column="1" Text="{Binding Tags, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/> <TextBlock Grid.Column="1" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/>
<ToggleButton Grid.Column="2" <TextBlock Grid.Column="2" Text="{Binding Tags, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
<ToggleButton Grid.Column="3"
Classes="tag_display_mode" Classes="tag_display_mode"
Width="14" Width="14"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowTagsAsTree, Mode=TwoWay}" IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowTagsAsTree, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Repository.ShowTagsAsTree}"/> ToolTip.Tip="{DynamicResource Text.Repository.ShowTagsAsTree}"/>
<Button Grid.Column="3" <Button Grid.Column="4"
Classes="icon_button" Classes="icon_button"
Width="14" Width="14"
Margin="8,0" Margin="8,0"
@ -226,10 +231,11 @@
<!-- Submodules --> <!-- Submodules -->
<ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}">
<Grid ColumnDefinitions="Auto,*,Auto,Auto"> <Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Submodules}"/> <Path Grid.Column="0" Width="10" Height="10" Margin="2,0,0,0" HorizontalAlignment="Left" Data="{StaticResource Icons.Submodules}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Grid.Column="1" Text="{Binding Submodules, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/> <TextBlock Grid.Column="1" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Submodules}"/>
<Button Grid.Column="2" <TextBlock Grid.Column="2" Text="{Binding Submodules, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
<Button Grid.Column="3"
Classes="icon_button" Classes="icon_button"
Width="14" Width="14"
Margin="8,0" Margin="8,0"
@ -238,7 +244,7 @@
ToolTip.Tip="{DynamicResource Text.Repository.Submodules.Update}"> ToolTip.Tip="{DynamicResource Text.Repository.Submodules.Update}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/> <Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/>
</Button> </Button>
<Button Grid.Column="3" <Button Grid.Column="4"
Classes="icon_button" Classes="icon_button"
Width="14" Width="14"
Margin="0,0,8,0" Margin="0,0,8,0"
@ -281,10 +287,11 @@
<!-- Worktrees --> <!-- Worktrees -->
<ToggleButton Grid.Row="8" Classes="group_expander" IsChecked="{Binding IsWorktreeGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="8" Classes="group_expander" IsChecked="{Binding IsWorktreeGroupExpanded, Mode=TwoWay}">
<Grid ColumnDefinitions="Auto,*,Auto,Auto"> <Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Worktrees}"/> <Path Grid.Column="0" Width="11" Height="11" Margin="1,0,0,0" HorizontalAlignment="Left" Data="{StaticResource Icons.Worktrees}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Grid.Column="1" Text="{Binding Worktrees, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/> <TextBlock Grid.Column="1" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Worktrees}"/>
<Button Grid.Column="2" <TextBlock Grid.Column="2" Text="{Binding Worktrees, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
<Button Grid.Column="3"
Classes="icon_button" Classes="icon_button"
Width="14" Width="14"
Margin="8,0" Margin="8,0"
@ -293,13 +300,13 @@
ToolTip.Tip="{DynamicResource Text.Repository.Worktrees.Prune}"> ToolTip.Tip="{DynamicResource Text.Repository.Worktrees.Prune}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/> <Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/>
</Button> </Button>
<Button Grid.Column="3" <Button Grid.Column="4"
Classes="icon_button" Classes="icon_button"
Width="14" Width="14"
Margin="0,0,8,0" Margin="0,0,9,0"
Command="{Binding AddWorktree}" Command="{Binding AddWorktree}"
ToolTip.Tip="{DynamicResource Text.Repository.Worktrees.Add}"> ToolTip.Tip="{DynamicResource Text.Repository.Worktrees.Add}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Worktree.Add}"/> <Path Width="11" Height="11" Data="{StaticResource Icons.Worktree.Add}"/>
</Button> </Button>
</Grid> </Grid>
</ToggleButton> </ToggleButton>

View file

@ -8,12 +8,12 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.RevisionFileTreeView" x:Class="SourceGit.Views.RevisionFileTreeView"
x:Name="ThisControl"> x:Name="ThisControl">
<ListBox ItemsSource="{Binding #ThisControl.Rows}" <v:RevisionFileRowsListBox ItemsSource="{Binding #ThisControl.Rows}"
Background="Transparent" Background="Transparent"
SelectionMode="Single" SelectionMode="Single"
SelectionChanged="OnRowsSelectionChanged" SelectionChanged="OnRowsSelectionChanged"
ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"> ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/> <VirtualizingStackPanel Orientation="Vertical"/>
@ -46,5 +46,5 @@
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </v:RevisionFileRowsListBox>
</UserControl> </UserControl>

View file

@ -103,6 +103,26 @@ namespace SourceGit.Views
} }
} }
public class RevisionFileRowsListBox : ListBox
{
protected override Type StyleKeyOverride => typeof(ListBox);
protected override void OnKeyDown(KeyEventArgs e)
{
if (SelectedItem is ViewModels.RevisionFileTreeNode { IsFolder: true } node && e.KeyModifiers == KeyModifiers.None)
{
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
{
this.FindAncestorOfType<RevisionFileTreeView>()?.ToggleNodeIsExpanded(node);
e.Handled = true;
}
}
if (!e.Handled)
base.OnKeyDown(e);
}
}
public partial class RevisionFileTreeView : UserControl public partial class RevisionFileTreeView : UserControl
{ {
public static readonly StyledProperty<string> RevisionProperty = public static readonly StyledProperty<string> RevisionProperty =
@ -285,8 +305,8 @@ namespace SourceGit.Views
} }
} }
private List<ViewModels.RevisionFileTreeNode> _tree = new List<ViewModels.RevisionFileTreeNode>(); private List<ViewModels.RevisionFileTreeNode> _tree = [];
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = new AvaloniaList<ViewModels.RevisionFileTreeNode>(); private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
private bool _disableSelectionChangingEvent = false; private bool _disableSelectionChangingEvent = false;
} }
} }

View file

@ -45,7 +45,7 @@
IndicatorForeground="{DynamicResource Brush.FG2}" IndicatorForeground="{DynamicResource Brush.FG2}"
FontFamily="{DynamicResource Fonts.Monospace}" FontFamily="{DynamicResource Fonts.Monospace}"
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}" WordWrap="False"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}" ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}" EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/> SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
@ -65,7 +65,7 @@
IndicatorForeground="{DynamicResource Brush.FG2}" IndicatorForeground="{DynamicResource Brush.FG2}"
FontFamily="{DynamicResource Fonts.Monospace}" FontFamily="{DynamicResource Fonts.Monospace}"
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}" WordWrap="False"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}" ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}" EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/> SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>

View file

@ -519,7 +519,17 @@ namespace SourceGit.Views
private void OnTextViewPointerMoved(object sender, PointerEventArgs e) private void OnTextViewPointerMoved(object sender, PointerEventArgs e)
{ {
if (EnableChunkSelection && sender is TextView view) if (EnableChunkSelection && sender is TextView view)
{
var chunk = SelectedChunk;
if (chunk != null)
{
var rect = new Rect(0, chunk.Y, Bounds.Width, chunk.Height);
if (rect.Contains(e.GetPosition(this)))
return;
}
UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset); UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset);
}
} }
private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e) private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e)

View file

@ -45,18 +45,18 @@
</TextBox> </TextBox>
<!-- Repository Tree --> <!-- Repository Tree -->
<ListBox Grid.Row="1" <v:RepositoryListBox Grid.Row="1"
x:Name="TreeContainer" x:Name="TreeContainer"
Margin="0,8,8,0" Margin="0,8,8,0"
Focusable="True" Focusable="True"
Background="Transparent" Background="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Rows}" ItemsSource="{Binding Rows}"
SelectionMode="Single" SelectionMode="Single"
Loaded="SetupTreeViewDragAndDrop" Loaded="SetupTreeViewDragAndDrop"
LostFocus="OnTreeViewLostFocus" LostFocus="OnTreeViewLostFocus"
KeyDown="OnTreeViewKeyDown"> KeyDown="OnTreeViewKeyDown">
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBox"> <Style Selector="ListBox">
<Setter Property="FocusAdorner"> <Setter Property="FocusAdorner">
@ -140,12 +140,12 @@
Margin="8,0" Margin="8,0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Foreground="{DynamicResource Brush.FG2}" Foreground="{DynamicResource Brush.FG2}"
Text="{Binding Id}" Text="{Binding Id, Converter={x:Static c:PathConverters.RelativeToHome}}"
IsVisible="{Binding IsRepository}"/> IsVisible="{Binding IsRepository}"/>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </v:RepositoryListBox>
</Grid> </Grid>
</Grid> </Grid>

View file

@ -25,6 +25,26 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
} }
public class RepositoryListBox : ListBox
{
protected override Type StyleKeyOverride => typeof(ListBox);
protected override void OnKeyDown(KeyEventArgs e)
{
if (SelectedItem is ViewModels.RepositoryNode { IsRepository: false } node && e.KeyModifiers == KeyModifiers.None)
{
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
{
ViewModels.Welcome.Instance.ToggleNodeIsExpanded(node);
e.Handled = true;
}
}
if (!e.Handled)
base.OnKeyDown(e);
}
}
public partial class Welcome : UserControl public partial class Welcome : UserControl
{ {