From c2b97ec1f7f0bf02b1f87de3a00419caff91f23c Mon Sep 17 00:00:00 2001 From: Kevin Simpson Date: Mon, 6 Mar 2023 13:54:56 -0800 Subject: [PATCH] Add the ability to set a custom C# editor This allows users to still use the built-in Godot editor for GDScript. --- .../GodotTools/GodotTools/ExternalEditorId.cs | 3 +- .../GodotTools/GodotTools/GodotSharpEditor.cs | 87 ++++++++++++++++++- .../GodotTools/Ides/GodotIdeManager.cs | 3 + 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs b/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs index 90d6eb960e0..049cc58512b 100644 --- a/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs +++ b/modules/mono/editor/GodotTools/GodotTools/ExternalEditorId.cs @@ -7,6 +7,7 @@ namespace GodotTools VisualStudioForMac, // Mac-only MonoDevelop, VsCode, - Rider + Rider, + CustomEditor } } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 9eefa3c386c..26239a7ce5d 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -25,6 +25,8 @@ namespace GodotTools public static class Settings { public const string ExternalEditor = "dotnet/editor/external_editor"; + public const string CustomExecPath = "dotnet/editor/custom_exec_path"; + public const string CustomExecPathArgs = "dotnet/editor/custom_exec_path_args"; public const string VerbosityLevel = "dotnet/build/verbosity_level"; public const string NoConsoleLogging = "dotnet/build/no_console_logging"; public const string CreateBinaryLog = "dotnet/build/create_binary_log"; @@ -185,6 +187,66 @@ namespace GodotTools case ExternalEditorId.None: // Not an error. Tells the caller to fallback to the global external editor settings or the built-in editor. return Error.Unavailable; + case ExternalEditorId.CustomEditor: + { + string file = ProjectSettings.GlobalizePath(script.ResourcePath); + var execCommand = _editorSettings.GetSetting(Settings.CustomExecPath).As(); + var execArgs = _editorSettings.GetSetting(Settings.CustomExecPathArgs).As(); + var args = new List(); + var from = 0; + var numChars = 0; + var insideQuotes = false; + var hasFileFlag = false; + + execArgs = execArgs.ReplaceN("{line}", line.ToString()); + execArgs = execArgs.ReplaceN("{col}", col.ToString()); + execArgs = execArgs.StripEdges(true, true); + execArgs = execArgs.Replace("\\\\", "\\"); + + for (int i = 0; i < execArgs.Length; ++i) + { + if ((execArgs[i] == '"' && (i == 0 || execArgs[i - 1] != '\\')) && i != execArgs.Length - 1) + { + if (!insideQuotes) + { + from++; + } + insideQuotes = !insideQuotes; + } + else if ((execArgs[i] == ' ' && !insideQuotes) || i == execArgs.Length - 1) + { + if (i == execArgs.Length - 1 && !insideQuotes) + { + numChars++; + } + + var arg = execArgs.Substr(from, numChars); + if (arg.Contains("{file}")) + { + hasFileFlag = true; + } + + arg = arg.ReplaceN("{file}", file); + args.Add(arg); + + from = i + 1; + numChars = 0; + } + else + { + numChars++; + } + } + + if (!hasFileFlag) + { + args.Add(file); + } + + OS.RunProcess(execCommand, args); + + break; + } case ExternalEditorId.VisualStudio: { string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath); @@ -463,6 +525,8 @@ namespace GodotTools // External editor settings EditorDef(Settings.ExternalEditor, Variant.From(ExternalEditorId.None)); + EditorDef(Settings.CustomExecPath, ""); + EditorDef(Settings.CustomExecPathArgs, ""); EditorDef(Settings.VerbosityLevel, Variant.From(VerbosityLevelId.Normal)); EditorDef(Settings.NoConsoleLogging, false); EditorDef(Settings.CreateBinaryLog, false); @@ -474,20 +538,23 @@ namespace GodotTools settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" + $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" + - $",JetBrains Rider:{(int)ExternalEditorId.Rider}"; + $",JetBrains Rider:{(int)ExternalEditorId.Rider}" + + $",Custom:{(int)ExternalEditorId.CustomEditor}"; } else if (OS.IsMacOS) { settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" + $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" + - $",JetBrains Rider:{(int)ExternalEditorId.Rider}"; + $",JetBrains Rider:{(int)ExternalEditorId.Rider}" + + $",Custom:{(int)ExternalEditorId.CustomEditor}"; } else if (OS.IsUnixLike) { settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" + - $",JetBrains Rider:{(int)ExternalEditorId.Rider}"; + $",JetBrains Rider:{(int)ExternalEditorId.Rider}" + + $",Custom:{(int)ExternalEditorId.CustomEditor}"; } _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary @@ -498,6 +565,20 @@ namespace GodotTools ["hint_string"] = settingsHintStr }); + _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary + { + ["type"] = (int)Variant.Type.String, + ["name"] = Settings.CustomExecPath, + ["hint"] = (int)PropertyHint.GlobalFile, + }); + + _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary + { + ["type"] = (int)Variant.Type.String, + ["name"] = Settings.CustomExecPathArgs, + }); + _editorSettings.SetInitialValue(Settings.CustomExecPathArgs, "{file}", false); + var verbosityLevels = Enum.GetValues().Select(level => $"{Enum.GetName(level)}:{(int)level}"); _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary { diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs index 83621ce5afb..5d1a2277f96 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs @@ -70,6 +70,8 @@ namespace GodotTools.Ides return "VisualStudioForMac"; case ExternalEditorId.MonoDevelop: return "MonoDevelop"; + case ExternalEditorId.CustomEditor: + return "CustomEditor"; default: throw new NotImplementedException(); } @@ -105,6 +107,7 @@ namespace GodotTools.Ides case ExternalEditorId.VisualStudio: case ExternalEditorId.VsCode: case ExternalEditorId.Rider: + case ExternalEditorId.CustomEditor: throw new NotSupportedException(); case ExternalEditorId.VisualStudioForMac: goto case ExternalEditorId.MonoDevelop;