Merge pull request #34181 from van800/rider
Support Rider as external editor for Godot mono version
This commit is contained in:
commit
cd9d513285
11 changed files with 595 additions and 5 deletions
|
@ -82,7 +82,8 @@ def build(env_mono, api_sln_cmd):
|
||||||
|
|
||||||
target_filenames = [
|
target_filenames = [
|
||||||
'GodotTools.dll', 'GodotTools.IdeConnection.dll', 'GodotTools.BuildLogger.dll',
|
'GodotTools.dll', 'GodotTools.IdeConnection.dll', 'GodotTools.BuildLogger.dll',
|
||||||
'GodotTools.ProjectEditor.dll', 'DotNet.Glob.dll', 'GodotTools.Core.dll'
|
'GodotTools.ProjectEditor.dll', 'DotNet.Glob.dll', 'GodotTools.Core.dll',
|
||||||
|
'JetBrains.Annotations.dll', 'Newtonsoft.Json.dll'
|
||||||
]
|
]
|
||||||
|
|
||||||
if env_mono['target'] == 'debug':
|
if env_mono['target'] == 'debug':
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace GodotTools
|
||||||
VisualStudio, // TODO (Windows-only)
|
VisualStudio, // TODO (Windows-only)
|
||||||
VisualStudioForMac, // Mac-only
|
VisualStudioForMac, // Mac-only
|
||||||
MonoDevelop,
|
MonoDevelop,
|
||||||
VsCode
|
VsCode,
|
||||||
|
Rider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,10 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GodotTools.Ides;
|
using GodotTools.Ides;
|
||||||
|
using GodotTools.Ides.Rider;
|
||||||
using GodotTools.Internals;
|
using GodotTools.Internals;
|
||||||
using GodotTools.ProjectEditor;
|
using GodotTools.ProjectEditor;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using static GodotTools.Internals.Globals;
|
using static GodotTools.Internals.Globals;
|
||||||
using File = GodotTools.Utils.File;
|
using File = GodotTools.Utils.File;
|
||||||
using OS = GodotTools.Utils.OS;
|
using OS = GodotTools.Utils.OS;
|
||||||
|
@ -189,6 +191,7 @@ namespace GodotTools
|
||||||
"code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss"
|
"code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[UsedImplicitly]
|
||||||
public Error OpenInExternalEditor(Script script, int line, int col)
|
public Error OpenInExternalEditor(Script script, int line, int col)
|
||||||
{
|
{
|
||||||
var editor = (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor");
|
var editor = (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor");
|
||||||
|
@ -202,6 +205,12 @@ namespace GodotTools
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
case ExternalEditorId.VisualStudioForMac:
|
case ExternalEditorId.VisualStudioForMac:
|
||||||
goto case ExternalEditorId.MonoDevelop;
|
goto case ExternalEditorId.MonoDevelop;
|
||||||
|
case ExternalEditorId.Rider:
|
||||||
|
{
|
||||||
|
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
|
||||||
|
RiderPathManager.OpenFile(GodotSharpDirs.ProjectSlnPath, scriptPath, line);
|
||||||
|
return Error.Ok;
|
||||||
|
}
|
||||||
case ExternalEditorId.MonoDevelop:
|
case ExternalEditorId.MonoDevelop:
|
||||||
{
|
{
|
||||||
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
|
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
|
||||||
|
@ -306,6 +315,7 @@ namespace GodotTools
|
||||||
return Error.Ok;
|
return Error.Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UsedImplicitly]
|
||||||
public bool OverridesExternalEditor()
|
public bool OverridesExternalEditor()
|
||||||
{
|
{
|
||||||
return (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None;
|
return (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None;
|
||||||
|
@ -419,18 +429,21 @@ namespace GodotTools
|
||||||
if (OS.IsWindows)
|
if (OS.IsWindows)
|
||||||
{
|
{
|
||||||
settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
||||||
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}";
|
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}" +
|
||||||
|
$",JetBrains Rider:{(int) ExternalEditorId.Rider}";
|
||||||
}
|
}
|
||||||
else if (OS.IsOSX)
|
else if (OS.IsOSX)
|
||||||
{
|
{
|
||||||
settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" +
|
settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" +
|
||||||
$",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
$",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
||||||
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}";
|
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}" +
|
||||||
|
$",JetBrains Rider:{(int) ExternalEditorId.Rider}";
|
||||||
}
|
}
|
||||||
else if (OS.IsUnixLike())
|
else if (OS.IsUnixLike())
|
||||||
{
|
{
|
||||||
settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" +
|
||||||
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}";
|
$",Visual Studio Code:{(int) ExternalEditorId.VsCode}" +
|
||||||
|
$",JetBrains Rider:{(int) ExternalEditorId.Rider}";
|
||||||
}
|
}
|
||||||
|
|
||||||
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
|
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
|
||||||
|
@ -448,6 +461,7 @@ namespace GodotTools
|
||||||
exportPluginWeak = WeakRef(exportPlugin);
|
exportPluginWeak = WeakRef(exportPlugin);
|
||||||
|
|
||||||
BuildManager.Initialize();
|
BuildManager.Initialize();
|
||||||
|
RiderPathManager.Initialize();
|
||||||
|
|
||||||
GodotIdeManager = new GodotIdeManager();
|
GodotIdeManager = new GodotIdeManager();
|
||||||
AddChild(GodotIdeManager);
|
AddChild(GodotIdeManager);
|
||||||
|
|
|
@ -30,7 +30,15 @@
|
||||||
<ConsolePause>false</ConsolePause>
|
<ConsolePause>false</ConsolePause>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="JetBrains.Annotations, Version=2019.1.3.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325">
|
||||||
|
<HintPath>..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Mono.Posix" />
|
<Reference Include="Mono.Posix" />
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="GodotSharp">
|
<Reference Include="GodotSharp">
|
||||||
<HintPath>$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharp.dll</HintPath>
|
<HintPath>$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharp.dll</HintPath>
|
||||||
|
@ -47,6 +55,8 @@
|
||||||
<Compile Include="Ides\GodotIdeServer.cs" />
|
<Compile Include="Ides\GodotIdeServer.cs" />
|
||||||
<Compile Include="Ides\MonoDevelop\EditorId.cs" />
|
<Compile Include="Ides\MonoDevelop\EditorId.cs" />
|
||||||
<Compile Include="Ides\MonoDevelop\Instance.cs" />
|
<Compile Include="Ides\MonoDevelop\Instance.cs" />
|
||||||
|
<Compile Include="Ides\Rider\RiderPathLocator.cs" />
|
||||||
|
<Compile Include="Ides\Rider\RiderPathManager.cs" />
|
||||||
<Compile Include="Internals\BindingsGenerator.cs" />
|
<Compile Include="Internals\BindingsGenerator.cs" />
|
||||||
<Compile Include="Internals\EditorProgress.cs" />
|
<Compile Include="Internals\EditorProgress.cs" />
|
||||||
<Compile Include="Internals\GodotSharpDirs.cs" />
|
<Compile Include="Internals\GodotSharpDirs.cs" />
|
||||||
|
@ -67,6 +77,7 @@
|
||||||
<Compile Include="BottomPanel.cs" />
|
<Compile Include="BottomPanel.cs" />
|
||||||
<Compile Include="CsProjOperations.cs" />
|
<Compile Include="CsProjOperations.cs" />
|
||||||
<Compile Include="Utils\CollectionExtensions.cs" />
|
<Compile Include="Utils\CollectionExtensions.cs" />
|
||||||
|
<Compile Include="Utils\User32Dll.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\GodotTools.BuildLogger\GodotTools.BuildLogger.csproj">
|
<ProjectReference Include="..\GodotTools.BuildLogger\GodotTools.BuildLogger.csproj">
|
||||||
|
@ -86,5 +97,11 @@
|
||||||
<Name>GodotTools.Core</Name>
|
<Name>GodotTools.Core</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Ides\Rider\.editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -72,6 +72,7 @@ namespace GodotTools.Ides
|
||||||
case ExternalEditorId.None:
|
case ExternalEditorId.None:
|
||||||
case ExternalEditorId.VisualStudio:
|
case ExternalEditorId.VisualStudio:
|
||||||
case ExternalEditorId.VsCode:
|
case ExternalEditorId.VsCode:
|
||||||
|
case ExternalEditorId.Rider:
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
case ExternalEditorId.VisualStudioForMac:
|
case ExternalEditorId.VisualStudioForMac:
|
||||||
goto case ExternalEditorId.MonoDevelop;
|
goto case ExternalEditorId.MonoDevelop;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
|
@ -0,0 +1,416 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Directory = System.IO.Directory;
|
||||||
|
using Environment = System.Environment;
|
||||||
|
using File = System.IO.File;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
using OS = GodotTools.Utils.OS;
|
||||||
|
|
||||||
|
namespace GodotTools.Ides.Rider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This code is a modified version of the JetBrains resharper-unity plugin listed under Apache License 2.0 license:
|
||||||
|
/// https://github.com/JetBrains/resharper-unity/blob/master/unity/JetBrains.Rider.Unity.Editor/EditorPlugin/RiderPathLocator.cs
|
||||||
|
/// </summary>
|
||||||
|
public static class RiderPathLocator
|
||||||
|
{
|
||||||
|
public static RiderInfo[] GetAllRiderPaths()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (OS.IsWindows)
|
||||||
|
{
|
||||||
|
return CollectRiderInfosWindows();
|
||||||
|
}
|
||||||
|
if (OS.IsOSX)
|
||||||
|
{
|
||||||
|
return CollectRiderInfosMac();
|
||||||
|
}
|
||||||
|
if (OS.IsUnixLike())
|
||||||
|
{
|
||||||
|
return CollectAllRiderPathsLinux();
|
||||||
|
}
|
||||||
|
throw new Exception("Unexpected OS.");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
GD.PushWarning(e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RiderInfo[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RiderInfo[] CollectAllRiderPathsLinux()
|
||||||
|
{
|
||||||
|
var installInfos = new List<RiderInfo>();
|
||||||
|
var home = Environment.GetEnvironmentVariable("HOME");
|
||||||
|
if (!string.IsNullOrEmpty(home))
|
||||||
|
{
|
||||||
|
var toolboxRiderRootPath = GetToolboxBaseDir();
|
||||||
|
installInfos.AddRange(CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider.sh", false)
|
||||||
|
.Select(a => new RiderInfo(a, true)).ToList());
|
||||||
|
|
||||||
|
//$Home/.local/share/applications/jetbrains-rider.desktop
|
||||||
|
var shortcut = new FileInfo(Path.Combine(home, @".local/share/applications/jetbrains-rider.desktop"));
|
||||||
|
|
||||||
|
if (shortcut.Exists)
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(shortcut.FullName);
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
if (!line.StartsWith("Exec=\""))
|
||||||
|
continue;
|
||||||
|
var path = line.Split('"').Where((item, index) => index == 1).SingleOrDefault();
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (installInfos.Any(a => a.Path == path)) // avoid adding similar build as from toolbox
|
||||||
|
continue;
|
||||||
|
installInfos.Add(new RiderInfo(path, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// snap install
|
||||||
|
var snapInstallPath = "/snap/rider/current/bin/rider.sh";
|
||||||
|
if (new FileInfo(snapInstallPath).Exists)
|
||||||
|
installInfos.Add(new RiderInfo(snapInstallPath, false));
|
||||||
|
|
||||||
|
return installInfos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RiderInfo[] CollectRiderInfosMac()
|
||||||
|
{
|
||||||
|
var installInfos = new List<RiderInfo>();
|
||||||
|
// "/Applications/*Rider*.app"
|
||||||
|
var folder = new DirectoryInfo("/Applications");
|
||||||
|
if (folder.Exists)
|
||||||
|
{
|
||||||
|
installInfos.AddRange(folder.GetDirectories("*Rider*.app")
|
||||||
|
.Select(a => new RiderInfo(a.FullName, false))
|
||||||
|
.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
// /Users/user/Library/Application Support/JetBrains/Toolbox/apps/Rider/ch-1/181.3870.267/Rider EAP.app
|
||||||
|
var toolboxRiderRootPath = GetToolboxBaseDir();
|
||||||
|
var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "", "Rider*.app", true)
|
||||||
|
.Select(a => new RiderInfo(a, true));
|
||||||
|
installInfos.AddRange(paths);
|
||||||
|
|
||||||
|
return installInfos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RiderInfo[] CollectRiderInfosWindows()
|
||||||
|
{
|
||||||
|
var installInfos = new List<RiderInfo>();
|
||||||
|
var toolboxRiderRootPath = GetToolboxBaseDir();
|
||||||
|
var installPathsToolbox = CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider64.exe", false).ToList();
|
||||||
|
installInfos.AddRange(installPathsToolbox.Select(a => new RiderInfo(a, true)).ToList());
|
||||||
|
|
||||||
|
var installPaths = new List<string>();
|
||||||
|
const string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||||
|
CollectPathsFromRegistry(registryKey, installPaths);
|
||||||
|
const string wowRegistryKey = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||||
|
CollectPathsFromRegistry(wowRegistryKey, installPaths);
|
||||||
|
|
||||||
|
installInfos.AddRange(installPaths.Select(a => new RiderInfo(a, false)).ToList());
|
||||||
|
|
||||||
|
return installInfos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetToolboxBaseDir()
|
||||||
|
{
|
||||||
|
if (OS.IsWindows)
|
||||||
|
{
|
||||||
|
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
return Path.Combine(localAppData, @"JetBrains\Toolbox\apps\Rider");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OS.IsOSX)
|
||||||
|
{
|
||||||
|
var home = Environment.GetEnvironmentVariable("HOME");
|
||||||
|
if (!string.IsNullOrEmpty(home))
|
||||||
|
{
|
||||||
|
return Path.Combine(home, @"Library/Application Support/JetBrains/Toolbox/apps/Rider");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OS.IsUnixLike())
|
||||||
|
{
|
||||||
|
var home = Environment.GetEnvironmentVariable("HOME");
|
||||||
|
if (!string.IsNullOrEmpty(home))
|
||||||
|
{
|
||||||
|
return Path.Combine(home, @".local/share/JetBrains/Toolbox/apps/Rider");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Unexpected OS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ProductInfo GetBuildVersion(string path)
|
||||||
|
{
|
||||||
|
var buildTxtFileInfo = new FileInfo(Path.Combine(path, GetRelativePathToBuildTxt()));
|
||||||
|
var dir = buildTxtFileInfo.DirectoryName;
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
return null;
|
||||||
|
var buildVersionFile = new FileInfo(Path.Combine(dir, "product-info.json"));
|
||||||
|
if (!buildVersionFile.Exists)
|
||||||
|
return null;
|
||||||
|
var json = File.ReadAllText(buildVersionFile.FullName);
|
||||||
|
return ProductInfo.GetProductInfo(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Version GetBuildNumber(string path)
|
||||||
|
{
|
||||||
|
var file = new FileInfo(Path.Combine(path, GetRelativePathToBuildTxt()));
|
||||||
|
if (!file.Exists)
|
||||||
|
return null;
|
||||||
|
var text = File.ReadAllText(file.FullName);
|
||||||
|
if (text.Length <= 3)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var versionText = text.Substring(3);
|
||||||
|
return Version.TryParse(versionText, out var v) ? v : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsToolbox(string path)
|
||||||
|
{
|
||||||
|
return path.StartsWith(GetToolboxBaseDir());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRelativePathToBuildTxt()
|
||||||
|
{
|
||||||
|
if (OS.IsWindows || OS.IsUnixLike())
|
||||||
|
return "../../build.txt";
|
||||||
|
if (OS.IsOSX)
|
||||||
|
return "Contents/Resources/build.txt";
|
||||||
|
throw new Exception("Unknown OS.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CollectPathsFromRegistry(string registryKey, List<string> installPaths)
|
||||||
|
{
|
||||||
|
using (var key = Registry.LocalMachine.OpenSubKey(registryKey))
|
||||||
|
{
|
||||||
|
if (key == null) return;
|
||||||
|
foreach (var subkeyName in key.GetSubKeyNames().Where(a => a.Contains("Rider")))
|
||||||
|
{
|
||||||
|
using (var subkey = key.OpenSubKey(subkeyName))
|
||||||
|
{
|
||||||
|
var folderObject = subkey?.GetValue("InstallLocation");
|
||||||
|
if (folderObject == null) continue;
|
||||||
|
var folder = folderObject.ToString();
|
||||||
|
var possiblePath = Path.Combine(folder, @"bin\rider64.exe");
|
||||||
|
if (File.Exists(possiblePath))
|
||||||
|
installPaths.Add(possiblePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] CollectPathsFromToolbox(string toolboxRiderRootPath, string dirName, string searchPattern,
|
||||||
|
bool isMac)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(toolboxRiderRootPath))
|
||||||
|
return new string[0];
|
||||||
|
|
||||||
|
var channelDirs = Directory.GetDirectories(toolboxRiderRootPath);
|
||||||
|
var paths = channelDirs.SelectMany(channelDir =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// use history.json - last entry stands for the active build https://jetbrains.slack.com/archives/C07KNP99D/p1547807024066500?thread_ts=1547731708.057700&cid=C07KNP99D
|
||||||
|
var historyFile = Path.Combine(channelDir, ".history.json");
|
||||||
|
if (File.Exists(historyFile))
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(historyFile);
|
||||||
|
var build = ToolboxHistory.GetLatestBuildFromJson(json);
|
||||||
|
if (build != null)
|
||||||
|
{
|
||||||
|
var buildDir = Path.Combine(channelDir, build);
|
||||||
|
var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir);
|
||||||
|
if (executablePaths.Any())
|
||||||
|
return executablePaths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var channelFile = Path.Combine(channelDir, ".channel.settings.json");
|
||||||
|
if (File.Exists(channelFile))
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(channelFile).Replace("active-application", "active_application");
|
||||||
|
var build = ToolboxInstallData.GetLatestBuildFromJson(json);
|
||||||
|
if (build != null)
|
||||||
|
{
|
||||||
|
var buildDir = Path.Combine(channelDir, build);
|
||||||
|
var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir);
|
||||||
|
if (executablePaths.Any())
|
||||||
|
return executablePaths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// changes in toolbox json files format may brake the logic above, so return all found Rider installations
|
||||||
|
return Directory.GetDirectories(channelDir)
|
||||||
|
.SelectMany(buildDir => GetExecutablePaths(dirName, searchPattern, isMac, buildDir));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// do not write to Debug.Log, just log it.
|
||||||
|
Logger.Warn($"Failed to get RiderPath from {channelDir}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string[0];
|
||||||
|
})
|
||||||
|
.Where(c => !string.IsNullOrEmpty(c))
|
||||||
|
.ToArray();
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] GetExecutablePaths(string dirName, string searchPattern, bool isMac, string buildDir)
|
||||||
|
{
|
||||||
|
var folder = new DirectoryInfo(Path.Combine(buildDir, dirName));
|
||||||
|
if (!folder.Exists)
|
||||||
|
return new string[0];
|
||||||
|
|
||||||
|
if (!isMac)
|
||||||
|
return new[] {Path.Combine(folder.FullName, searchPattern)}.Where(File.Exists).ToArray();
|
||||||
|
return folder.GetDirectories(searchPattern).Select(f => f.FullName)
|
||||||
|
.Where(Directory.Exists).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the "field is never assigned" compiler warning. We never assign it, but Unity does.
|
||||||
|
// Note that Unity disable this warning in the generated C# projects
|
||||||
|
#pragma warning disable 0649
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
class ToolboxHistory
|
||||||
|
{
|
||||||
|
public List<ItemNode> history;
|
||||||
|
|
||||||
|
public static string GetLatestBuildFromJson(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<ToolboxHistory>(json).history.LastOrDefault()?.item.build;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Logger.Warn($"Failed to get latest build from json {json}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
class ItemNode
|
||||||
|
{
|
||||||
|
public BuildNode item;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
class BuildNode
|
||||||
|
{
|
||||||
|
public string build;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ProductInfo
|
||||||
|
{
|
||||||
|
public string version;
|
||||||
|
public string versionSuffix;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
internal static ProductInfo GetProductInfo(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var productInfo = JsonConvert.DeserializeObject<ProductInfo>(json);
|
||||||
|
return productInfo;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Logger.Warn($"Failed to get version from json {json}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once ClassNeverInstantiated.Global
|
||||||
|
[Serializable]
|
||||||
|
class ToolboxInstallData
|
||||||
|
{
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public ActiveApplication active_application;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
public static string GetLatestBuildFromJson(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toolbox = JsonConvert.DeserializeObject<ToolboxInstallData>(json);
|
||||||
|
var builds = toolbox.active_application.builds;
|
||||||
|
if (builds != null && builds.Any())
|
||||||
|
return builds.First();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Logger.Warn($"Failed to get latest build from json {json}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
class ActiveApplication
|
||||||
|
{
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public List<string> builds;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore 0649
|
||||||
|
|
||||||
|
public struct RiderInfo
|
||||||
|
{
|
||||||
|
public bool IsToolbox;
|
||||||
|
public string Presentation;
|
||||||
|
public Version BuildNumber;
|
||||||
|
public ProductInfo ProductInfo;
|
||||||
|
public string Path;
|
||||||
|
|
||||||
|
public RiderInfo(string path, bool isToolbox)
|
||||||
|
{
|
||||||
|
BuildNumber = GetBuildNumber(path);
|
||||||
|
ProductInfo = GetBuildVersion(path);
|
||||||
|
Path = new FileInfo(path).FullName; // normalize separators
|
||||||
|
var presentation = $"Rider {BuildNumber}";
|
||||||
|
|
||||||
|
if (ProductInfo != null && !string.IsNullOrEmpty(ProductInfo.version))
|
||||||
|
{
|
||||||
|
var suffix = string.IsNullOrEmpty(ProductInfo.versionSuffix) ? "" : $" {ProductInfo.versionSuffix}";
|
||||||
|
presentation = $"Rider {ProductInfo.version}{suffix}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isToolbox)
|
||||||
|
presentation += " (JetBrains Toolbox)";
|
||||||
|
|
||||||
|
Presentation = presentation;
|
||||||
|
IsToolbox = isToolbox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Logger
|
||||||
|
{
|
||||||
|
internal static void Warn(string message, Exception e = null)
|
||||||
|
{
|
||||||
|
throw new Exception(message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Godot;
|
||||||
|
using GodotTools.Internals;
|
||||||
|
|
||||||
|
namespace GodotTools.Ides.Rider
|
||||||
|
{
|
||||||
|
public static class RiderPathManager
|
||||||
|
{
|
||||||
|
private static readonly string editorPathSettingName= "mono/editor/editor_path_optional";
|
||||||
|
|
||||||
|
private static string GetRiderPathFromSettings()
|
||||||
|
{
|
||||||
|
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||||
|
if (editorSettings.HasSetting(editorPathSettingName))
|
||||||
|
return (string) editorSettings.GetSetting(editorPathSettingName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||||
|
var editor = (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor");
|
||||||
|
if (editor == ExternalEditorId.Rider)
|
||||||
|
{
|
||||||
|
if (!editorSettings.HasSetting(editorPathSettingName))
|
||||||
|
{
|
||||||
|
Globals.EditorDef(editorPathSettingName, "Optional");
|
||||||
|
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
|
||||||
|
{
|
||||||
|
["type"] = Variant.Type.String,
|
||||||
|
["name"] = editorPathSettingName,
|
||||||
|
["hint"] = PropertyHint.File,
|
||||||
|
["hint_string"] = ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var riderPath = (string) editorSettings.GetSetting(editorPathSettingName);
|
||||||
|
if (IsRiderAndExists(riderPath))
|
||||||
|
{
|
||||||
|
Globals.EditorDef(editorPathSettingName, riderPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var paths = RiderPathLocator.GetAllRiderPaths();
|
||||||
|
|
||||||
|
if (!paths.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newPath = paths.Last().Path;
|
||||||
|
Globals.EditorDef(editorPathSettingName, newPath);
|
||||||
|
editorSettings.SetSetting(editorPathSettingName, newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsRider(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileInfo = new FileInfo(path);
|
||||||
|
var filename = fileInfo.Name.ToLowerInvariant();
|
||||||
|
return filename.StartsWith("rider", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CheckAndUpdatePath(string riderPath)
|
||||||
|
{
|
||||||
|
if (IsRiderAndExists(riderPath))
|
||||||
|
{
|
||||||
|
return riderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||||
|
var paths = RiderPathLocator.GetAllRiderPaths();
|
||||||
|
|
||||||
|
if (!paths.Any())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var newPath = paths.Last().Path;
|
||||||
|
editorSettings.SetSetting(editorPathSettingName, newPath);
|
||||||
|
Globals.EditorDef(editorPathSettingName, newPath);
|
||||||
|
return newPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsRiderAndExists(string riderPath)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(riderPath) && IsRider(riderPath) && new FileInfo(riderPath).Exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenFile(string slnPath, string scriptPath, int line)
|
||||||
|
{
|
||||||
|
var pathFromSettings = GetRiderPathFromSettings();
|
||||||
|
var path = CheckAndUpdatePath(pathFromSettings);
|
||||||
|
|
||||||
|
var args = new List<string>();
|
||||||
|
args.Add(slnPath);
|
||||||
|
if (line >= 0)
|
||||||
|
{
|
||||||
|
args.Add("--line");
|
||||||
|
args.Add(line.ToString());
|
||||||
|
}
|
||||||
|
args.Add(scriptPath);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Utils.OS.RunProcess(path, args);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
GD.PushError($"Error when trying to run code editor: JetBrains Rider. Exception message: '{e.Message}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -157,6 +157,8 @@ namespace GodotTools.Utils
|
||||||
|
|
||||||
process.BeginOutputReadLine();
|
process.BeginOutputReadLine();
|
||||||
process.BeginErrorReadLine();
|
process.BeginErrorReadLine();
|
||||||
|
if (IsWindows && process.Id>0)
|
||||||
|
User32Dll.AllowSetForegroundWindow(process.Id); // allows application to focus itself
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
modules/mono/editor/GodotTools/GodotTools/Utils/User32Dll.cs
Normal file
10
modules/mono/editor/GodotTools/GodotTools/Utils/User32Dll.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace GodotTools.Utils
|
||||||
|
{
|
||||||
|
public static class User32Dll
|
||||||
|
{
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool AllowSetForegroundWindow(int dwProcessId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="JetBrains.Annotations" version="2019.1.3" targetFramework="net45" />
|
||||||
|
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" />
|
||||||
|
</packages>
|
Loading…
Reference in a new issue