From 399bbca153b1e4fdea2bdf6eff9234dd8bc15535 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 14 Mar 2021 16:53:04 +0100 Subject: [PATCH] Add program to merge XAML style files. --- Avalonia.sln | 33 ++++- samples/Sandbox/MainWindow.axaml.cs | 8 +- samples/Sandbox/Program.cs | 6 +- src/Avalonia.Styling/Avalonia.Styling.csproj | 3 + src/Avalonia.Styling/Styling/Styles.cs | 8 + src/tools/XamlStyleMerge/Program.cs | 138 ++++++++++++++++++ .../Properties/launchSettings.json | 8 + .../XamlStyleMerge/XamlStyleMerge.csproj | 9 ++ 8 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 src/tools/XamlStyleMerge/Program.cs create mode 100644 src/tools/XamlStyleMerge/Properties/launchSettings.json create mode 100644 src/tools/XamlStyleMerge/XamlStyleMerge.csproj diff --git a/Avalonia.sln b/Avalonia.sln index 75f1dd8407..e1c0c23533 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -226,11 +226,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.Events" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "samples\Sandbox\Sandbox.csproj", "{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\tools\MicroComGenerator\MicroComGenerator.csproj", "{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicroComGenerator", "src\tools\MicroComGenerator\MicroComGenerator.csproj", "{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlStyleMerge", "src\tools\XamlStyleMerge\XamlStyleMerge.csproj", "{740C248D-C44F-44D5-90E0-89B7536CDDC7}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -2142,6 +2144,30 @@ Global {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.Build.0 = Release|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|iPhone.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|iPhone.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|Any CPU.Build.0 = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|iPhone.ActiveCfg = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|iPhone.Build.0 = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {740C248D-C44F-44D5-90E0-89B7536CDDC7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2203,6 +2229,7 @@ Global {11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098} {AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {740C248D-C44F-44D5-90E0-89B7536CDDC7} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/Sandbox/MainWindow.axaml.cs b/samples/Sandbox/MainWindow.axaml.cs index 3d54036d29..6dd8c03567 100644 --- a/samples/Sandbox/MainWindow.axaml.cs +++ b/samples/Sandbox/MainWindow.axaml.cs @@ -1,7 +1,6 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using Avalonia.Win32.WinRT.Composition; namespace Sandbox { @@ -11,6 +10,13 @@ namespace Sandbox { this.InitializeComponent(); this.AttachDevTools(); + this.Activated += MainWindow_Activated; + } + + private void MainWindow_Activated(object sender, System.EventArgs e) + { + Program.sw.Stop(); + Title = Program.sw.Elapsed.ToString(); } private void InitializeComponent() diff --git a/samples/Sandbox/Program.cs b/samples/Sandbox/Program.cs index 1e74105196..dc1ed8d0e0 100644 --- a/samples/Sandbox/Program.cs +++ b/samples/Sandbox/Program.cs @@ -1,4 +1,5 @@ -using Avalonia; +using System.Diagnostics; +using Avalonia; namespace Sandbox { @@ -6,10 +7,13 @@ namespace Sandbox { static void Main(string[] args) { + sw.Start(); AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .StartWithClassicDesktopLifetime(args); } + + public static Stopwatch sw = new Stopwatch(); } } diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj index d9f0cef3da..8ef7b97f5b 100644 --- a/src/Avalonia.Styling/Avalonia.Styling.csproj +++ b/src/Avalonia.Styling/Avalonia.Styling.csproj @@ -4,6 +4,9 @@ Avalonia.Styling Avalonia + + + diff --git a/src/Avalonia.Styling/Styling/Styles.cs b/src/Avalonia.Styling/Styling/Styles.cs index c752bdfeb8..643c2abd9d 100644 --- a/src/Avalonia.Styling/Styling/Styles.cs +++ b/src/Avalonia.Styling/Styling/Styles.cs @@ -286,7 +286,15 @@ namespace Avalonia.Styling if (Owner is object && style is IResourceProvider resourceProvider) { + var profile = Owner.GetType().Name == "App"; + + if (profile) + JetBrains.Profiler.Api.MeasureProfiler.StartCollectingData(); + resourceProvider.AddOwner(Owner); + + if (profile) + JetBrains.Profiler.Api.MeasureProfiler.SaveData(); } _cache = null; diff --git a/src/tools/XamlStyleMerge/Program.cs b/src/tools/XamlStyleMerge/Program.cs new file mode 100644 index 0000000000..a53a0bde20 --- /dev/null +++ b/src/tools/XamlStyleMerge/Program.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace XamlStyleMerge +{ + class Program + { + private static readonly XNamespace s_ns = "https://github.com/avaloniaui"; + private static readonly XNamespace s_xns = "http://schemas.microsoft.com/winfx/2006/xaml"; + private static readonly List s_namespaces = new List(); + private static readonly OrderedDictionary s_resources = new OrderedDictionary(); + private static readonly List s_styles = new List(); + private static string s_basePath = null!; + + static void Main(string[] args) + { + if (args.Length == 0) + Console.WriteLine("Usage: XamlStyleMerge [output]"); + + if (!UriParser.IsKnownScheme("avares")) + UriParser.Register(new GenericUriParser( + GenericUriParserOptions.GenericAuthority | + GenericUriParserOptions.NoUserInfo | + GenericUriParserOptions.NoPort | + GenericUriParserOptions.NoQuery | + GenericUriParserOptions.NoFragment), "avares", -1); + + s_basePath = Path.GetDirectoryName(args[0])!; + + var f = File.ReadAllText(args[0]); + var d = XDocument.Parse(f); + + if (d.Root.Name != s_ns + "Styles") + { + throw new InvalidOperationException("File is not an Avalonia Styles document."); + } + + ProcessStyles(d.Root); + + foreach (var ns in s_namespaces) + { + if (d.Root.Attribute(ns.Name) is null) + d.Root.Add(ns); + } + + d.Root.RemoveNodes(); + d.Root.Add(new XElement(s_ns + "Styles.Resources", s_resources.Values)); + d.Root.Add(s_styles); + + var outFile = args.Length > 1 ? args[1] : "out.xaml"; + d.Save(outFile); + } + + private static void Process(string fileName) + { + var f = File.ReadAllText(fileName); + var d = XDocument.Parse(f); + + if (d.Root.Name == s_ns + "Style") + ProcessStyle(d.Root); + else + ProcessStyles(d.Root); + } + + private static void ProcessStyle(XElement element) + { + ProcessAttributes(element); + ProcessResources(element); + RemoveDesignTimeElements(element); + + var selector = element.Attribute("Selector"); + + if (selector is object) + { + + s_styles.Add(element); + } + } + + private static void ProcessStyles(XElement element) + { + ProcessAttributes(element); + ProcessResources(element); + RemoveDesignTimeElements(element); + + foreach (var child in element.Elements(s_ns + "StyleInclude")) + { + var source = new Uri(child.Attribute("Source").Value); + var fileName = Path.Combine(s_basePath, source.LocalPath.TrimStart('/')); + Process(fileName); + } + + foreach (var child in element.Elements(s_ns + "Style")) + { + ProcessStyle(child); + } + } + + private static void ProcessAttributes(XElement element) + { + foreach (var attr in element.Attributes().ToList()) + { + if (attr.IsNamespaceDeclaration) + { + s_namespaces.Add(attr); + attr.Remove(); + } + } + } + + private static void ProcessResources(XElement element) + { + var resources = element.Element(s_ns + "Style.Resources") ?? + element.Element(s_ns + "Styles.Resources"); + + if (resources is object) + { + foreach (var r in resources.Elements()) + { + var key = r.Attribute(s_xns + "Key").Value; + s_resources[key] = r; + } + + resources.ReplaceWith(null); + } + } + + private static void RemoveDesignTimeElements(XElement element) + { + foreach (var e in element.Elements(s_ns + "Design.PreviewWith")) + e.Remove(); + } + } +} diff --git a/src/tools/XamlStyleMerge/Properties/launchSettings.json b/src/tools/XamlStyleMerge/Properties/launchSettings.json new file mode 100644 index 0000000000..e5dddb9199 --- /dev/null +++ b/src/tools/XamlStyleMerge/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "XamlStyleMerge": { + "commandName": "Project", + "commandLineArgs": "\"D:\\projects\\AvaloniaUI\\Avalonia\\src\\Avalonia.Themes.Fluent\\FluentDark.xaml\"" + } + } +} \ No newline at end of file diff --git a/src/tools/XamlStyleMerge/XamlStyleMerge.csproj b/src/tools/XamlStyleMerge/XamlStyleMerge.csproj new file mode 100644 index 0000000000..de1adbd7d3 --- /dev/null +++ b/src/tools/XamlStyleMerge/XamlStyleMerge.csproj @@ -0,0 +1,9 @@ + + + + Exe + netcoreapp3.1 + enable + + +