From 02528874420ab7ab82ac1dd33e1eb98aa4151245 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 3 Apr 2024 12:17:20 +0800 Subject: [PATCH] feature: external editor supports visual studio code insiders; add environment variable `VSCODE_PATH` and `FLEET_PATH` to help to find these editors. (#54) (#55) --- README.md | 6 +++++ src/Models/ExternalMergeTools.cs | 21 ++++++++++++++- src/Native/OS.cs | 17 ++++++++++++ src/Native/Windows.cs | 44 +++++++++++++++++++++++++------- src/Views/Preference.axaml.cs | 3 +-- 5 files changed, 79 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4530bf6d..5a63304f 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ You can download the latest stable from [Releases](https://github.com/sourcegit- For **Windows** users: * **MSYS Git is NOT supported**. Please use official [Git for Windows](https://git-scm.com/download/win) instead. +* You can use `Visual Studio Code Insiders` as the same way as `Visual Studio Code` in this software. For **macOS** users: @@ -53,6 +54,11 @@ For **Linux** users: * Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI. * Modify `SourceGit.desktop.template` (replace SOURCEGIT_LOCAL_FOLDER with real path) and move it into `~/.local/share/applications`. +Other tips: + +* You can set `VSCODE_PATH` environment variable if VSCode can NOT be found when you click `Open In Visual Studio Code`. +* You can set `FLEET_PATH` environment variable if JetBrains Fleet can NOT be found when you click `Open In Fleet`. + ## Screen Shots * Dark Theme diff --git a/src/Models/ExternalMergeTools.cs b/src/Models/ExternalMergeTools.cs index 2ccab1e0..1871faf2 100644 --- a/src/Models/ExternalMergeTools.cs +++ b/src/Models/ExternalMergeTools.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; namespace SourceGit.Models { @@ -19,7 +20,7 @@ namespace SourceGit.Models { Supported = new List() { new ExternalMergeTools(0, "Custom", "", "", ""), - new ExternalMergeTools(1, "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), + new ExternalMergeTools(1, "Visual Studio Code", "Code.exe;Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(2, "Visual Studio 2017/2019", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(3, "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""), new ExternalMergeTools(4, "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), @@ -62,5 +63,23 @@ namespace SourceGit.Models Cmd = cmd; DiffCmd = diffCmd; } + + public string[] GetPatterns() + { + if (OperatingSystem.IsWindows()) + { + return Exec.Split(';'); + } + else + { + var patterns = new List(); + var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries); + foreach (var c in choices) + { + patterns.Add(Path.GetFileName(c)); + } + return patterns.ToArray(); + } + } } } diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 6df30c46..004cfc62 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using Avalonia; @@ -47,7 +48,12 @@ namespace SourceGit.Native } VSCodeExecutableFile = _backend.FindVSCode(); + if (string.IsNullOrEmpty(VSCodeExecutableFile)) + VSCodeExecutableFile = GetPathFromEnvironmentVar("VSCODE_PATH"); + FleetExecutableFile = _backend.FindFleet(); + if (string.IsNullOrEmpty(FleetExecutableFile)) + FleetExecutableFile = GetPathFromEnvironmentVar("FLEET_PATH"); } public static void SetupApp(AppBuilder builder) @@ -114,6 +120,17 @@ namespace SourceGit.Native }); } + private static string GetPathFromEnvironmentVar(string key) + { + var customPath = Environment.GetEnvironmentVariable(key); + if (!string.IsNullOrEmpty(customPath) && File.Exists(customPath)) + { + return customPath; + } + + return string.Empty; + } + private static readonly IBackend _backend; } } diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 40a1f856..f026852b 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -105,27 +105,52 @@ namespace SourceGit.Native } var exePath = builder.ToString(); - if (string.IsNullOrEmpty(exePath)) - return null; + if (!string.IsNullOrEmpty(exePath)) + { + return exePath; + } - return exePath; + return null; } public string FindVSCode() { - var root = Microsoft.Win32.RegistryKey.OpenBaseKey( + var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( Microsoft.Win32.RegistryHive.LocalMachine, - Environment.Is64BitOperatingSystem ? Microsoft.Win32.RegistryView.Registry64 : Microsoft.Win32.RegistryView.Registry32); + Microsoft.Win32.RegistryView.Registry64); - var vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1"); + // VSCode (system) + var systemVScode = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1"); + if (systemVScode != null) + { + return systemVScode.GetValue("DisplayIcon") as string; + } + + // VSCode - Insiders (system) + var systemVScodeInsiders = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1"); + if (systemVScodeInsiders != null) + { + return systemVScodeInsiders.GetValue("DisplayIcon") as string; + } + + var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey( + Microsoft.Win32.RegistryHive.CurrentUser, + Microsoft.Win32.RegistryView.Registry64); + + // VSCode (user) + var vscode = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{771FD6B0-FA20-440A-A002-3B3BAC16DC50}_is1"); if (vscode != null) { return vscode.GetValue("DisplayIcon") as string; } - var toolPath = Environment.ExpandEnvironmentVariables($"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe"); - if (File.Exists(toolPath)) - return toolPath; + // VSCode - Insiders (user) + var vscodeInsiders = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{217B4C08-948D-4276-BFBB-BEE930AE5A2C}_is1"); + if (vscodeInsiders != null) + { + return vscodeInsiders.GetValue("DisplayIcon") as string; + } + return string.Empty; } @@ -134,6 +159,7 @@ namespace SourceGit.Native var toolPath = Environment.ExpandEnvironmentVariables($"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\\AppData\\Local\\Programs\\Fleet\\Fleet.exe"); if (File.Exists(toolPath)) return toolPath; + return string.Empty; } diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preference.axaml.cs index 71f4ed48..9dfe9c30 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -229,10 +229,9 @@ namespace SourceGit.Views } var tool = Models.ExternalMergeTools.Supported[type]; - var pattern = Path.GetFileName(tool.Exec); var options = new FilePickerOpenOptions() { - FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = [pattern] }], + FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = tool.GetPatterns() }], AllowMultiple = false, };