From 9dc0f3d12880735b69216dc78cb7a66e8b390be5 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Mon, 5 Aug 2024 10:54:11 -0600 Subject: [PATCH 01/10] fix: Window title not shown when packaged --- src/.nuspec/Uno.Resizetizer.targets | 30 ++--- .../Resizetizer.Generators.csproj | 33 +++++ .../WindowTitleGenerator.cs | 115 ++++++++++++++++++ src/Resizetizer/src/Resizetizer.csproj | 18 ++- .../src/WindowIconGeneratorTask.cs | 108 ---------------- src/Resizetizer/uno.resizetizer.sln | 8 ++ 6 files changed, 180 insertions(+), 132 deletions(-) create mode 100644 src/Resizetizer/Resizetizer.Generators/Resizetizer.Generators.csproj create mode 100644 src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs delete mode 100644 src/Resizetizer/src/WindowIconGeneratorTask.cs diff --git a/src/.nuspec/Uno.Resizetizer.targets b/src/.nuspec/Uno.Resizetizer.targets index 9cd40b93..d5cd7da7 100644 --- a/src/.nuspec/Uno.Resizetizer.targets +++ b/src/.nuspec/Uno.Resizetizer.targets @@ -48,10 +48,6 @@ AssemblyFile="$(_UnoResizetizerTaskAssemblyName)" TaskName="Uno.Resizetizer.GenerateWasmSplashAssets_v0"/> - - @@ -589,25 +585,13 @@ - - - - $([MSBuild]::ValueOrDefault('$(ApplicationTitle)', '$(AssemblyName)')) - - - - - - + + + + + + + netstandard2.0 + false + true + analyzers/dotnet/cs + latest + false + + System.Runtime.CompilerServices.IsExternalInit; + System.Diagnostics.CodeAnalysis.NotNullWhenAttribute; + + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs new file mode 100644 index 00000000..699f5b22 --- /dev/null +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -0,0 +1,115 @@ +using System.IO; +using CodeGenHelpers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Resizetizer.Generators; + +[Generator(LanguageNames.CSharp)] +internal sealed class WindowTitleGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + var options = context.AnalyzerConfigOptions.GlobalOptions; + if (!GetProperty(options, "IsUnoHead") || !HasUnoIcon(options, out var unoIcon)) + { + return; + } + + GenerateLegacyNamespaceCompat(context); + + GenerateWindowTitleExtension(context, unoIcon); + } + + public void Initialize(GeneratorInitializationContext context) + { + } + + private static void GenerateWindowTitleExtension(GeneratorExecutionContext context, string unoIcon) + { + var options = context.AnalyzerConfigOptions.GlobalOptions; + var rootNamespace = GetPropertyValue(options, "RootNamespace"); + var iconName = Path.GetFileNameWithoutExtension(unoIcon); + var windowTitle = GetPropertyValue(options, "ApplicationTitle"); + if (string.IsNullOrEmpty(windowTitle)) + { + windowTitle = context.Compilation.AssemblyName!; + } + + var builder = CodeBuilder.Create(rootNamespace) + .AddClass("WindowExtensions") + .MakeStaticClass() + .WithSummary(@"Extension methods for the class."); + + builder.AddMethod("SetWindowIcon") + .AddParameter("this global::Microsoft.UI.Xaml.Window", "window") + .MakeStaticMethod() + .MakePublicMethod() + .WithSummary(@"This will set the Window Icon for the given using the provided UnoIcon.") + .WithBody(w => + { + w.AppendUnindentedLine("#if WINDOWS && !HAS_UNO"); + w.AppendLine("var hWnd = global::WinRT.Interop.WindowNative.GetWindowHandle(window);"); + w.NewLine(); + w.AppendLine("// Retrieve the WindowId that corresponds to hWnd."); + w.AppendLine("global::Microsoft.UI.WindowId windowId = global::Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);"); + w.NewLine(); + w.AppendLine("// Lastly, retrieve the AppWindow for the current (XAML) WinUI 3 window."); + w.AppendLine("global::Microsoft.UI.Windowing.AppWindow appWindow = global::Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);"); + w.AppendLine($@"appWindow.SetIcon(""{iconName}.ico"");"); + w.NewLine(); + w.AppendLine("// Set the Window Title Only if it has the Default WinUI Desktop value and we are running Unpackaged"); + // We're no longer checking for IsPackaged as this seems to be needed when Packaged as well. + w.If(@"appWindow.Title == ""WinUI Desktop""") + .WithBody(b => + { + b.AppendLine($@"appWindow.Title = ""{windowTitle}"";"); + }) + .EndIf(); + w.AppendUnindentedLine("#endif"); + }); + + //builder.AddMethod("IsPackaged") + // .WithReturnType("bool") + // .MakePrivateMethod() + // .MakeStaticMethod() + // .WithBody(w => + // { + // using (w.Block("try")) + // { + // w.AppendLine("return global::Windows.ApplicationModel.Package.Current != null;"); + // } + // using (w.Block("catch")) + // { + // w.AppendLine("return false;"); + // } + // }); + + AddSource(context, builder); + } + + private static string GetPropertyValue(AnalyzerConfigOptions options, string key) => + options.TryGetValue($"build_property.{key}", out var value) ? value : string.Empty; + + private static bool GetProperty(AnalyzerConfigOptions options, string key) => + bool.TryParse(GetPropertyValue(options, key), out var result) && result; + + private static bool HasUnoIcon(AnalyzerConfigOptions options, out string unoIcon) + { + unoIcon = GetPropertyValue(options, "UnoIcon"); + return !string.IsNullOrEmpty(unoIcon) && !unoIcon.Contains(","); + } + + private static void GenerateLegacyNamespaceCompat(GeneratorExecutionContext context) + { + var builder = CodeBuilder.Create("Uno.Resizetizer") + .AddClass("__LegacyResizetizerSupport__") + .WithSummary("This is added to ensure the Uno.Resizetizer namespace is present to avoid breaking any applications.") + .MakeStaticClass(); + + AddSource(context, builder); + } + + private static void AddSource(GeneratorExecutionContext context, ClassBuilder builder) => + context.AddSource($"{builder.FullyQualifiedName}.g.cs", builder.Build()); +} diff --git a/src/Resizetizer/src/Resizetizer.csproj b/src/Resizetizer/src/Resizetizer.csproj index dff9209b..90b8085a 100644 --- a/src/Resizetizer/src/Resizetizer.csproj +++ b/src/Resizetizer/src/Resizetizer.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -72,6 +72,13 @@ + + + false + Analyzer + + + @@ -119,4 +126,13 @@ Condition="Exists('$(NuGetPackageRoot)$(PackageId.ToLowerInvariant())') And '$(OS)' != 'Windows_NT'" /> + + + + + + diff --git a/src/Resizetizer/src/WindowIconGeneratorTask.cs b/src/Resizetizer/src/WindowIconGeneratorTask.cs deleted file mode 100644 index 257d3834..00000000 --- a/src/Resizetizer/src/WindowIconGeneratorTask.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.IO; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace Uno.Resizetizer; - -public class WindowIconGeneratorTask_V0 : Task -{ - private const string FileName = "Uno.Resizetizer.WindowIconExtensions.g.cs"; - - public ITaskItem[] UnoIcons { get; set; } - - [Required] - public string IntermediateOutputDirectory { get; set; } - - public string WindowTitle { get; set; } - - [Output] - public ITaskItem[] GeneratedClass { get; private set; } = Array.Empty(); - - public override bool Execute() - { - if (UnoIcons is null || UnoIcons.Length == 0) - { - return true; - } - - if(string.IsNullOrEmpty(IntermediateOutputDirectory)) - { - Log.LogError("The IntermediateOutputDirectory (typically the obj directory) is a required parameter but was null or empty."); - return false; - } - - var iconPath = UnoIcons[0].ItemSpec; - var iconName = Path.GetFileNameWithoutExtension(iconPath); - - var code = @$"//------------------------------------------------------------------------------ -// -// This code was auto-generated. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Uno.Resizetizer -{{ - /// - /// Extension methods for the class. - /// - public static class WindowExtensions - {{ - /// - /// This will set the Window Icon for the given using - /// the provided UnoIcon. - /// - public static void SetWindowIcon(this global::Microsoft.UI.Xaml.Window window) - {{ -#if WINDOWS && !HAS_UNO - var hWnd = - global::WinRT.Interop.WindowNative.GetWindowHandle(window); - - // Retrieve the WindowId that corresponds to hWnd. - global::Microsoft.UI.WindowId windowId = - global::Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd); - - // Lastly, retrieve the AppWindow for the current (XAML) WinUI 3 window. - global::Microsoft.UI.Windowing.AppWindow appWindow = - global::Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId); - appWindow.SetIcon(""{iconName}.ico""); - - // Set the Window Title Only if it has the Default WinUI Desktop value and we are running Unpackaged - if (!IsPackaged() && appWindow.Title == ""WinUI Desktop"") - {{ - appWindow.Title = ""{WindowTitle}""; - }} - - static bool IsPackaged() - {{ - try - {{ - if (global::Windows.ApplicationModel.Package.Current != null) - return true; - }} - catch - {{ - // no-op - }} - - return false; - }} -#endif - }} - }} -}}"; - - if(!Directory.Exists(IntermediateOutputDirectory)) - { - Directory.CreateDirectory(IntermediateOutputDirectory); - } - - var item = new TaskItem(Path.Combine(IntermediateOutputDirectory, FileName)); - File.WriteAllText(item.ItemSpec, code); - GeneratedClass = new [] { item }; - return true; - } -} diff --git a/src/Resizetizer/uno.resizetizer.sln b/src/Resizetizer/uno.resizetizer.sln index a80b9860..721110fc 100644 --- a/src/Resizetizer/uno.resizetizer.sln +++ b/src/Resizetizer/uno.resizetizer.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\.nuspec\Uno.Resizetizer.targets = ..\.nuspec\Uno.Resizetizer.targets EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resizetizer.Generators", "Resizetizer.Generators\Resizetizer.Generators.csproj", "{9CDB1CAA-293A-434C-A092-29D0EE03496D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DEBUG_RESIZETIZER|Any CPU = DEBUG_RESIZETIZER|Any CPU @@ -31,6 +33,12 @@ Global {7695AB69-4414-4539-8172-A78D8460F663}.Debug|Any CPU.Build.0 = Debug|Any CPU {7695AB69-4414-4539-8172-A78D8460F663}.Release|Any CPU.ActiveCfg = Release|Any CPU {7695AB69-4414-4539-8172-A78D8460F663}.Release|Any CPU.Build.0 = Release|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.DEBUG_RESIZETIZER|Any CPU.ActiveCfg = Debug|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.DEBUG_RESIZETIZER|Any CPU.Build.0 = Debug|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CDB1CAA-293A-434C-A092-29D0EE03496D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From bedfa9053c57b5049aff270c22765e8392686808 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 7 Aug 2024 08:39:17 -0600 Subject: [PATCH 02/10] chore: fixing Uno Icon property name --- .../Resizetizer.Generators/WindowTitleGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index 699f5b22..2badb78e 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using CodeGenHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -96,7 +96,7 @@ private static bool GetProperty(AnalyzerConfigOptions options, string key) => private static bool HasUnoIcon(AnalyzerConfigOptions options, out string unoIcon) { - unoIcon = GetPropertyValue(options, "UnoIcon"); + unoIcon = GetPropertyValue(options, "UnoResizetizerIcon"); return !string.IsNullOrEmpty(unoIcon) && !unoIcon.Contains(","); } From 4ac18808c96958063f6ac4e5567d8ddb3db6b202 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 7 Aug 2024 08:40:13 -0600 Subject: [PATCH 03/10] chore: update to use Incremental Generator --- .../WindowTitleGenerator.cs | 67 ++++++++++++------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index 2badb78e..b4468d8e 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -1,39 +1,60 @@ +using System; using System.IO; +using System.Text; using CodeGenHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; namespace Resizetizer.Generators; [Generator(LanguageNames.CSharp)] -internal sealed class WindowTitleGenerator : ISourceGenerator +internal sealed class WindowTitleGenerator : IIncrementalGenerator { - public void Execute(GeneratorExecutionContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - var options = context.AnalyzerConfigOptions.GlobalOptions; - if (!GetProperty(options, "IsUnoHead") || !HasUnoIcon(options, out var unoIcon)) - { - return; - } - - GenerateLegacyNamespaceCompat(context); + // Get the AnalyzerConfigOptionsProvider + var optionsProvider = context.AnalyzerConfigOptionsProvider; + var compilationProvider = context.CompilationProvider; - GenerateWindowTitleExtension(context, unoIcon); - } + // Combine optionsProvider and compilationProvider + var combinedProvider = optionsProvider.Combine(compilationProvider); - public void Initialize(GeneratorInitializationContext context) - { + // Define the source generator logic + var sourceCodeProvider = combinedProvider.Select((combined, cancellationToken) => + { + var options = combined.Left.GlobalOptions; + if (!GetProperty(options, "IsUnoHead") || !HasUnoIcon(options, out var unoIcon)) + { + return Array.Empty(); + } + + var compilation = combined.Right; + return + [ + GenerateLegacyNamespaceCompat(), + GenerateWindowTitleExtension(options, compilation.AssemblyName, unoIcon) + ]; + }); + + // Register the source generator logic to add the generated source code + context.RegisterSourceOutput(sourceCodeProvider, (context, classBuilders) => + { + foreach (var classBuilder in classBuilders) + { + AddSource(context, classBuilder); + } + }); } - private static void GenerateWindowTitleExtension(GeneratorExecutionContext context, string unoIcon) + private static ClassBuilder GenerateWindowTitleExtension(AnalyzerConfigOptions options, string assemblyName, string unoIcon) { - var options = context.AnalyzerConfigOptions.GlobalOptions; var rootNamespace = GetPropertyValue(options, "RootNamespace"); var iconName = Path.GetFileNameWithoutExtension(unoIcon); var windowTitle = GetPropertyValue(options, "ApplicationTitle"); if (string.IsNullOrEmpty(windowTitle)) { - windowTitle = context.Compilation.AssemblyName!; + windowTitle = assemblyName!; } var builder = CodeBuilder.Create(rootNamespace) @@ -69,6 +90,8 @@ private static void GenerateWindowTitleExtension(GeneratorExecutionContext conte w.AppendUnindentedLine("#endif"); }); + return builder; + //builder.AddMethod("IsPackaged") // .WithReturnType("bool") // .MakePrivateMethod() @@ -84,8 +107,6 @@ private static void GenerateWindowTitleExtension(GeneratorExecutionContext conte // w.AppendLine("return false;"); // } // }); - - AddSource(context, builder); } private static string GetPropertyValue(AnalyzerConfigOptions options, string key) => @@ -100,16 +121,14 @@ private static bool HasUnoIcon(AnalyzerConfigOptions options, out string unoIcon return !string.IsNullOrEmpty(unoIcon) && !unoIcon.Contains(","); } - private static void GenerateLegacyNamespaceCompat(GeneratorExecutionContext context) + private static ClassBuilder GenerateLegacyNamespaceCompat() { - var builder = CodeBuilder.Create("Uno.Resizetizer") + return CodeBuilder.Create("Uno.Resizetizer") .AddClass("__LegacyResizetizerSupport__") .WithSummary("This is added to ensure the Uno.Resizetizer namespace is present to avoid breaking any applications.") .MakeStaticClass(); - - AddSource(context, builder); } - private static void AddSource(GeneratorExecutionContext context, ClassBuilder builder) => - context.AddSource($"{builder.FullyQualifiedName}.g.cs", builder.Build()); + private static void AddSource(SourceProductionContext context, ClassBuilder builder) => + context.AddSource($"{builder.FullyQualifiedName}.g.cs", SourceText.From(builder.Build(), Encoding.UTF8)); } From 2b9dbfdf6d6b5556bfc5c219b531cdfa3445e4bc Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 7 Aug 2024 08:40:55 -0600 Subject: [PATCH 04/10] chore: rename generator assembly name --- .../Resizetizer.Generators/Resizetizer.Generators.csproj | 1 + src/Resizetizer/src/Resizetizer.csproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/Resizetizer.Generators.csproj b/src/Resizetizer/Resizetizer.Generators/Resizetizer.Generators.csproj index b5c8aae4..1d8f78da 100644 --- a/src/Resizetizer/Resizetizer.Generators/Resizetizer.Generators.csproj +++ b/src/Resizetizer/Resizetizer.Generators/Resizetizer.Generators.csproj @@ -3,6 +3,7 @@ netstandard2.0 false + Uno.Resizetizer true analyzers/dotnet/cs latest diff --git a/src/Resizetizer/src/Resizetizer.csproj b/src/Resizetizer/src/Resizetizer.csproj index 90b8085a..c522638b 100644 --- a/src/Resizetizer/src/Resizetizer.csproj +++ b/src/Resizetizer/src/Resizetizer.csproj @@ -128,9 +128,9 @@ - From 23fc14fef10e378d5324ae84122a5102ed9f364f Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 7 Aug 2024 10:01:23 -0600 Subject: [PATCH 05/10] chore: execute before design time targets --- src/.nuspec/Uno.Resizetizer.targets | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/.nuspec/Uno.Resizetizer.targets b/src/.nuspec/Uno.Resizetizer.targets index d5cd7da7..c209ce65 100644 --- a/src/.nuspec/Uno.Resizetizer.targets +++ b/src/.nuspec/Uno.Resizetizer.targets @@ -586,10 +586,9 @@ + BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun;GenerateMSBuildEditorConfigFileCore;ResolveFrameworkReferencesDesignTime;ResolveProjectReferencesDesignTime2;CollectAnalyzersDesignTime;GetAndroidDependencies"> - From ebe49aa56553dbd2be57bbd2e2a47ee385edbf60 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 7 Aug 2024 11:23:49 -0600 Subject: [PATCH 06/10] chore: adding debug output --- .../WindowTitleGenerator.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index b4468d8e..274d17e0 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -11,6 +11,9 @@ namespace Resizetizer.Generators; [Generator(LanguageNames.CSharp)] internal sealed class WindowTitleGenerator : IIncrementalGenerator { + private const string UnoResizetizerIcon = nameof(UnoResizetizerIcon); + private const string IsUnoHead = nameof(IsUnoHead); + public void Initialize(IncrementalGeneratorInitializationContext context) { // Get the AnalyzerConfigOptionsProvider @@ -24,13 +27,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var sourceCodeProvider = combinedProvider.Select((combined, cancellationToken) => { var options = combined.Left.GlobalOptions; - if (!GetProperty(options, "IsUnoHead") || !HasUnoIcon(options, out var unoIcon)) + if (!GetProperty(options, IsUnoHead) || !HasUnoIcon(options, out var unoIcon)) { - return Array.Empty(); + + return (ClassBuilder[])[ + CodeBuilder.Create("__Empty__") + .AddClass("GeneratorResult") + .WithSummary($"IsUnoHead: {GetPropertyValue(options, IsUnoHead)}, UnoResizetizerIcon: {GetPropertyValue(options, UnoResizetizerIcon)}") + ]; } var compilation = combined.Right; - return + return [ GenerateLegacyNamespaceCompat(), GenerateWindowTitleExtension(options, compilation.AssemblyName, unoIcon) @@ -117,7 +125,7 @@ private static bool GetProperty(AnalyzerConfigOptions options, string key) => private static bool HasUnoIcon(AnalyzerConfigOptions options, out string unoIcon) { - unoIcon = GetPropertyValue(options, "UnoResizetizerIcon"); + unoIcon = GetPropertyValue(options, UnoResizetizerIcon); return !string.IsNullOrEmpty(unoIcon) && !unoIcon.Contains(","); } From e17e19f6525573cd80fd5a39888bdb2791d04746 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Thu, 8 Aug 2024 06:41:48 -0600 Subject: [PATCH 07/10] chore: evaluate unoimage.inputs --- src/.nuspec/Uno.Resizetizer.targets | 3 + .../WindowTitleGenerator.cs | 88 +++++++++++++------ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/.nuspec/Uno.Resizetizer.targets b/src/.nuspec/Uno.Resizetizer.targets index c209ce65..bbd23fb5 100644 --- a/src/.nuspec/Uno.Resizetizer.targets +++ b/src/.nuspec/Uno.Resizetizer.targets @@ -227,6 +227,8 @@ _ComputeAndroidResourcePaths; $(UnoResizetizeCollectItemsAfterTargets); UnoAssetsGeneration; + GenerateMSBuildEditorConfigFileShouldRun; + GenerateMSBuildEditorConfigFileCore; @@ -414,6 +416,7 @@ WriteOnlyWhenDifferent="true"/> + diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index 274d17e0..40403c99 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using System.Text; using CodeGenHelpers; using Microsoft.CodeAnalysis; @@ -19,52 +20,84 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Get the AnalyzerConfigOptionsProvider var optionsProvider = context.AnalyzerConfigOptionsProvider; var compilationProvider = context.CompilationProvider; + var additionalTextsProvider = context.AdditionalTextsProvider; // Combine optionsProvider and compilationProvider - var combinedProvider = optionsProvider.Combine(compilationProvider); + var combinedProvider = additionalTextsProvider + .Combine(compilationProvider) + .Combine(optionsProvider); + // Define the source generator logic var sourceCodeProvider = combinedProvider.Select((combined, cancellationToken) => { - var options = combined.Left.GlobalOptions; - if (!GetProperty(options, IsUnoHead) || !HasUnoIcon(options, out var unoIcon)) - { + var ((additionalText, compilation), options) = combined; + var additionalFile = additionalText; - return (ClassBuilder[])[ - CodeBuilder.Create("__Empty__") - .AddClass("GeneratorResult") - .WithSummary($"IsUnoHead: {GetPropertyValue(options, IsUnoHead)}, UnoResizetizerIcon: {GetPropertyValue(options, UnoResizetizerIcon)}") - ]; + if (!GetProperty(options.GlobalOptions, IsUnoHead)) + { + return null; + } + else if (Path.GetFileName(additionalFile.Path) == "unoimages.inputs") + { + var text = additionalFile.GetText(cancellationToken); + var textContent = text?.ToString(); + var unoIcon = ParseFile(textContent); + + var rootNamespace = GetPropertyValue(options.GlobalOptions, "RootNamespace"); + var iconName = Path.GetFileNameWithoutExtension(unoIcon); + var windowTitle = GetPropertyValue(options.GlobalOptions, "ApplicationTitle"); + if (string.IsNullOrEmpty(windowTitle)) + { + windowTitle = compilation.AssemblyName!; + } + + return new ExtensionGenerationContext(rootNamespace, iconName, windowTitle); } - var compilation = combined.Right; - return - [ - GenerateLegacyNamespaceCompat(), - GenerateWindowTitleExtension(options, compilation.AssemblyName, unoIcon) - ]; - }); + return null; + }).Where(result => result != null); // Register the source generator logic to add the generated source code - context.RegisterSourceOutput(sourceCodeProvider, (context, classBuilders) => + context.RegisterSourceOutput(sourceCodeProvider, (sourceContext, extensionContext) => { - foreach (var classBuilder in classBuilders) + if (!string.IsNullOrEmpty(extensionContext.WindowTitle)) { - AddSource(context, classBuilder); + GenerateLegacyNamespaceCompat(); + GenerateWindowTitleExtension(extensionContext.RootNamespace, extensionContext.UnoIcon, extensionContext.WindowTitle); } }); } - private static ClassBuilder GenerateWindowTitleExtension(AnalyzerConfigOptions options, string assemblyName, string unoIcon) + internal record ExtensionGenerationContext(string RootNamespace, string UnoIcon, string WindowTitle); + + private static string ParseFile(string content) { - var rootNamespace = GetPropertyValue(options, "RootNamespace"); - var iconName = Path.GetFileNameWithoutExtension(unoIcon); - var windowTitle = GetPropertyValue(options, "ApplicationTitle"); - if (string.IsNullOrEmpty(windowTitle)) + // Split the content into lines + var lines = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var line in lines) { - windowTitle = assemblyName!; + // Split the line into key-value pairs + var properties = line.Split(';').Select(property => property.Split('=')).ToDictionary(parts => parts[0], parts => parts.Length > 1 ? parts[1] : null); + + // Check if IsAppIcon is true + if (properties.TryGetValue("IsAppIcon", out var isAppIcon) && bool.TryParse(isAppIcon, out var isAppIconValue) && isAppIconValue) + { + // Return the file path + if (properties.TryGetValue("File", out var filePath)) + { + return filePath; + } + } } + // Return null if no app icon is found + return null; + } + + private static ClassBuilder GenerateWindowTitleExtension(string rootNamespace, string iconName, string windowTitle) + { var builder = CodeBuilder.Create(rootNamespace) .AddClass("WindowExtensions") .MakeStaticClass() @@ -98,8 +131,7 @@ private static ClassBuilder GenerateWindowTitleExtension(AnalyzerConfigOptions o w.AppendUnindentedLine("#endif"); }); - return builder; - + // NOTE: This method has been removed as it seems WinUI isn't setting the title when Packaged. Keeping in case we need this in the future. //builder.AddMethod("IsPackaged") // .WithReturnType("bool") // .MakePrivateMethod() @@ -115,6 +147,8 @@ private static ClassBuilder GenerateWindowTitleExtension(AnalyzerConfigOptions o // w.AppendLine("return false;"); // } // }); + + return builder; } private static string GetPropertyValue(AnalyzerConfigOptions options, string key) => From de91be4c621bbf8cf12152854c3a5fc25c1e36ee Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 14 Aug 2024 07:17:12 -0600 Subject: [PATCH 08/10] chore: file cleanup --- src/Resizetizer/src/Resizetizer.csproj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Resizetizer/src/Resizetizer.csproj b/src/Resizetizer/src/Resizetizer.csproj index c522638b..de4c8946 100644 --- a/src/Resizetizer/src/Resizetizer.csproj +++ b/src/Resizetizer/src/Resizetizer.csproj @@ -21,7 +21,7 @@ - Uno.Resizetizer_v0 + Uno.Resizetizer_v0 $(GITVERSION_SHA) Uno.Resizetizer Uno Platform package support for images. @@ -44,7 +44,7 @@ - + @@ -75,7 +75,6 @@ false - Analyzer From f53c8e92235c3ffe2987b6d5e95e2d996559a443 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 14 Aug 2024 07:20:53 -0600 Subject: [PATCH 09/10] chore: fixing inputs file evaluation --- .../WindowTitleGenerator.cs | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index 40403c99..d5cceae3 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading; using CodeGenHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -27,36 +28,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Combine(compilationProvider) .Combine(optionsProvider); - // Define the source generator logic - var sourceCodeProvider = combinedProvider.Select((combined, cancellationToken) => - { - var ((additionalText, compilation), options) = combined; - var additionalFile = additionalText; - - if (!GetProperty(options.GlobalOptions, IsUnoHead)) - { - return null; - } - else if (Path.GetFileName(additionalFile.Path) == "unoimages.inputs") - { - var text = additionalFile.GetText(cancellationToken); - var textContent = text?.ToString(); - var unoIcon = ParseFile(textContent); - - var rootNamespace = GetPropertyValue(options.GlobalOptions, "RootNamespace"); - var iconName = Path.GetFileNameWithoutExtension(unoIcon); - var windowTitle = GetPropertyValue(options.GlobalOptions, "ApplicationTitle"); - if (string.IsNullOrEmpty(windowTitle)) - { - windowTitle = compilation.AssemblyName!; - } - - return new ExtensionGenerationContext(rootNamespace, iconName, windowTitle); - } - - return null; - }).Where(result => result != null); + var sourceCodeProvider = combinedProvider.Select(GenerateExtensionGenerationContext).Where(result => result != null); // Register the source generator logic to add the generated source code context.RegisterSourceOutput(sourceCodeProvider, (sourceContext, extensionContext) => @@ -69,6 +42,35 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }); } + static ExtensionGenerationContext GenerateExtensionGenerationContext(((AdditionalText, Compilation), AnalyzerConfigOptionsProvider) combined, CancellationToken cancellationToken) + { + var ((additionalText, compilation), options) = combined; + var additionalFile = additionalText; + + if (!GetProperty(options.GlobalOptions, IsUnoHead)) + { + return null; + } + else if (Path.GetFileName(additionalFile.Path).Equals("UnoImage.inputs", StringComparison.InvariantCultureIgnoreCase)) + { + var text = additionalFile.GetText(cancellationToken); + var textContent = text?.ToString(); + var unoIcon = ParseFile(textContent); + + var rootNamespace = GetPropertyValue(options.GlobalOptions, "RootNamespace"); + var iconName = Path.GetFileNameWithoutExtension(unoIcon); + var windowTitle = GetPropertyValue(options.GlobalOptions, "ApplicationTitle"); + if (string.IsNullOrEmpty(windowTitle)) + { + windowTitle = compilation.AssemblyName!; + } + + return new ExtensionGenerationContext(rootNamespace, iconName, windowTitle); + } + + return null; + } + internal record ExtensionGenerationContext(string RootNamespace, string UnoIcon, string WindowTitle); private static string ParseFile(string content) From ceb76c3c4b4ec9df2493dedfe545c51f5e572e92 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 14 Aug 2024 12:59:33 -0600 Subject: [PATCH 10/10] chore: optimize providers --- .../WindowTitleGenerator.cs | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs index d5cceae3..10d1ff95 100644 --- a/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs +++ b/src/Resizetizer/Resizetizer.Generators/WindowTitleGenerator.cs @@ -2,7 +2,6 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading; using CodeGenHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -20,58 +19,62 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { // Get the AnalyzerConfigOptionsProvider var optionsProvider = context.AnalyzerConfigOptionsProvider; - var compilationProvider = context.CompilationProvider; + var assemblyNameProvider = context.CompilationProvider.Select((compilation, _) => compilation.Assembly.Name); var additionalTextsProvider = context.AdditionalTextsProvider; + var extensionPropertiesProvider = optionsProvider.Combine(assemblyNameProvider).Select((x, cancellationToken) => + { + var (options, assemblyName) = x; + if (!GetProperty(options.GlobalOptions, IsUnoHead)) + { + return null; + } + + var rootNamespace = GetPropertyValue(options.GlobalOptions, "RootNamespace"); + var windowTitle = GetPropertyValue(options.GlobalOptions, "ApplicationTitle"); + if (string.IsNullOrEmpty(windowTitle)) + { + windowTitle = assemblyName; + } + + return string.IsNullOrEmpty(rootNamespace) || string.IsNullOrEmpty(windowTitle) ? null : new ExtensionPropertiesContext(rootNamespace, windowTitle); + }); + // Combine optionsProvider and compilationProvider - var combinedProvider = additionalTextsProvider - .Combine(compilationProvider) - .Combine(optionsProvider); + var iconNameProvider = additionalTextsProvider + .Where(x => Path.GetFileName(x.Path).Equals("UnoImage.inputs", StringComparison.InvariantCultureIgnoreCase)) + .Select((additionalText, cancellationToken) => + { + var sourceText = additionalText.GetText(cancellationToken); + return ParseFile(sourceText.ToString()); + }) + .Where(x => !string.IsNullOrEmpty(x)) + .Select((x, _) => Path.GetFileNameWithoutExtension(x)); // Define the source generator logic - var sourceCodeProvider = combinedProvider.Select(GenerateExtensionGenerationContext).Where(result => result != null); + var sourceCodeProvider = iconNameProvider.Combine(extensionPropertiesProvider).Select((x, _) => + { + var (iconName, coreContext) = x; + if (string.IsNullOrEmpty(iconName) || string.IsNullOrEmpty(coreContext?.RootNamespace) || string.IsNullOrEmpty(coreContext?.WindowTitle)) + return null; + + return new ExtensionGenerationContext(coreContext.RootNamespace, iconName, coreContext.WindowTitle); + }).Where(result => result != null); // Register the source generator logic to add the generated source code context.RegisterSourceOutput(sourceCodeProvider, (sourceContext, extensionContext) => { if (!string.IsNullOrEmpty(extensionContext.WindowTitle)) { - GenerateLegacyNamespaceCompat(); - GenerateWindowTitleExtension(extensionContext.RootNamespace, extensionContext.UnoIcon, extensionContext.WindowTitle); + AddSource(sourceContext, GenerateLegacyNamespaceCompat()); + AddSource(sourceContext, GenerateWindowTitleExtension(extensionContext.RootNamespace, extensionContext.IconName, extensionContext.WindowTitle)); } }); } - static ExtensionGenerationContext GenerateExtensionGenerationContext(((AdditionalText, Compilation), AnalyzerConfigOptionsProvider) combined, CancellationToken cancellationToken) - { - var ((additionalText, compilation), options) = combined; - var additionalFile = additionalText; - - if (!GetProperty(options.GlobalOptions, IsUnoHead)) - { - return null; - } - else if (Path.GetFileName(additionalFile.Path).Equals("UnoImage.inputs", StringComparison.InvariantCultureIgnoreCase)) - { - var text = additionalFile.GetText(cancellationToken); - var textContent = text?.ToString(); - var unoIcon = ParseFile(textContent); - - var rootNamespace = GetPropertyValue(options.GlobalOptions, "RootNamespace"); - var iconName = Path.GetFileNameWithoutExtension(unoIcon); - var windowTitle = GetPropertyValue(options.GlobalOptions, "ApplicationTitle"); - if (string.IsNullOrEmpty(windowTitle)) - { - windowTitle = compilation.AssemblyName!; - } - - return new ExtensionGenerationContext(rootNamespace, iconName, windowTitle); - } - - return null; - } + internal record ExtensionPropertiesContext(string RootNamespace, string WindowTitle); - internal record ExtensionGenerationContext(string RootNamespace, string UnoIcon, string WindowTitle); + internal record ExtensionGenerationContext(string RootNamespace, string IconName, string WindowTitle); private static string ParseFile(string content) {