mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-06-25 20:34:59 +00:00
Merge branch 'sourcegit-scm:develop' into develop
This commit is contained in:
commit
1906be5a8c
47 changed files with 3728 additions and 266 deletions
|
@ -7,7 +7,7 @@ Opensource Git GUI client.
|
|||
* Supports Windows/macOS/Linux
|
||||
* Opensource/Free
|
||||
* Fast
|
||||
* English/Français/Deutsch/Português/简体中文/繁體中文
|
||||
* English/Français/Deutsch/Português/Русский/简体中文/繁體中文
|
||||
* Built-in light/dark themes
|
||||
* Customize theme
|
||||
* Visual commit graph
|
||||
|
@ -97,7 +97,7 @@ For `OpenAI`:
|
|||
|
||||
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
|
||||
|
||||
## External Tools
|
||||
|
@ -111,6 +111,7 @@ This app supports open repository in external tools listed in the table below.
|
|||
| VSCodium | YES | YES | YES | VSCODIUM |
|
||||
| JetBrains Fleet | YES | YES | YES | FLEET |
|
||||
| Sublime Text | YES | YES | YES | SUBLIME_TEXT |
|
||||
| Zed | NO | YES | YES | ZED |
|
||||
|
||||
> [!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.
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.30.1
|
||||
8.31
|
|
@ -1,13 +1,16 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o
|
||||
set -u
|
||||
set pipefail
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "Provide the version as environment variable VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RUNTIME" ]; then
|
||||
if [[ -z "$RUNTIME" ]]; then
|
||||
echo "Provide the runtime as environment variable RUNTIME"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -33,7 +36,7 @@ APPIMAGETOOL_URL=https://github.com/AppImage/appimagetool/releases/download/cont
|
|||
|
||||
cd build
|
||||
|
||||
if [ ! -f "appimagetool" ]; then
|
||||
if [[ ! -f "appimagetool" ]]; then
|
||||
curl -o appimagetool -L "$APPIMAGETOOL_URL"
|
||||
chmod +x appimagetool
|
||||
fi
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o
|
||||
set -u
|
||||
set pipefail
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "Provide the version as environment variable VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RUNTIME" ]; then
|
||||
if [[ -z "$RUNTIME" ]]; then
|
||||
echo "Provide the runtime as environment variable RUNTIME"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o
|
||||
set -u
|
||||
set pipefail
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "Provide the version as environment variable VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RUNTIME" ]; then
|
||||
if [[ -z "$RUNTIME" ]]; then
|
||||
echo "Provide the runtime as environment variable RUNTIME"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -521,6 +521,9 @@ namespace SourceGit
|
|||
return false;
|
||||
|
||||
var param = args[0];
|
||||
if (Directory.Exists(param))
|
||||
return false;
|
||||
|
||||
if (!param.StartsWith("enter passphrase", StringComparison.OrdinalIgnoreCase) &&
|
||||
!param.Contains(" password", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
|
|
@ -59,9 +59,14 @@ namespace SourceGit.Commands
|
|||
|
||||
// If an SSH private key was provided, sets the environment.
|
||||
if (!string.IsNullOrEmpty(SSHKey))
|
||||
{
|
||||
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new");
|
||||
start.Arguments += "-c credential.helper=manager ";
|
||||
}
|
||||
|
||||
// Force using en_US.UTF-8 locale to avoid GCM crash
|
||||
if (OperatingSystem.IsLinux())
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
|
@ -7,9 +8,23 @@ namespace SourceGit.Converters
|
|||
public static class PathConverters
|
||||
{
|
||||
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 =
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -20,6 +21,7 @@ namespace SourceGit.Models
|
|||
|
||||
public class Job
|
||||
{
|
||||
public string IndexLockFile = string.Empty;
|
||||
public Commands.Fetch Cmd = null;
|
||||
public DateTime NextRunTimepoint = DateTime.MinValue;
|
||||
}
|
||||
|
@ -74,10 +76,13 @@ namespace SourceGit.Models
|
|||
}
|
||||
|
||||
foreach (var job in uptodate)
|
||||
{
|
||||
if (!File.Exists(job.IndexLockFile))
|
||||
{
|
||||
job.Cmd.Exec();
|
||||
job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
IndexLockFile = Path.Combine(gitDir, "index.lock"),
|
||||
Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false },
|
||||
NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)),
|
||||
};
|
||||
|
|
|
@ -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
|
||||
{
|
||||
public class CommitTemplate : ObservableObject
|
||||
public partial class CommitTemplate : ObservableObject
|
||||
{
|
||||
[GeneratedRegex(@"\$\{files(\:\d+)?\}")]
|
||||
private static partial Regex REG_COMMIT_TEMPLATE_FILES();
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
|
@ -16,6 +24,56 @@ namespace SourceGit.Models
|
|||
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 _content = string.Empty;
|
||||
}
|
||||
|
|
|
@ -149,6 +149,11 @@ namespace SourceGit.Models
|
|||
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)
|
||||
{
|
||||
var exclude = new List<string> { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" };
|
||||
|
|
|
@ -54,6 +54,8 @@ namespace SourceGit.Models
|
|||
new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"),
|
||||
new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"),
|
||||
new ShellOrTerminal("foot", "Foot", "foot"),
|
||||
new ShellOrTerminal("wezterm", "WezTerm", "wezterm"),
|
||||
new ShellOrTerminal("custom", "Custom", ""),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,94 +17,92 @@ using TextMateSharp.Themes;
|
|||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class RegistryOptionsWrapper : IRegistryOptions
|
||||
public static class GrammarUtility
|
||||
{
|
||||
public RegistryOptionsWrapper(ThemeName defaultTheme)
|
||||
{
|
||||
_backend = new RegistryOptions(defaultTheme);
|
||||
_extraGrammars = new List<IRawGrammar>();
|
||||
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"),
|
||||
];
|
||||
|
||||
string[] extraGrammarFiles = ["toml.json"];
|
||||
foreach (var file in extraGrammarFiles)
|
||||
public static string GetScope(string file, RegistryOptions reg)
|
||||
{
|
||||
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();
|
||||
|
||||
var extension = Path.GetExtension(file);
|
||||
if (extension == ".h")
|
||||
extension = ".cpp";
|
||||
else if (extension == ".resx" || extension == ".plist" || extension == ".manifest")
|
||||
extension = ".xml";
|
||||
else if (extension == ".command")
|
||||
extension = ".sh";
|
||||
else if (extension == ".kt" || extension == ".kts")
|
||||
extension = ".kotlin";
|
||||
|
||||
return _backend.GetScopeByExtension(extension);
|
||||
foreach (var grammar in s_extraGrammars)
|
||||
{
|
||||
if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
|
||||
return grammar.Scope;
|
||||
}
|
||||
|
||||
private readonly RegistryOptions _backend;
|
||||
private readonly List<IRawGrammar> _extraGrammars;
|
||||
return reg.GetScopeByExtension(extension);
|
||||
}
|
||||
|
||||
public static IRawGrammar GetGrammar(string scopeName, RegistryOptions reg)
|
||||
{
|
||||
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 TextMate.Installation CreateForEditor(TextEditor editor)
|
||||
{
|
||||
if (Application.Current?.ActualThemeVariant == ThemeVariant.Dark)
|
||||
return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.DarkPlus));
|
||||
|
||||
return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.LightPlus));
|
||||
return editor.InstallTextMate(Application.Current?.ActualThemeVariant == ThemeVariant.Dark ?
|
||||
new RegistryOptionsWrapper(ThemeName.DarkPlus) :
|
||||
new RegistryOptionsWrapper(ThemeName.LightPlus));
|
||||
}
|
||||
|
||||
public static void SetThemeByApp(TextMate.Installation installation)
|
||||
{
|
||||
if (installation == null)
|
||||
return;
|
||||
|
||||
if (installation.RegistryOptions is RegistryOptionsWrapper reg)
|
||||
if (installation is { RegistryOptions: RegistryOptionsWrapper reg })
|
||||
{
|
||||
var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark;
|
||||
installation.SetTheme(reg.LoadTheme(isDark ? ThemeName.DarkPlus : ThemeName.LightPlus));
|
||||
|
@ -115,7 +113,7 @@ namespace SourceGit.Models
|
|||
{
|
||||
if (installation is { RegistryOptions: RegistryOptionsWrapper reg })
|
||||
{
|
||||
installation.SetGrammar(reg.GetScopeByFileName(filePath));
|
||||
installation.SetGrammar(reg.GetScope(filePath));
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,16 +26,10 @@ namespace SourceGit.Native
|
|||
|
||||
public string FindTerminal(Models.ShellOrTerminal shell)
|
||||
{
|
||||
var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
|
||||
var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var path in pathes)
|
||||
{
|
||||
var test = Path.Combine(path, shell.Exec);
|
||||
if (File.Exists(test))
|
||||
return test;
|
||||
}
|
||||
|
||||
if (shell.Type.Equals("custom", StringComparison.Ordinal))
|
||||
return string.Empty;
|
||||
|
||||
return FindExecutable(shell.Exec);
|
||||
}
|
||||
|
||||
public List<Models.ExternalTool> FindExternalTools()
|
||||
|
@ -47,6 +41,7 @@ namespace SourceGit.Native
|
|||
finder.Fleet(FindJetBrainsFleet);
|
||||
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox");
|
||||
finder.SublimeText(() => FindExecutable("subl"));
|
||||
finder.Zed(() => FindExecutable("zeditor"));
|
||||
return finder.Founded;
|
||||
}
|
||||
|
||||
|
@ -71,17 +66,25 @@ namespace SourceGit.Native
|
|||
|
||||
public void OpenTerminal(string workdir)
|
||||
{
|
||||
if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal))
|
||||
{
|
||||
App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured.");
|
||||
return;
|
||||
}
|
||||
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
|
||||
|
||||
var startInfo = new ProcessStartInfo();
|
||||
startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? "~" : workdir;
|
||||
startInfo.WorkingDirectory = cwd;
|
||||
startInfo.FileName = OS.ShellOrTerminal;
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace SourceGit.Native
|
|||
return "iTerm";
|
||||
}
|
||||
|
||||
return "InvalidTerminal";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
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.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Application Support/JetBrains/Toolbox");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,12 +74,17 @@ namespace SourceGit.Native
|
|||
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;
|
||||
else
|
||||
ShellOrTerminal = _backend.FindTerminal(shellOrTerminal);
|
||||
ShellOrTerminal = _backend.FindTerminal(shell);
|
||||
}
|
||||
|
||||
public static void OpenInFileManager(string path, bool select = false)
|
||||
|
@ -95,7 +100,7 @@ namespace SourceGit.Native
|
|||
public static void OpenTerminal(string workdir)
|
||||
{
|
||||
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
|
||||
_backend.OpenTerminal(workdir);
|
||||
}
|
||||
|
|
|
@ -26,23 +26,11 @@ namespace SourceGit.Native
|
|||
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")]
|
||||
private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
private static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
|
||||
private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
|
||||
private static extern IntPtr ILCreateFromPathW(string pszPath);
|
||||
|
@ -60,8 +48,8 @@ namespace SourceGit.Native
|
|||
v.dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOEX>();
|
||||
if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000))
|
||||
{
|
||||
Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w));
|
||||
Control.LoadedEvent.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w));
|
||||
Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, _) => FixWindowFrameOnWin10(w));
|
||||
Control.LoadedEvent.AddClassHandler<Window>((w, _) => FixWindowFrameOnWin10(w));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,15 +146,20 @@ namespace SourceGit.Native
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo();
|
||||
startInfo.WorkingDirectory = workdir;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -206,14 +199,12 @@ namespace SourceGit.Native
|
|||
Process.Start(start);
|
||||
}
|
||||
|
||||
private void ExtendWindowFrame(Window w)
|
||||
private void FixWindowFrameOnWin10(Window w)
|
||||
{
|
||||
var platformHandle = w.TryGetPlatformHandle();
|
||||
if (platformHandle == null)
|
||||
return;
|
||||
|
||||
var margins = new MARGINS { cxLeftWidth = 1, cxRightWidth = 1, cyTopHeight = 1, cyBottomHeight = 1 };
|
||||
DwmExtendFrameIntoClientArea(platformHandle.Handle, ref margins);
|
||||
if (w.WindowState == WindowState.Maximized || w.WindowState == WindowState.FullScreen)
|
||||
w.SystemDecorations = SystemDecorations.Full;
|
||||
else if (w.WindowState == WindowState.Normal)
|
||||
w.SystemDecorations = SystemDecorations.BorderOnly;
|
||||
}
|
||||
|
||||
#region EXTERNAL_EDITOR_FINDER
|
||||
|
|
2488
src/Resources/Grammars/haxe.json
Normal file
2488
src/Resources/Grammars/haxe.json
Normal file
File diff suppressed because it is too large
Load diff
70
src/Resources/Grammars/hxml.json
Normal file
70
src/Resources/Grammars/hxml.json
Normal 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"
|
||||
}
|
701
src/Resources/Grammars/kotlin.json
Normal file
701
src/Resources/Grammars/kotlin.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.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.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.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>
|
||||
|
@ -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.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.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.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.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.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>
|
||||
|
@ -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.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.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.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">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">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>
|
||||
|
|
BIN
src/Resources/Images/ExternalToolIcons/zed.png
Normal file
BIN
src/Resources/Images/ExternalToolIcons/zed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
src/Resources/Images/ShellIcons/custom.png
Normal file
BIN
src/Resources/Images/ShellIcons/custom.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
src/Resources/Images/ShellIcons/wezterm.png
Normal file
BIN
src/Resources/Images/ShellIcons/wezterm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
|
@ -150,8 +150,8 @@
|
|||
<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.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.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.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String>
|
||||
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>
|
||||
|
|
|
@ -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.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.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.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.CopyAllText" xml:space="preserve">Copy All Text</x:String>
|
||||
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COPY MESSAGE</x:String>
|
||||
|
|
|
@ -152,8 +152,8 @@
|
|||
<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.ConfigureWorkspace.Restore" 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>
|
||||
|
|
|
@ -152,8 +152,8 @@
|
|||
<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.ConfigureWorkspace.Restore" 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>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal);
|
||||
if (sepIdx == -1)
|
||||
if (sepIdx == -1 || branch.IsDetachedHead)
|
||||
{
|
||||
roots.Add(new BranchTreeNode()
|
||||
{
|
||||
|
|
|
@ -36,10 +36,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public void Add()
|
||||
{
|
||||
var workspace = new Workspace();
|
||||
workspace.Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
|
||||
workspace.Color = 4278221015;
|
||||
|
||||
var workspace = new Workspace() { Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}" };
|
||||
Preference.Instance.Workspaces.Add(workspace);
|
||||
Workspaces.Add(workspace);
|
||||
Selected = workspace;
|
||||
|
|
|
@ -113,11 +113,19 @@ namespace SourceGit.ViewModels
|
|||
public void NavigateTo(string commitSHA)
|
||||
{
|
||||
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;
|
||||
NavigationId = _navigationId + 1;
|
||||
}
|
||||
|
||||
if (commit != null)
|
||||
{
|
||||
if (_detailContext is CommitDetail detail)
|
||||
{
|
||||
detail.Commit = commit;
|
||||
|
@ -129,6 +137,10 @@ namespace SourceGit.ViewModels
|
|||
DetailContext = commitDetail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DetailContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Select(IList commits)
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
else
|
||||
{
|
||||
ActiveWorkspace = new Workspace() { Name = "Unnamed", Color = 4278221015 };
|
||||
ActiveWorkspace = new Workspace() { Name = "Unnamed" };
|
||||
|
||||
foreach (var w in pref.Workspaces)
|
||||
w.IsActive = false;
|
||||
|
@ -271,7 +271,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
repo.Open();
|
||||
ActiveWorkspace.AddRepository(repo.FullPath);
|
||||
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath);
|
||||
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir);
|
||||
|
||||
if (page == null)
|
||||
{
|
||||
|
|
|
@ -18,32 +18,13 @@ namespace SourceGit.ViewModels
|
|||
if (_instance == null)
|
||||
{
|
||||
_isLoading = true;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
_instance = Load();
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
if (!_instance.IsGitConfigured())
|
||||
_instance.GitInstallPath = Native.OS.FindGitExecutable();
|
||||
|
||||
if (_instance.Workspaces.Count == 0)
|
||||
_instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 });
|
||||
|
||||
_instance.PrepareGit();
|
||||
_instance.PrepareShellOrTerminal();
|
||||
_instance.PrepareWorkspaces();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
@ -498,6 +479,63 @@ namespace SourceGit.ViewModels
|
|||
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)
|
||||
{
|
||||
foreach (var node in collection)
|
||||
|
@ -536,7 +574,7 @@ namespace SourceGit.ViewModels
|
|||
return true;
|
||||
}
|
||||
|
||||
foreach (RepositoryNode one in collection)
|
||||
foreach (var one in collection)
|
||||
{
|
||||
if (RemoveNodeRecursive(node, one.SubNodes))
|
||||
return true;
|
||||
|
|
|
@ -780,14 +780,10 @@ namespace SourceGit.ViewModels
|
|||
foreach (var change in _selectedUnstaged)
|
||||
{
|
||||
if (change.IsConflit)
|
||||
{
|
||||
hasConflicts = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasNoneConflicts = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasConflicts)
|
||||
{
|
||||
|
@ -1160,7 +1156,7 @@ namespace SourceGit.ViewModels
|
|||
item.Icon = App.CreateMenuIcon("Icons.Code");
|
||||
item.Click += (_, e) =>
|
||||
{
|
||||
CommitMessage = template.Content;
|
||||
CommitMessage = template.Apply(_staged);
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(item);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Avalonia.Media;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
|
@ -21,7 +18,7 @@ namespace SourceGit.ViewModels
|
|||
set
|
||||
{
|
||||
if (SetProperty(ref _color, value))
|
||||
Brush = new SolidColorBrush(value);
|
||||
OnPropertyChanged(nameof(Brush));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,11 +40,15 @@ namespace SourceGit.ViewModels
|
|||
set => SetProperty(ref _isActive, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool RestoreOnStartup
|
||||
{
|
||||
get => _restoreOnStartup;
|
||||
set => SetProperty(ref _restoreOnStartup, value);
|
||||
}
|
||||
|
||||
public IBrush Brush
|
||||
{
|
||||
get => _brush;
|
||||
private set => SetProperty(ref _brush, value);
|
||||
get => new SolidColorBrush(_color);
|
||||
}
|
||||
|
||||
public void AddRepository(string repo)
|
||||
|
@ -57,8 +58,8 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
|
||||
private string _name = string.Empty;
|
||||
private uint _color = 0;
|
||||
private uint _color = 4278221015;
|
||||
private bool _isActive = false;
|
||||
private IBrush _brush = null;
|
||||
private bool _restoreOnStartup = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,16 @@ namespace SourceGit.Views
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -157,15 +166,13 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (lastUnselected == -1)
|
||||
continue;
|
||||
else
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
lastUnselected = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastUnselected != -1)
|
||||
return tree.Rows[lastUnselected].Change;
|
||||
|
@ -179,14 +186,12 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (lastUnselected == -1)
|
||||
continue;
|
||||
else
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
lastUnselected = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastUnselected != -1)
|
||||
return changes[lastUnselected];
|
||||
|
@ -239,9 +244,9 @@ namespace SourceGit.Views
|
|||
_disableSelectionChangingEvent = true;
|
||||
|
||||
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)
|
||||
selected.Add(c);
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace SourceGit.Views
|
|||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return new Size(256, 256);
|
||||
return new Size(256, 240);
|
||||
}
|
||||
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- 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"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="{DynamicResource Brush.Contents}">
|
||||
|
@ -107,11 +107,12 @@
|
|||
<ContentControl Grid.Column="2" Content="{Binding Selected}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:Workspace">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
<TextBlock Grid.Row="0" Text="{DynamicResource Text.ConfigureWorkspace.Name}"/>
|
||||
<TextBox Grid.Row="1" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Margin="0,12,0,4" Text="{DynamicResource Text.ConfigureWorkspace.Color}"/>
|
||||
<Grid RowDefinitions="32,32,Auto,Auto">
|
||||
<TextBox Grid.Row="0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/>
|
||||
<CheckBox Grid.Row="1"
|
||||
Content="{DynamicResource Text.ConfigureWorkspace.Restore}"
|
||||
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}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
|
|
@ -451,7 +451,7 @@ namespace SourceGit.Views
|
|||
return;
|
||||
|
||||
// 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 startY = list.Scroll?.Offset.Y ?? 0;
|
||||
double endY = startY + height + 28;
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
public partial class ImageDiffView : UserControl
|
||||
{
|
||||
public ImageDiffView()
|
||||
|
|
|
@ -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">
|
||||
<!-- Local Branches -->
|
||||
<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>
|
||||
<v:BranchTree Grid.Row="1"
|
||||
x:Name="LocalBranchTree"
|
||||
|
@ -176,9 +179,10 @@
|
|||
|
||||
<!-- Remotes -->
|
||||
<ToggleButton Grid.Row="2" Classes="group_expander" IsChecked="{Binding IsRemoteGroupExpanded, Mode=TwoWay}">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Remotes}"/>
|
||||
<Button Grid.Column="1" Classes="icon_button" Width="14" Margin="8,0" Command="{Binding AddRemote}" ToolTip.Tip="{DynamicResource Text.Repository.Remotes.Add}">
|
||||
<Grid ColumnDefinitions="16,*,Auto">
|
||||
<Path Grid.Column="0" Width="12" Height="12" HorizontalAlignment="Left" Data="{StaticResource Icons.Remotes}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<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}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
@ -194,15 +198,16 @@
|
|||
|
||||
<!-- Tags -->
|
||||
<ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Tags, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
|
||||
<ToggleButton Grid.Column="2"
|
||||
<Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
|
||||
<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" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/>
|
||||
<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"
|
||||
Width="14"
|
||||
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowTagsAsTree, Mode=TwoWay}"
|
||||
ToolTip.Tip="{DynamicResource Text.Repository.ShowTagsAsTree}"/>
|
||||
<Button Grid.Column="3"
|
||||
<Button Grid.Column="4"
|
||||
Classes="icon_button"
|
||||
Width="14"
|
||||
Margin="8,0"
|
||||
|
@ -226,10 +231,11 @@
|
|||
|
||||
<!-- Submodules -->
|
||||
<ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Submodules}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Submodules, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
|
||||
<Button Grid.Column="2"
|
||||
<Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
|
||||
<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" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Submodules}"/>
|
||||
<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"
|
||||
Width="14"
|
||||
Margin="8,0"
|
||||
|
@ -238,7 +244,7 @@
|
|||
ToolTip.Tip="{DynamicResource Text.Repository.Submodules.Update}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/>
|
||||
</Button>
|
||||
<Button Grid.Column="3"
|
||||
<Button Grid.Column="4"
|
||||
Classes="icon_button"
|
||||
Width="14"
|
||||
Margin="0,0,8,0"
|
||||
|
@ -281,10 +287,11 @@
|
|||
|
||||
<!-- Worktrees -->
|
||||
<ToggleButton Grid.Row="8" Classes="group_expander" IsChecked="{Binding IsWorktreeGroupExpanded, Mode=TwoWay}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Worktrees}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Worktrees, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
|
||||
<Button Grid.Column="2"
|
||||
<Grid ColumnDefinitions="16,Auto,*,Auto,Auto">
|
||||
<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" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Worktrees}"/>
|
||||
<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"
|
||||
Width="14"
|
||||
Margin="8,0"
|
||||
|
@ -293,13 +300,13 @@
|
|||
ToolTip.Tip="{DynamicResource Text.Repository.Worktrees.Prune}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Loading}"/>
|
||||
</Button>
|
||||
<Button Grid.Column="3"
|
||||
<Button Grid.Column="4"
|
||||
Classes="icon_button"
|
||||
Width="14"
|
||||
Margin="0,0,8,0"
|
||||
Margin="0,0,9,0"
|
||||
Command="{Binding AddWorktree}"
|
||||
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>
|
||||
</Grid>
|
||||
</ToggleButton>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.RevisionFileTreeView"
|
||||
x:Name="ThisControl">
|
||||
<ListBox ItemsSource="{Binding #ThisControl.Rows}"
|
||||
<v:RevisionFileRowsListBox ItemsSource="{Binding #ThisControl.Rows}"
|
||||
Background="Transparent"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="OnRowsSelectionChanged"
|
||||
|
@ -46,5 +46,5 @@
|
|||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</v:RevisionFileRowsListBox>
|
||||
</UserControl>
|
||||
|
|
|
@ -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 static readonly StyledProperty<string> RevisionProperty =
|
||||
|
@ -285,8 +305,8 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
private List<ViewModels.RevisionFileTreeNode> _tree = new List<ViewModels.RevisionFileTreeNode>();
|
||||
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = new AvaloniaList<ViewModels.RevisionFileTreeNode>();
|
||||
private List<ViewModels.RevisionFileTreeNode> _tree = [];
|
||||
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
|
||||
private bool _disableSelectionChangingEvent = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
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}"
|
||||
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
|
||||
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
|
||||
|
@ -65,7 +65,7 @@
|
|||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
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}"
|
||||
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
|
||||
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
|
||||
|
|
|
@ -519,8 +519,18 @@ namespace SourceGit.Views
|
|||
private void OnTextViewPointerMoved(object sender, PointerEventArgs e)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
</TextBox>
|
||||
|
||||
<!-- Repository Tree -->
|
||||
<ListBox Grid.Row="1"
|
||||
<v:RepositoryListBox Grid.Row="1"
|
||||
x:Name="TreeContainer"
|
||||
Margin="0,8,8,0"
|
||||
Focusable="True"
|
||||
|
@ -140,12 +140,12 @@
|
|||
Margin="8,0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
Text="{Binding Id}"
|
||||
Text="{Binding Id, Converter={x:Static c:PathConverters.RelativeToHome}}"
|
||||
IsVisible="{Binding IsRepository}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</v:RepositoryListBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
|
|
@ -26,6 +26,26 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
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 Welcome()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue