Merge branch 'release/v8.11'

This commit is contained in:
leo 2024-05-06 12:08:38 +08:00
commit 56780f9c74
34 changed files with 463 additions and 126 deletions

View file

@ -7,21 +7,9 @@ on:
branches: [develop] branches: [develop]
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build: build-windows:
name: Build name: Build Windows x64
strategy: runs-on: windows-latest
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux-x64
- os: windows-latest
platform: win-x64
- os: macos-latest
platform: osx-x64
- os: macos-latest
platform: osx-arm64
runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -34,9 +22,80 @@ jobs:
- name: Build - name: Build
run: dotnet build -c Release run: dotnet build -c Release
- name: Publish - name: Publish
run: dotnet publish src/SourceGit.csproj -c Release -o publish -r ${{ matrix.platform }} -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained run: dotnet publish src/SourceGit.csproj -c Release -o publish -r win-x64 -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
- name: Upload Artifact - name: Upload Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ matrix.platform }} name: sourcegit.win-x64
path: publish path: publish
build-macos-intel:
name: Build macOS (Intel)
runs-on: macos-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Build
run: dotnet build -c Release
- name: Publish
run: dotnet publish src/SourceGit.csproj -c Release -o publish -r osx-x64 -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
- name: Packing Program
run: tar -cvf sourcegit.osx-x64.tar publish/
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: sourcegit.osx-x64
path: sourcegit.osx-x64.tar
build-macos-arm64:
name: Build macOS (Apple Silicon)
runs-on: macos-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Build
run: dotnet build -c Release
- name: Publish
run: dotnet publish src/SourceGit.csproj -c Release -o publish -r osx-arm64 -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
- name: Packing Program
run: tar -cvf sourcegit.osx-arm64.tar publish/
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: sourcegit.osx-arm64
path: sourcegit.osx-arm64.tar
build-linux:
name: Build Linux
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Build
run: dotnet build -c Release
- name: Publish
run: dotnet publish src/SourceGit.csproj -c Release -o publish -r linux-x64 -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
- name: Rename Executable File
run: mv publish/SourceGit publish/sourcegit
- name: Packing Program
run: tar -cvf sourcegit.linux-x64.tar publish/
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: sourcegit.linux-x64
path: sourcegit.linux-x64.tar

View file

@ -69,6 +69,7 @@ This app supports open repository in external tools listed in the table below.
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Visual Studio Code | YES | YES | YES | VSCODE_PATH | | Visual Studio Code | YES | YES | YES | VSCODE_PATH |
| Visual Studio Code - Insiders | YES | YES | YES | VSCODE_INSIDERS_PATH | | Visual Studio Code - Insiders | YES | YES | YES | VSCODE_INSIDERS_PATH |
| VSCodium | YES | YES | YES | VSCODIUM_PATH |
| JetBrains Fleet | YES | YES | YES | FLEET_PATH | | JetBrains Fleet | YES | YES | YES | FLEET_PATH |
| Sublime Text | YES | YES | YES | SUBLIME_TEXT_PATH | | Sublime Text | YES | YES | YES | SUBLIME_TEXT_PATH |

View file

@ -1 +1 @@
8.10 8.11

View file

@ -8,10 +8,12 @@ rm -rf SourceGit *.tar.gz resources/deb/opt *.deb *.rpm
# Compile # Compile
dotnet publish ../src/SourceGit.csproj -c Release -r linux-x64 -o SourceGit -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained dotnet publish ../src/SourceGit.csproj -c Release -r linux-x64 -o SourceGit -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
mv SourceGit/SourceGit SourceGit/sourcegit mv SourceGit/SourceGit SourceGit/sourcegit
cp resources/app/App.icns SourceGit/sourcegit.icns
rm -f SourceGit/*.dbg rm -f SourceGit/*.dbg
# General Linux archive # General Linux archive
tar -zcvf sourcegit_${version}.linux-x64.tar.gz SourceGit tar -zcvf sourcegit_${version}.linux-x64.tar.gz SourceGit
rm -f SourceGit/sourcegit.icns
# Debain/Ubuntu package # Debain/Ubuntu package
mkdir -p resources/deb/opt/sourcegit/ mkdir -p resources/deb/opt/sourcegit/

View file

@ -2,7 +2,7 @@
{ {
public class IsConflictResolved : Command public class IsConflictResolved : Command
{ {
public IsConflictResolved(string repo, Models.Change change) public IsConflictResolved(string repo, Models.Change change)
{ {
var opt = new Models.DiffOption(change, true); var opt = new Models.DiffOption(change, true);

View file

@ -1,4 +1,5 @@
using Avalonia.Data.Converters; using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Media; using Avalonia.Media;
namespace SourceGit.Converters namespace SourceGit.Converters
@ -8,7 +9,10 @@ namespace SourceGit.Converters
public static readonly FuncValueConverter<bool, double> HalfIfFalse = public static readonly FuncValueConverter<bool, double> HalfIfFalse =
new FuncValueConverter<bool, double>(x => x ? 1 : 0.5); new FuncValueConverter<bool, double>(x => x ? 1 : 0.5);
public static readonly FuncValueConverter<bool, FontWeight> BoldIfTrue = public static readonly FuncValueConverter<bool, FontWeight> BoldIfTrue =
new FuncValueConverter<bool, FontWeight>(x => x ? FontWeight.Bold : FontWeight.Regular); new FuncValueConverter<bool, FontWeight>(x => x ? FontWeight.Bold : FontWeight.Regular);
public static readonly FuncValueConverter<bool, GridLength> ToStarOrAutoGridLength =
new(value => value ? new GridLength(1, GridUnitType.Star) : new GridLength(1, GridUnitType.Auto));
} }
} }

View file

@ -40,6 +40,7 @@ namespace SourceGit.Models
new ExternalMerger(5, "kdiff3", "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(5, "kdiff3", "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(6, "beyond_compare", "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(6, "beyond_compare", "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(7, "win_merge", "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""), new ExternalMerger(7, "win_merge", "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(8, "codium", "VSCodium", "VSCodium.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
}; };
} }
else if (OperatingSystem.IsMacOS()) else if (OperatingSystem.IsMacOS())
@ -51,6 +52,7 @@ namespace SourceGit.Models
new ExternalMerger(3, "vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMerger(3, "vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(4, "kdiff3", "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(4, "kdiff3", "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(5, "beyond_compare", "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(5, "beyond_compare", "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(6, "codium", "VSCodium", "/Applications/VSCodium.app/Contents/Resources/app/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
}; };
} }
else if (OperatingSystem.IsLinux()) else if (OperatingSystem.IsLinux())
@ -62,6 +64,7 @@ namespace SourceGit.Models
new ExternalMerger(3, "kdiff3", "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(3, "kdiff3", "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(4, "beyond_compare", "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(4, "beyond_compare", "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(5, "meld", "Meld", "/usr/bin/meld", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" -output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger(5, "meld", "Meld", "/usr/bin/meld", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" -output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(6, "codium", "VSCodium", "/usr/share/codium/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
}; };
} }
else else

View file

@ -116,31 +116,36 @@ namespace SourceGit.Models
}); });
} }
public void VSCode(Func<string> platform_finder) public void VSCode(Func<string> platformFinder)
{ {
TryAdd("Visual Studio Code", "vscode", "\"{0}\"", "VSCODE_PATH", platform_finder); TryAdd("Visual Studio Code", "vscode", "\"{0}\"", "VSCODE_PATH", platformFinder);
} }
public void VSCodeInsiders(Func<string> platform_finder) public void VSCodeInsiders(Func<string> platformFinder)
{ {
TryAdd("Visual Studio Code - Insiders", "vscode_insiders", "\"{0}\"", "VSCODE_INSIDERS_PATH", platform_finder); TryAdd("Visual Studio Code - Insiders", "vscode_insiders", "\"{0}\"", "VSCODE_INSIDERS_PATH", platformFinder);
} }
public void Fleet(Func<string> platform_finder) public void VSCodium(Func<string> platformFinder)
{ {
TryAdd("Fleet", "fleet", "\"{0}\"", "FLEET_PATH", platform_finder); TryAdd("VSCodium", "codium", "\"{0}\"", "VSCODIUM_PATH", platformFinder);
} }
public void SublimeText(Func<string> platform_finder) public void Fleet(Func<string> platformFinder)
{ {
TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT_PATH", platform_finder); TryAdd("Fleet", "fleet", "\"{0}\"", "FLEET_PATH", platformFinder);
} }
public void FindJetBrainsFromToolbox(Func<string> platform_finder) public void SublimeText(Func<string> platformFinder)
{
TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT_PATH", 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" };
var supported_icons = new List<string> { "CL", "DB", "DL", "DS", "GO", "IC", "IU", "JB", "PC", "PS", "PY", "QA", "QD", "RD", "RM", "RR", "WRS", "WS" }; var supported_icons = new List<string> { "CL", "DB", "DL", "DS", "GO", "IC", "IU", "JB", "PC", "PS", "PY", "QA", "QD", "RD", "RM", "RR", "WRS", "WS" };
var state = Path.Combine(platform_finder(), "state.json"); var state = Path.Combine(platformFinder(), "state.json");
if (File.Exists(state)) if (File.Exists(state))
{ {
var stateData = JsonSerializer.Deserialize(File.ReadAllText(state), JsonCodeGen.Default.JetBrainsState); var stateData = JsonSerializer.Deserialize(File.ReadAllText(state), JsonCodeGen.Default.JetBrainsState);

View file

@ -35,8 +35,15 @@ namespace SourceGit.Models
_wcWatcher.Deleted += OnWorkingCopyChanged; _wcWatcher.Deleted += OnWorkingCopyChanged;
_wcWatcher.EnableRaisingEvents = true; _wcWatcher.EnableRaisingEvents = true;
// If this repository is a worktree repository, just watch the main repository's gitdir.
var gitDirNormalized = _repo.GitDir.Replace("\\", "/");
var worktreeIdx = gitDirNormalized.IndexOf(".git/worktrees/");
var repoWatchDir = _repo.GitDir;
if (worktreeIdx > 0)
repoWatchDir = _repo.GitDir.Substring(0, worktreeIdx + 4);
_repoWatcher = new FileSystemWatcher(); _repoWatcher = new FileSystemWatcher();
_repoWatcher.Path = _repo.GitDir; _repoWatcher.Path = repoWatchDir;
_repoWatcher.Filter = "*"; _repoWatcher.Filter = "*";
_repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName; _repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
_repoWatcher.IncludeSubdirectories = true; _repoWatcher.IncludeSubdirectories = true;
@ -173,8 +180,7 @@ namespace SourceGit.Models
} }
else if (name.Equals("HEAD", StringComparison.Ordinal) || else if (name.Equals("HEAD", StringComparison.Ordinal) ||
name.StartsWith("refs/heads/", StringComparison.Ordinal) || name.StartsWith("refs/heads/", StringComparison.Ordinal) ||
name.StartsWith("refs/remotes/", StringComparison.Ordinal) || name.StartsWith("refs/remotes/", StringComparison.Ordinal))
name.StartsWith("worktrees/", StringComparison.Ordinal))
{ {
_updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime(); _updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
} }

View file

@ -57,6 +57,7 @@ namespace SourceGit.Native
var finder = new Models.ExternalToolsFinder(); var finder = new Models.ExternalToolsFinder();
finder.VSCode(() => FindExecutable("code")); finder.VSCode(() => FindExecutable("code"));
finder.VSCodeInsiders(() => FindExecutable("code-insiders")); finder.VSCodeInsiders(() => FindExecutable("code-insiders"));
finder.VSCodium(() => FindExecutable("codium"));
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"));

View file

@ -19,6 +19,12 @@ namespace SourceGit.Native
{ {
DefaultFamilyName = "PingFang SC", DefaultFamilyName = "PingFang SC",
}); });
builder.With(new MacOSPlatformOptions()
{
DisableNativeMenus = true,
DisableDefaultApplicationMenuItems = true,
});
} }
public string FindGitExecutable() public string FindGitExecutable()
@ -32,6 +38,7 @@ namespace SourceGit.Native
var finder = new Models.ExternalToolsFinder(); var finder = new Models.ExternalToolsFinder();
finder.VSCode(() => "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"); finder.VSCode(() => "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code");
finder.VSCodeInsiders(() => "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"); finder.VSCodeInsiders(() => "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code");
finder.VSCodium(() => "/Applications/VSCodium.app/Contents/Resources/app/bin/codium");
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");
@ -58,10 +65,12 @@ namespace SourceGit.Native
public void OpenTerminal(string workdir) public void OpenTerminal(string workdir)
{ {
var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir; var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir;
dir = dir.Replace(" ", "\\ ");
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("on run argv"); builder.AppendLine("on run argv");
builder.AppendLine(" tell application \"Terminal\""); builder.AppendLine(" tell application \"Terminal\"");
builder.AppendLine($" do script \"cd '{dir}'\""); builder.AppendLine($" do script \"cd {dir}\"");
builder.AppendLine(" activate"); builder.AppendLine(" activate");
builder.AppendLine(" end tell"); builder.AppendLine(" end tell");
builder.AppendLine("end run"); builder.AppendLine("end run");

View file

@ -110,6 +110,7 @@ namespace SourceGit.Native
var finder = new Models.ExternalToolsFinder(); var finder = new Models.ExternalToolsFinder();
finder.VSCode(FindVSCode); finder.VSCode(FindVSCode);
finder.VSCodeInsiders(FindVSCodeInsiders); finder.VSCodeInsiders(FindVSCodeInsiders);
finder.VSCodium(FindVSCodium);
finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe"); finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe");
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\JetBrains\\Toolbox"); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\JetBrains\\Toolbox");
finder.SublimeText(FindSublimeText); finder.SublimeText(FindSublimeText);
@ -323,6 +324,33 @@ namespace SourceGit.Native
return string.Empty; return string.Empty;
} }
private string FindVSCodium()
{
var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey(
Microsoft.Win32.RegistryHive.LocalMachine,
Microsoft.Win32.RegistryView.Registry64);
// VSCodium (system)
var systemVScodium = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{88DA3577-054F-4CA1-8122-7D820494CFFB}_is1");
if (systemVScodium != null)
{
return systemVScodium.GetValue("DisplayIcon") as string;
}
var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
Microsoft.Win32.RegistryHive.CurrentUser,
Microsoft.Win32.RegistryView.Registry64);
// VSCodium (user)
var vscodium = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2E1F05D1-C245-4562-81EE-28188DB6FD17}_is1");
if (vscodium != null)
{
return vscodium.GetValue("DisplayIcon") as string;
}
return string.Empty;
}
private string FindSublimeText() private string FindSublimeText()
{ {
var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey(

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -52,7 +52,10 @@
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Show as List</x:String> <x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Show as List</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Show as Tree</x:String> <x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Show as Tree</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Checkout Branch</x:String> <x:String x:Key="Text.Checkout" xml:space="preserve">Checkout Branch</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Target :</x:String> <x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch :</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Local Changes :</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reapply</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick This Commit</x:String> <x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick This Commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit :</x:String> <x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit :</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit all changes</x:String> <x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit all changes</x:String>
@ -117,6 +120,8 @@
<x:String x:Key="Text.Cut" xml:space="preserve">Cut</x:String> <x:String x:Key="Text.Cut" xml:space="preserve">Cut</x:String>
<x:String x:Key="Text.DeleteBranch" xml:space="preserve">Delete Branch</x:String> <x:String x:Key="Text.DeleteBranch" xml:space="preserve">Delete Branch</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">Branch :</x:String> <x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">Branch :</x:String>
<x:String x:Key="Text.DeleteBranch.IsRemoteTip" xml:space="preserve">You are about to delete a remote branch!!!</x:String>
<x:String x:Key="Text.DeleteBranch.WithTrackingRemote" xml:space="preserve">Also delete remote branch${0}$</x:String>
<x:String x:Key="Text.DeleteRemote" xml:space="preserve">Delete Remote</x:String> <x:String x:Key="Text.DeleteRemote" xml:space="preserve">Delete Remote</x:String>
<x:String x:Key="Text.DeleteRemote.Remote" xml:space="preserve">Remote :</x:String> <x:String x:Key="Text.DeleteRemote.Remote" xml:space="preserve">Remote :</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.Target" xml:space="preserve">Target :</x:String> <x:String x:Key="Text.DeleteRepositoryNode.Target" xml:space="preserve">Target :</x:String>
@ -208,12 +213,13 @@
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String> <x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Cancel current popup</x:String> <x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Cancel current popup</x:String>
<x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Close current page</x:String> <x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Close current page</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Go to previous page</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Go to next page</x:String> <x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Go to next page</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Create new page</x:String> <x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Create new page</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</x:String> <x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Force to reload this repository</x:String> <x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Force to reload this repository</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Stage/Unstage selected changes</x:String> <x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Stage/Unstage selected changes</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ToggleSearch" xml:space="preserve">Toggle commit search</x:String> <x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Open commit search</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Switch to 'Changes'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Switch to 'Changes'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Switch to 'Histories'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Switch to 'Histories'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Switch to 'Stashes'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Switch to 'Stashes'</x:String>
@ -243,7 +249,7 @@
<x:String x:Key="Text.OpenFolder" xml:space="preserve">SELECT FOLDER</x:String> <x:String x:Key="Text.OpenFolder" xml:space="preserve">SELECT FOLDER</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Open With ...</x:String> <x:String x:Key="Text.OpenWith" xml:space="preserve">Open With ...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String> <x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String>
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Create New Page (Ctrl+T)</x:String> <x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Create New Page</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Bookmark</x:String> <x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Bookmark</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Close Tab</x:String> <x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Close Tab</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Close Other Tabs</x:String> <x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Close Other Tabs</x:String>
@ -340,7 +346,7 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String> <x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ADD REMOTE</x:String> <x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ADD REMOTE</x:String>
<x:String x:Key="Text.Repository.Resolve" xml:space="preserve">RESOLVE</x:String> <x:String x:Key="Text.Repository.Resolve" xml:space="preserve">RESOLVE</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Search Commit (Ctrl+F)</x:String> <x:String x:Key="Text.Repository.Search" xml:space="preserve">Search Commit</x:String>
<x:String x:Key="Text.Repository.SearchTip" xml:space="preserve">Search Author/Committer/Message/SHA</x:String> <x:String x:Key="Text.Repository.SearchTip" xml:space="preserve">Search Author/Committer/Message/SHA</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistics</x:String> <x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistics</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULES</x:String> <x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULES</x:String>

View file

@ -53,6 +53,9 @@
<x:String x:Key="Text.ChangeDisplayMode.Tree" 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">检出(checkout)分支</x:String> <x:String x:Key="Text.Checkout" xml:space="preserve">检出(checkout)分支</x:String>
<x:String x:Key="Text.Checkout.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.StashAndReply" xml:space="preserve">贮藏(stash)并自动恢复</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">忽略</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选(cherry-pick)此提交</x:String> <x:String x:Key="Text.CherryPick" xml:space="preserve">挑选(cherry-pick)此提交</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交ID </x:String> <x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交ID </x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">提交变化</x:String> <x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">提交变化</x:String>
@ -117,6 +120,8 @@
<x:String x:Key="Text.Cut" xml:space="preserve">剪切</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" xml:space="preserve">删除分支确认</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" 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.DeleteRemote" 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.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.Target" xml:space="preserve">目标 </x:String>
@ -208,12 +213,13 @@
<x:String x:Key="Text.Hotkeys.Global" 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.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.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.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.NewTab" xml:space="preserve">新建页面</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">仓库页面快捷键</x:String> <x:String x:Key="Text.Hotkeys.Repo" 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.Refresh" xml:space="preserve">重新加载仓库状态</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">将选中的变更暂存或从暂存列表中移除</x:String> <x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">将选中的变更暂存或从暂存列表中移除</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ToggleSearch" 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.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.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.Repo.ViewStashes" xml:space="preserve">显示贮藏列表</x:String>
@ -243,9 +249,9 @@
<x:String x:Key="Text.OpenFolder" 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.OpenWith" xml:space="preserve">打开文件...</x:String>
<x:String x:Key="Text.Optional" 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">新建空白页 (Ctrl+T)</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.Bookmark" xml:space="preserve">设置书签</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">关闭标签页 (Ctrl+W)</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.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.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.Tab.CopyPath" xml:space="preserve">复制仓库路径</x:String>
@ -340,7 +346,7 @@
<x:String x:Key="Text.Repository.Remotes" 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.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.Resolve" xml:space="preserve">解决冲突</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">查找提交(Ctrl+F)</x:String> <x:String x:Key="Text.Repository.Search" xml:space="preserve">查找提交</x:String>
<x:String x:Key="Text.Repository.SearchTip" xml:space="preserve">支持搜索作者/提交者/主题/指纹</x:String> <x:String x:Key="Text.Repository.SearchTip" xml:space="preserve">支持搜索作者/提交者/主题/指纹</x:String>
<x:String x:Key="Text.Repository.Statistics" 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" xml:space="preserve">子模块列表</x:String>

View file

@ -10,6 +10,12 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public bool AutoStash
{
get => _autoStash;
set => SetProperty(ref _autoStash, value);
}
public Checkout(Repository repo, string branch) public Checkout(Repository repo, string branch)
{ {
_repo = repo; _repo = repo;
@ -22,14 +28,56 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
ProgressDescription = $"Checkout '{Branch}' ..."; ProgressDescription = $"Checkout '{Branch}' ...";
var hasLocalChanges = _repo.WorkingCopyChangesCount > 0;
return Task.Run(() => return Task.Run(() =>
{ {
var succ = new Commands.Checkout(_repo.FullPath).Branch(Branch, SetProgressDescription); var needPopStash = false;
if (hasLocalChanges)
{
if (AutoStash)
{
SetProgressDescription("Adding untracked changes ...");
var succ = new Commands.Add(_repo.FullPath).Exec();
if (succ)
{
SetProgressDescription("Stash local changes ...");
succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
}
if (!succ)
{
CallUIThread(() => _repo.SetWatcherEnabled(true));
return false;
}
needPopStash = true;
}
else
{
SetProgressDescription("Discard local changes ...");
Commands.Discard.All(_repo.FullPath);
}
}
SetProgressDescription("Checkout branch ...");
var rs = new Commands.Checkout(_repo.FullPath).Branch(Branch, SetProgressDescription);
if (needPopStash)
{
SetProgressDescription("Re-apply local changes...");
rs = new Commands.Stash(_repo.FullPath).Apply("stash@{0}");
if (rs)
{
rs = new Commands.Stash(_repo.FullPath).Drop("stash@{0}");
}
}
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return rs;
}); });
} }
private readonly Repository _repo; private readonly Repository _repo = null;
private bool _autoStash = true;
} }
} }

View file

@ -10,10 +10,36 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public Models.Branch TrackingRemoteBranch
{
get;
private set;
}
public object DeleteTrackingRemoteTip
{
get;
private set;
}
public bool AlsoDeleteTrackingRemote
{
get => _alsoDeleteTrackingRemote;
set => SetProperty(ref _alsoDeleteTrackingRemote, value);
}
public DeleteBranch(Repository repo, Models.Branch branch) public DeleteBranch(Repository repo, Models.Branch branch)
{ {
_repo = repo; _repo = repo;
Target = branch; Target = branch;
if (branch.IsLocal && !string.IsNullOrEmpty(branch.Upstream))
{
var upstream = branch.Upstream.Substring(13);
TrackingRemoteBranch = repo.Branches.Find(x => !x.IsLocal && $"{x.Remote}/{x.Name}" == upstream);
DeleteTrackingRemoteTip = new Views.NameHighlightedTextBlock("DeleteBranch.WithTrackingRemote", upstream);
}
View = new Views.DeleteBranch() { DataContext = this }; View = new Views.DeleteBranch() { DataContext = this };
} }
@ -27,6 +53,9 @@ namespace SourceGit.ViewModels
if (Target.IsLocal) if (Target.IsLocal)
{ {
Commands.Branch.Delete(_repo.FullPath, Target.Name); Commands.Branch.Delete(_repo.FullPath, Target.Name);
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
new Commands.Push(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name).Exec();
} }
else else
{ {
@ -39,5 +68,6 @@ namespace SourceGit.ViewModels
} }
private readonly Repository _repo = null; private readonly Repository _repo = null;
private bool _alsoDeleteTrackingRemote = false;
} }
} }

View file

@ -34,8 +34,19 @@ namespace SourceGit.ViewModels
get => _commits; get => _commits;
set set
{ {
var oldAutoSelectedCommitSHA = AutoSelectedCommit?.SHA;
if (SetProperty(ref _commits, value)) if (SetProperty(ref _commits, value))
{ {
Models.Commit newSelectedCommit = null;
if (value.Count > 0 && oldAutoSelectedCommitSHA != null)
{
newSelectedCommit = value.Find(x => x.SHA == oldAutoSelectedCommitSHA);
}
if (newSelectedCommit != AutoSelectedCommit)
{
AutoSelectedCommit = newSelectedCommit;
}
Graph = null; Graph = null;
Task.Run(() => Task.Run(() =>
{ {
@ -372,7 +383,6 @@ namespace SourceGit.ViewModels
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(current.UpstreamTrackStatus) && current.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.IsEnabled = !string.IsNullOrEmpty(current.UpstreamTrackStatus) && current.UpstreamTrackStatus.IndexOf('↑') < 0;
;
fastForward.Click += (o, e) => fastForward.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
@ -447,8 +457,7 @@ namespace SourceGit.ViewModels
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) _repo.CheckoutLocalBranch(branch.Name);
PopupHost.ShowAndStartPopup(new Checkout(_repo, branch.Name));
e.Handled = true; e.Handled = true;
}; };
submenu.Items.Add(checkout); submenu.Items.Add(checkout);
@ -524,16 +533,16 @@ namespace SourceGit.ViewModels
{ {
if (b.IsLocal && b.Upstream == branch.FullName) if (b.IsLocal && b.Upstream == branch.FullName)
{ {
if (b.IsCurrent) if (!b.IsCurrent)
return; _repo.CheckoutLocalBranch(b.Name);
if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new Checkout(_repo, b.Name));
return; return;
} }
} }
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateBranch(_repo, branch)); PopupHost.ShowPopup(new CreateBranch(_repo, branch));
e.Handled = true; e.Handled = true;
}; };
submenu.Items.Add(checkout); submenu.Items.Add(checkout);

View file

@ -93,6 +93,16 @@ namespace SourceGit.ViewModels
ActivePage = Pages[nextIdx]; ActivePage = Pages[nextIdx];
} }
public void GotoPrevTab()
{
if (Pages.Count == 1)
return;
var activeIdx = Pages.IndexOf(_activePage);
var prevIdx = activeIdx == 0 ? Pages.Count - 1 : activeIdx - 1;
ActivePage = Pages[prevIdx];
}
public void CloseTab(object param) public void CloseTab(object param)
{ {
if (Pages.Count == 1) if (Pages.Count == 1)

View file

@ -37,7 +37,8 @@ namespace SourceGit.ViewModels
} }
} }
_instance.Repositories.RemoveAll(x => !Directory.Exists(x.FullPath)); // It will cause some issue on Linux. See https://github.com/sourcegit-scm/sourcegit/issues/99
// _instance.Repositories.RemoveAll(x => !Directory.Exists(x.FullPath));
if (_instance.DefaultFont == null) if (_instance.DefaultFont == null)
{ {

View file

@ -690,6 +690,17 @@ namespace SourceGit.ViewModels
PopupHost.ShowPopup(new CreateBranch(this, current)); PopupHost.ShowPopup(new CreateBranch(this, current));
} }
public void CheckoutLocalBranch(string branch)
{
if (!PopupHost.CanCreatePopup())
return;
if (WorkingCopyChangesCount > 0)
PopupHost.ShowPopup(new Checkout(this, branch));
else
PopupHost.ShowAndStartPopup(new Checkout(this, branch));
}
public void CreateNewTag() public void CreateNewTag()
{ {
var current = Branches.Find(x => x.IsCurrent); var current = Branches.Find(x => x.IsCurrent);
@ -842,8 +853,7 @@ namespace SourceGit.ViewModels
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (o, e) =>
{ {
if (PopupHost.CanCreatePopup()) CheckoutLocalBranch(branch.Name);
PopupHost.ShowAndStartPopup(new Checkout(this, branch.Name));
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(checkout); menu.Items.Add(checkout);

View file

@ -10,10 +10,29 @@
<TextBlock FontSize="18" <TextBlock FontSize="18"
Classes="bold" Classes="bold"
Text="{DynamicResource Text.Checkout}"/> Text="{DynamicResource Text.Checkout}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
<TextBlock Text="{DynamicResource Text.Checkout.Target}"/> <Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
<Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/> <TextBlock Grid.Row="0" Grid.Column="0"
<TextBlock Text="{Binding Branch}"/> HorizontalAlignment="Right" VerticalAlignment="Center"
</StackPanel> Margin="0,0,8,0"
Text="{DynamicResource Text.Checkout.Target}"/>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<Path Width="14" Height="14" Margin="4,0" Data="{StaticResource Icons.Branch}"/>
<TextBlock Text="{Binding Branch}"/>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.Checkout.LocalChanges}"/>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<RadioButton Content="{DynamicResource Text.Checkout.LocalChanges.StashAndReply}"
GroupName="LocalChanges"
IsChecked="{Binding AutoStash, Mode=TwoWay}"/>
<RadioButton Content="{DynamicResource Text.Checkout.LocalChanges.Discard}"
GroupName="LocalChanges"
Margin="8,0,0,0"/>
</StackPanel>
</Grid>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View file

@ -12,34 +12,42 @@
<DataTemplate DataType="m:Commit"> <DataTemplate DataType="m:Commit">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<!-- Author & Committer --> <!-- Author & Committer -->
<Grid ColumnDefinitions="96,*,96,*" Margin="0,8"> <Grid Margin="0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding IsCommitterVisible, Converter={x:Static c:BoolConverters.ToStarOrAutoGridLength}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Author --> <!-- Author -->
<v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/> <Grid Grid.Column="0" ColumnDefinitions="96,*">
<StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical"> <v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/>
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Author}"/> <StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical">
<StackPanel Orientation="Horizontal" Margin="0,10,0,8"> <TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Author}"/>
<SelectableTextBlock Text="{Binding Author.Name}" Margin="2,0,8,0"/> <DockPanel Margin="0,10,0,8" ClipToBounds="True">
<SelectableTextBlock Text="{Binding Author.Email}" Foreground="{DynamicResource Brush.FG2}"/> <SelectableTextBlock Text="{Binding Author.Name}" Margin="2,0,8,0"/>
<SelectableTextBlock Text="{Binding Author.Email}" ToolTip.Tip="{Binding Author.Email}" Foreground="{DynamicResource Brush.FG2}" TextTrimming="CharacterEllipsis"/>
</DockPanel>
<SelectableTextBlock Text="{Binding AuthorTimeStr}"
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel> </StackPanel>
<SelectableTextBlock Text="{Binding AuthorTimeStr}" </Grid>
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
<!-- Committer --> <!-- Committer -->
<v:Avatar Grid.Column="2" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Committer}" IsVisible="{Binding IsCommitterVisible}"/> <Grid Grid.Column="1" ColumnDefinitions="96,*" IsVisible="{Binding IsCommitterVisible}">
<StackPanel Grid.Column="3" Margin="16,0,8,0" Orientation="Vertical" IsVisible="{Binding IsCommitterVisible}"> <v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Committer}"/>
<TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Committer}"/> <StackPanel Grid.Column="1" Margin="16,0,8,0" Orientation="Vertical">
<StackPanel Orientation="Horizontal" Margin="0,10,0,8"> <TextBlock Classes="group_header_label" Margin="0" Text="{DynamicResource Text.CommitDetail.Info.Committer}"/>
<SelectableTextBlock Text="{Binding Committer.Name}" Margin="2,0,8,0"/> <DockPanel Margin="0,10,0,8" ClipToBounds="True">
<SelectableTextBlock Text="{Binding Committer.Email}" Foreground="{DynamicResource Brush.FG2}"/> <SelectableTextBlock Text="{Binding Committer.Name}" Margin="2,0,8,0"/>
<SelectableTextBlock Text="{Binding Committer.Email}" ToolTip.Tip="{Binding Committer.Email}" Foreground="{DynamicResource Brush.FG2}" TextTrimming="CharacterEllipsis"/>
</DockPanel>
<SelectableTextBlock Text="{Binding CommitterTimeStr}"
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel> </StackPanel>
<SelectableTextBlock Text="{Binding CommitterTimeStr}" </Grid>
Margin="2,0,0,0"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</Grid> </Grid>
<!-- Line --> <!-- Line -->

View file

@ -23,7 +23,8 @@
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent" Background="Transparent"
Watermark="{DynamicResource Text.CommitDetail.Changes.Search}" Watermark="{DynamicResource Text.CommitDetail.Changes.Search}"
Text="{Binding SearchChangeFilter, Mode=TwoWay}"> Text="{Binding SearchChangeFilter, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
<TextBox.InnerLeftContent> <TextBox.InnerLeftContent>
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/> <Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
</TextBox.InnerLeftContent> </TextBox.InnerLeftContent>

View file

@ -2,7 +2,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters" xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.DeleteBranch" x:Class="SourceGit.Views.DeleteBranch"
@ -11,10 +13,25 @@
<TextBlock FontSize="18" <TextBlock FontSize="18"
Classes="bold" Classes="bold"
Text="{DynamicResource Text.DeleteBranch}"/> Text="{DynamicResource Text.DeleteBranch}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,16,0,0">
<TextBlock Text="{DynamicResource Text.DeleteBranch.Branch}"/> <Grid Margin="0,16,8,0" RowDefinitions="32,Auto" ColumnDefinitions="120,*">
<Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/> <TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" Text="{DynamicResource Text.DeleteBranch.Branch}"/>
<TextBlock Text="{Binding Target, Converter={x:Static c:BranchConverters.ToName}}"/> <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
</StackPanel> <Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/>
<TextBlock Text="{Binding Target, Converter={x:Static c:BranchConverters.ToName}}"/>
</StackPanel>
<Border Grid.Row="1" Grid.Column="1" Height="32" IsVisible="{Binding !Target.IsLocal}">
<TextBlock Margin="6,0,0,0"
Text="{DynamicResource Text.DeleteBranch.IsRemoteTip}"
Foreground="{DynamicResource Brush.FG2}"
FontStyle="Italic"
VerticalAlignment="Center"/>
</Border>
<Border Grid.Row="1" Grid.Column="1" Height="32" IsVisible="{Binding TrackingRemoteBranch, Converter={x:Static ObjectConverters.IsNotNull}}">
<CheckBox Margin="6,0,0,0" Content="{Binding DeleteTrackingRemoteTip}" IsChecked="{Binding AlsoDeleteTrackingRemote, Mode=TwoWay}"/>
</Border>
</Grid>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View file

@ -67,18 +67,21 @@
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}" FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
Margin="0,0,0,8"/> Margin="0,0,0,8"/>
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="80,*"> <Grid RowDefinitions="20,20,20,20,20" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+T"/> <TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+T, macOS=⌘+T}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.NewTab}" /> <TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.NewTab}" />
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Ctrl+W" /> <TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+W, macOS=⌘+W}" />
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CloseTab}" /> <TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CloseTab}" />
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="Ctrl+Tab"/> <TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Shift+Ctrl+Tab, macOS=⌘+⌥+←}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.GotoNextTab}" /> <TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.GotoPrevTab}" />
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="ESC"/> <TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+Tab, macOS=⌘+⌥+→}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CancelPopup}" /> <TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.GotoNextTab}" />
<TextBlock Grid.Row="4" Grid.Column="0" Classes="monospace bold" Text="ESC"/>
<TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.CancelPopup}" />
</Grid> </Grid>
<TextBlock Text="{DynamicResource Text.Hotkeys.Repo}" <TextBlock Text="{DynamicResource Text.Hotkeys.Repo}"
@ -87,20 +90,20 @@
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}" FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
Margin="0,8"/> Margin="0,8"/>
<Grid RowDefinitions="20,20,20,20,20,20" ColumnDefinitions="80,*"> <Grid RowDefinitions="20,20,20,20,20,20" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+F"/> <TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+F, macOS=⌘+F}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ToggleSearch}" /> <TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenSearchCommits}" />
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Ctrl+1"/> <TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+1, macOS=⌘+1}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewHistories}" /> <TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewHistories}" />
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="Ctrl+2"/> <TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+2, macOS=⌘+2}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewChanges}" /> <TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewChanges}" />
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="Ctrl+3"/> <TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+3, macOS=⌘+3}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewStashes}" /> <TextBlock Grid.Row="3" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewStashes}" />
<TextBlock Grid.Row="4" Grid.Column="0" Classes="monospace bold" Text="SPACE"/> <TextBlock Grid.Row="4" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Space, macOS=␣}"/>
<TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.StageOrUnstageSelected}" /> <TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.StageOrUnstageSelected}" />
<TextBlock Grid.Row="5" Grid.Column="0" Classes="monospace bold" Text="F5"/> <TextBlock Grid.Row="5" Grid.Column="0" Classes="monospace bold" Text="F5"/>
@ -113,14 +116,14 @@
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}" FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
Margin="0,8"/> Margin="0,8"/>
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="80,*"> <Grid RowDefinitions="20,20,20,20" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="Ctrl+F"/> <TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+F, macOS=⌘+F}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.Search}" /> <TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.Search}" />
<TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="Shift+F3"/> <TextBlock Grid.Row="1" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Shift+F3/Shift+Enter, macOS=⇧+F3/⇧+Enter}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoPrevMatch}" /> <TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoPrevMatch}" />
<TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="F3"/> <TextBlock Grid.Row="2" Grid.Column="0" Classes="monospace bold" Text="F3/Enter"/>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoNextMatch}" /> <TextBlock Grid.Row="2" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.TextEditor.GotoNextMatch}" />
<TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="ESC"/> <TextBlock Grid.Row="3" Grid.Column="0" Classes="monospace bold" Text="ESC"/>

View file

@ -121,7 +121,7 @@
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.Close}" <MenuItem Header="{DynamicResource Text.PageTabBar.Tab.Close}"
Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}" Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
InputGesture="Ctrl+W"/> InputGesture="{OnPlatform Ctrl+W, macOS=⌘+W}"/>
<MenuItem Header="{DynamicResource Text.PageTabBar.Tab.CloseOther}" <MenuItem Header="{DynamicResource Text.PageTabBar.Tab.CloseOther}"
Command="{Binding #me.DataContext.(vm:Launcher).CloseOtherTabs}" Command="{Binding #me.DataContext.(vm:Launcher).CloseOtherTabs}"
CommandParameter="{Binding}"/> CommandParameter="{Binding}"/>
@ -199,8 +199,13 @@
Classes="icon_button" Classes="icon_button"
Width="16" Height="16" Margin="12,0" Width="16" Height="16" Margin="12,0"
Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}" Command="{Binding #me.DataContext.(vm:Launcher).CloseTab}"
CommandParameter="{Binding}" CommandParameter="{Binding}">
ToolTip.Tip="{DynamicResource Text.PageTabBar.Tab.Close}"> <ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.PageTabBar.Tab.Close}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Ctrl+W, macOS=⌘+W}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="8" Height="8" Data="{StaticResource Icons.Window.Close}"/> <Path Width="8" Height="8" Data="{StaticResource Icons.Window.Close}"/>
</Button> </Button>
<Rectangle Grid.Column="2" Width=".5" Height="20" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="{DynamicResource Brush.FG2}"> <Rectangle Grid.Column="2" Width=".5" Height="20" HorizontalAlignment="Right" VerticalAlignment="Center" Fill="{DynamicResource Brush.FG2}">
@ -221,9 +226,14 @@
<Button Classes="icon_button" <Button Classes="icon_button"
Width="16" Height="16" Width="16" Height="16"
Margin="8,0" Margin="8,0"
Command="{Binding AddNewTab}" Command="{Binding AddNewTab}">
HotKey="Ctrl+T" <ToolTip.Tip>
ToolTip.Tip="{DynamicResource Text.PageTabBar.New}"> <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.PageTabBar.New}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Ctrl+T, macOS=⌘+T}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="12" Height="12" Data="{StaticResource Icons.Plus}"/> <Path Width="12" Height="12" Data="{StaticResource Icons.Plus}"/>
</Button> </Button>
</StackPanel> </StackPanel>

View file

@ -98,7 +98,8 @@ namespace SourceGit.Views
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
var vm = DataContext as ViewModels.Launcher; var vm = DataContext as ViewModels.Launcher;
if (e.KeyModifiers.HasFlag(KeyModifiers.Control)) if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Meta)) ||
(!OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Control)))
{ {
if (e.Key == Key.W) if (e.Key == Key.W)
{ {
@ -106,12 +107,26 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
return; return;
} }
else if (e.Key == Key.Tab) else if (e.Key == Key.T)
{
vm.AddNewTab();
e.Handled = true;
return;
}
else if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Right) ||
(!OperatingSystem.IsMacOS() && !e.KeyModifiers.HasFlag(KeyModifiers.Shift) && e.Key == Key.Tab))
{ {
vm.GotoNextTab(); vm.GotoNextTab();
e.Handled = true; e.Handled = true;
return; return;
} }
else if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Left) ||
(!OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Shift) && e.Key == Key.Tab))
{
vm.GotoPrevTab();
e.Handled = true;
return;
}
else if (vm.ActivePage.Data is ViewModels.Repository repo) else if (vm.ActivePage.Data is ViewModels.Repository repo)
{ {
if (e.Key == Key.D1 || e.Key == Key.NumPad1) if (e.Key == Key.D1 || e.Key == Key.NumPad1)
@ -134,7 +149,7 @@ namespace SourceGit.Views
} }
else if (e.Key == Key.F) else if (e.Key == Key.F)
{ {
repo.IsSearching = !repo.IsSearching; repo.IsSearching = true;
e.Handled = true; e.Handled = true;
return; return;
} }
@ -143,6 +158,12 @@ namespace SourceGit.Views
else if (e.Key == Key.Escape) else if (e.Key == Key.Escape)
{ {
vm.ActivePage.CancelPopup(); vm.ActivePage.CancelPopup();
if (vm.ActivePage.Data is ViewModels.Repository repo)
{
repo.IsSearching = false;
}
e.Handled = true; e.Handled = true;
return; return;
} }

View file

@ -71,7 +71,7 @@ namespace SourceGit.Views
FontSize, FontSize,
Foreground); Foreground);
return new Size(formatted.Width - 16, formatted.Height); return new Size(formatted.Width, formatted.Height);
} }
public override void Render(DrawingContext context) public override void Render(DrawingContext context)

View file

@ -28,8 +28,13 @@
<ToggleButton Width="32" <ToggleButton Width="32"
Background="Transparent" Background="Transparent"
IsChecked="{Binding IsSearching, Mode=TwoWay}" IsChecked="{Binding IsSearching, Mode=TwoWay}">
ToolTip.Tip="{DynamicResource Text.Repository.Search}"> <ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.Repository.Search}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Ctrl+F, macOS=⌘+F}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="14" Height="14" Data="{StaticResource Icons.Search}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Search}"/>
</ToggleButton> </ToggleButton>
</StackPanel> </StackPanel>

View file

@ -298,7 +298,7 @@ namespace SourceGit.Views
if (branch.IsCurrent) if (branch.IsCurrent)
return; return;
ViewModels.PopupHost.ShowAndStartPopup(new ViewModels.Checkout(repo, branch.Name)); repo.CheckoutLocalBranch(branch.Name);
e.Handled = true; e.Handled = true;
} }
} }

View file

@ -24,7 +24,8 @@
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent" Background="Transparent"
Watermark="{DynamicResource Text.CommitDetail.Changes.Search}" Watermark="{DynamicResource Text.CommitDetail.Changes.Search}"
Text="{Binding SearchFileFilter, Mode=TwoWay}"> Text="{Binding SearchFileFilter, Mode=TwoWay}"
v:AutoFocusBehaviour.IsEnabled="True">
<TextBox.InnerLeftContent> <TextBox.InnerLeftContent>
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/> <Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
</TextBox.InnerLeftContent> </TextBox.InnerLeftContent>

View file

@ -686,12 +686,14 @@ namespace SourceGit.Views
private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e) private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e)
{ {
if (!TextArea.IsFocused) Focus(); if (!TextArea.IsFocused)
Focus();
} }
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e) private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
{ {
if (TextArea.IsFocused) SetCurrentValue(SyncScrollOffsetProperty, _scrollViewer.Offset); if (TextArea.IsFocused)
SetCurrentValue(SyncScrollOffsetProperty, _scrollViewer.Offset);
} }
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)

View file

@ -43,7 +43,13 @@
Classes="icon_button" Classes="icon_button"
Width="26" Height="14" Width="26" Height="14"
Padding="0" Padding="0"
ToolTip.Tip="{DynamicResource Text.WorkingCopy.Unstaged.Stage}" Click="StageSelected"> Click="StageSelected">
<ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.WorkingCopy.Unstaged.Stage}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space, macOS=␣}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/> <Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/>
</Button> </Button>
<Button Grid.Column="8" <Button Grid.Column="8"
@ -173,7 +179,13 @@
<TextBlock Grid.Column="1" Text="{DynamicResource Text.WorkingCopy.Staged}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold" Margin="8,0,0,0"/> <TextBlock Grid.Column="1" Text="{DynamicResource Text.WorkingCopy.Staged}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" FontWeight="Bold" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Staged, Converter={x:Static c:ListConverters.ToCount}}"/> <TextBlock Grid.Column="2" FontWeight="Bold" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Staged, Converter={x:Static c:ListConverters.ToCount}}"/>
<Path Grid.Column="3" Classes="rotating" Width="14" Height="14" Data="{StaticResource Icons.Loading}" Margin="8,0,0,0" IsVisible="{Binding IsUnstaging}"/> <Path Grid.Column="3" Classes="rotating" Width="14" Height="14" Data="{StaticResource Icons.Loading}" Margin="8,0,0,0" IsVisible="{Binding IsUnstaging}"/>
<Button Grid.Column="5" Classes="icon_button" Width="26" Height="14" Padding="0" ToolTip.Tip="{DynamicResource Text.WorkingCopy.Staged.Unstage}" Click="UnstageSelected"> <Button Grid.Column="5" Classes="icon_button" Width="26" Height="14" Padding="0" Click="UnstageSelected">
<ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.WorkingCopy.Staged.Unstage}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space, macOS=␣}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/> <Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/>
</Button> </Button>
<Button Grid.Column="6" Classes="icon_button" Width="26" Height="14" Padding="0" ToolTip.Tip="{DynamicResource Text.WorkingCopy.Staged.UnstageAll}" Click="UnstageAll"> <Button Grid.Column="6" Classes="icon_button" Width="26" Height="14" Padding="0" ToolTip.Tip="{DynamicResource Text.WorkingCopy.Staged.UnstageAll}" Click="UnstageAll">