diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py
index 03aaa925f08f..6e5273f5e00d 100644
--- a/modules/mono/build_scripts/godot_tools_build.py
+++ b/modules/mono/build_scripts/godot_tools_build.py
@@ -82,7 +82,8 @@ def build(env_mono, api_sln_cmd):
target_filenames = [
'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':
diff --git a/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs b/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs
index 4312ca0230ed..bb218c2f190a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs
@@ -6,6 +6,7 @@ public enum ExternalEditorId
VisualStudio, // TODO (Windows-only)
VisualStudioForMac, // Mac-only
MonoDevelop,
- VsCode
+ VsCode,
+ Rider
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 2a5d3de1266f..660971d91249 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -6,8 +6,10 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using GodotTools.Ides;
+using GodotTools.Ides.Rider;
using GodotTools.Internals;
using GodotTools.ProjectEditor;
+using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS;
@@ -189,6 +191,7 @@ public void ShowErrorDialog(string message, string title = "Error")
"code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss"
};
+ [UsedImplicitly]
public Error OpenInExternalEditor(Script script, int line, int col)
{
var editor = (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor");
@@ -202,6 +205,12 @@ public Error OpenInExternalEditor(Script script, int line, int col)
throw new NotSupportedException();
case ExternalEditorId.VisualStudioForMac:
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:
{
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
@@ -306,6 +315,7 @@ public Error OpenInExternalEditor(Script script, int line, int col)
return Error.Ok;
}
+ [UsedImplicitly]
public bool OverridesExternalEditor()
{
return (ExternalEditorId) editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None;
@@ -419,18 +429,21 @@ public override void EnablePlugin()
if (OS.IsWindows)
{
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)
{
settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" +
$",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())
{
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
@@ -448,6 +461,7 @@ public override void EnablePlugin()
exportPluginWeak = WeakRef(exportPlugin);
BuildManager.Initialize();
+ RiderPathManager.Initialize();
GodotIdeManager = new GodotIdeManager();
AddChild(GodotIdeManager);
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index fb2cbabc8ec9..be2b70529eb1 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -30,7 +30,15 @@
false
+
+ ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll
+ True
+
+
+ ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+ True
+
$(GodotSourceRootPath)/bin/GodotSharp/Api/$(GodotApiConfiguration)/GodotSharp.dll
@@ -47,6 +55,8 @@
+
+
@@ -67,6 +77,7 @@
+
@@ -86,5 +97,11 @@
GodotTools.Core
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
index f94d6f998cc9..3213de012737 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -72,6 +72,7 @@ private void LaunchIde()
case ExternalEditorId.None:
case ExternalEditorId.VisualStudio:
case ExternalEditorId.VsCode:
+ case ExternalEditorId.Rider:
throw new NotSupportedException();
case ExternalEditorId.VisualStudioForMac:
goto case ExternalEditorId.MonoDevelop;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/.editorconfig b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/.editorconfig
new file mode 100644
index 000000000000..aca19790ca3d
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/.editorconfig
@@ -0,0 +1,6 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
\ No newline at end of file
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
new file mode 100644
index 000000000000..901ade71e3fc
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
@@ -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
+{
+ ///
+ /// 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
+ ///
+ 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();
+ 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();
+ // "/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();
+ 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();
+ 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 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 history;
+
+ public static string GetLatestBuildFromJson(string json)
+ {
+ try
+ {
+ return JsonConvert.DeserializeObject(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(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(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 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);
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
new file mode 100644
index 000000000000..b7dba13bbe25
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -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();
+ 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}'");
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index e89ea0c476dc..1fe07e0bb6ef 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -157,6 +157,8 @@ string CmdLineArgsToString(IEnumerable args)
process.BeginOutputReadLine();
process.BeginErrorReadLine();
+ if (IsWindows && process.Id>0)
+ User32Dll.AllowSetForegroundWindow(process.Id); // allows application to focus itself
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/User32Dll.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/User32Dll.cs
new file mode 100644
index 000000000000..6810a991b341
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/User32Dll.cs
@@ -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);
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/packages.config b/modules/mono/editor/GodotTools/GodotTools/packages.config
new file mode 100644
index 000000000000..2db4b4acc638
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file