From a0709aab61044de719038d50ca135b8230791359 Mon Sep 17 00:00:00 2001 From: OmerCD Date: Thu, 11 Dec 2025 17:57:35 +0000 Subject: [PATCH] Add source generator for input map names. --- src/SharpIDE.Godot/SharpIDE.Godot.csproj | 10 +++ src/SharpIDE.Godot/SharpIDE.Godot.sln | 8 +++ ...nputStringNames.cs => ThemeStringNames.cs} | 11 --- ...ngNames.cs.uid => ThemeStringNames.cs.uid} | 0 .../InputMapName/InputMapNameConstants.cs | 16 +++++ .../InputMapName/InputMapNameGenerator.cs | 67 +++++++++++++++++++ .../Properties/launchSettings.json | 9 +++ .../SharpIDE.SourceGenerators.csproj | 26 +++++++ 8 files changed, 136 insertions(+), 11 deletions(-) rename src/SharpIDE.Godot/{InputStringNames.cs => ThemeStringNames.cs} (54%) rename src/SharpIDE.Godot/{InputStringNames.cs.uid => ThemeStringNames.cs.uid} (100%) create mode 100644 src/SharpIDE.SourceGenerators/InputMapName/InputMapNameConstants.cs create mode 100644 src/SharpIDE.SourceGenerators/InputMapName/InputMapNameGenerator.cs create mode 100644 src/SharpIDE.SourceGenerators/Properties/launchSettings.json create mode 100644 src/SharpIDE.SourceGenerators/SharpIDE.SourceGenerators.csproj diff --git a/src/SharpIDE.Godot/SharpIDE.Godot.csproj b/src/SharpIDE.Godot/SharpIDE.Godot.csproj index 36bf2b10..c023ca0a 100644 --- a/src/SharpIDE.Godot/SharpIDE.Godot.csproj +++ b/src/SharpIDE.Godot/SharpIDE.Godot.csproj @@ -26,7 +26,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/SharpIDE.Godot/SharpIDE.Godot.sln b/src/SharpIDE.Godot/SharpIDE.Godot.sln index 5f231ac3..606bd0e1 100644 --- a/src/SharpIDE.Godot/SharpIDE.Godot.sln +++ b/src/SharpIDE.Godot/SharpIDE.Godot.sln @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\..\.globalconfig = ..\..\.globalconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpIDE.SourceGenerators", "..\SharpIDE.SourceGenerators\SharpIDE.SourceGenerators.csproj", "{3EE9E01D-5C04-4C6D-89DD-D85F1F527976}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,5 +46,11 @@ Global {DFF170D9-D92E-4DB7-83B5-19640EAF79D2}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU {DFF170D9-D92E-4DB7-83B5-19640EAF79D2}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU {DFF170D9-D92E-4DB7-83B5-19640EAF79D2}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.ExportDebug|Any CPU.ActiveCfg = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.ExportDebug|Any CPU.Build.0 = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.ExportRelease|Any CPU.ActiveCfg = Debug|Any CPU + {3EE9E01D-5C04-4C6D-89DD-D85F1F527976}.ExportRelease|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection EndGlobal diff --git a/src/SharpIDE.Godot/InputStringNames.cs b/src/SharpIDE.Godot/ThemeStringNames.cs similarity index 54% rename from src/SharpIDE.Godot/InputStringNames.cs rename to src/SharpIDE.Godot/ThemeStringNames.cs index 7907e5f2..a37086ec 100644 --- a/src/SharpIDE.Godot/InputStringNames.cs +++ b/src/SharpIDE.Godot/ThemeStringNames.cs @@ -2,17 +2,6 @@ namespace SharpIDE.Godot; -public static class InputStringNames -{ - public static readonly StringName RenameSymbol = nameof(RenameSymbol); - public static readonly StringName CodeFixes = nameof(CodeFixes); - public static readonly StringName StepOver = nameof(StepOver); - public static readonly StringName FindInFiles = nameof(FindInFiles); - public static readonly StringName FindFiles = nameof(FindFiles); - public static readonly StringName SaveFile = nameof(SaveFile); - public static readonly StringName SaveAllFiles = nameof(SaveAllFiles); -} - public static class ThemeStringNames { public static readonly StringName Font = "font"; diff --git a/src/SharpIDE.Godot/InputStringNames.cs.uid b/src/SharpIDE.Godot/ThemeStringNames.cs.uid similarity index 100% rename from src/SharpIDE.Godot/InputStringNames.cs.uid rename to src/SharpIDE.Godot/ThemeStringNames.cs.uid diff --git a/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameConstants.cs b/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameConstants.cs new file mode 100644 index 00000000..29432977 --- /dev/null +++ b/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameConstants.cs @@ -0,0 +1,16 @@ +namespace SharpIDE.SourceGenerators.InputMapName; + +public class InputMapNameConstants +{ + public const string PropertiesPlaceholder = "{Properties}"; + public const string Code = $$""" + // + using Godot; + namespace SharpIDE.Godot; + + public static partial class InputStringNames + { + {{PropertiesPlaceholder}} + } + """; +} diff --git a/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameGenerator.cs b/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameGenerator.cs new file mode 100644 index 00000000..67f3204d --- /dev/null +++ b/src/SharpIDE.SourceGenerators/InputMapName/InputMapNameGenerator.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis; + +namespace SharpIDE.SourceGenerators.InputMapName; + +[Generator] +public class InputMapNameGenerator : IIncrementalGenerator +{ + private static readonly Regex _inputNameRegex = new(@"\b(\w+)\s*=\s*\{", RegexOptions.Compiled); + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var inputMapNamesProvider = context.AdditionalTextsProvider + .Where(at => Path.GetFileName(at.Path).Equals("project.godot", StringComparison.OrdinalIgnoreCase)); + context.RegisterSourceOutput(inputMapNamesProvider, GenerateInputMapNames); + } + + private static void GenerateInputMapNames(SourceProductionContext context, AdditionalText additionalText) + { + var text = additionalText.GetText(context.CancellationToken); + if (text is null) + return; + + // Parse the input map names from the project.godot file + var matchCollection = _inputNameRegex.Matches(text.ToString()); + var inputMapNames = matchCollection.Cast().Select(match => match.Groups[1].Value).ToList(); + + // Generate the source code + var sourceText = InputMapNameConstants.Code.Replace(InputMapNameConstants.PropertiesPlaceholder, GenerateProperties(inputMapNames)); + + // Add the source code to the compilation + context.AddSource("InputMapNames.g.cs", sourceText); + } + + private static string GenerateProperties(IEnumerable inputMapNames) + { + var propertiesBuilder = new System.Text.StringBuilder(); + foreach (var name in inputMapNames) + { + var safeName = SanitizeIdentifier(name); + propertiesBuilder.AppendLine($"\tpublic const string {safeName} = \"{name}\";"); + } + return propertiesBuilder.ToString(); + } + /// + /// Sanitizes a string to be a valid C# identifier. + /// Replaces invalid characters with underscores and ensures the identifier does not start with a digit. + /// + private static string SanitizeIdentifier(string name) + { + if (string.IsNullOrEmpty(name)) + return "_"; + + // Remove invalid characters + var sanitized = Regex.Replace(name, "[^a-zA-Z0-9_]", ""); + + // If the first character is not a letter or underscore, prefix with underscore + if (!char.IsLetter(sanitized, 0) && sanitized[0] != '_') + sanitized = "_" + sanitized; + + return sanitized; + } +} diff --git a/src/SharpIDE.SourceGenerators/Properties/launchSettings.json b/src/SharpIDE.SourceGenerators/Properties/launchSettings.json new file mode 100644 index 00000000..3c38c4ac --- /dev/null +++ b/src/SharpIDE.SourceGenerators/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "SharpIDE.SourceGenerators": { + "commandName": "DebugRoslynComponent", + "targetProject": "../SharpIDE.Godot/SharpIDE.Godot.csproj" + } + } +} diff --git a/src/SharpIDE.SourceGenerators/SharpIDE.SourceGenerators.csproj b/src/SharpIDE.SourceGenerators/SharpIDE.SourceGenerators.csproj new file mode 100644 index 00000000..c5d3962f --- /dev/null +++ b/src/SharpIDE.SourceGenerators/SharpIDE.SourceGenerators.csproj @@ -0,0 +1,26 @@ + + + + false + false + netstandard2.0 + false + enable + latest + + true + true + + SharpIDE.SourceGenerators + SharpIDE.SourceGenerators + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + +