using System.Collections.Generic; using Avalonia.Generators.Common.Domain; using XamlX.TypeSystem; namespace Avalonia.Generators.NameGenerator; internal class InitializeComponentCodeGenerator : ICodeGenerator { private string _generatorName = typeof(InitializeComponentCodeGenerator).FullName; private string _generatorVersion = typeof(InitializeComponentCodeGenerator).Assembly.GetName().Version.ToString(); private readonly bool _diagnosticsAreConnected; private const string AttachDevToolsCodeBlock = @" #if DEBUG if (attachDevTools) { this.AttachDevTools(); } #endif "; private const string AttachDevToolsParameterDocumentation = @" /// Should the dev tools be attached. "; public InitializeComponentCodeGenerator(IXamlTypeSystem types, bool avaloniaNameGeneratorAttachDevTools) { _diagnosticsAreConnected = avaloniaNameGeneratorAttachDevTools && types.FindAssembly("Avalonia.Diagnostics") != null; } public string GenerateCode(ResolvedView view, IEnumerable names) { var properties = new List(); var initializations = new List(); const string thisFindNameScopeVariable = " var __thisNameScope__ = this.FindNameScope();"; bool hasNames = false; foreach (var resolvedName in names) { if (!hasNames) { initializations.Add(thisFindNameScopeVariable); } var (typeName, name, fieldModifier) = resolvedName; var propertySource = $""" [global::System.CodeDom.Compiler.GeneratedCode("{_generatorName}", "{_generatorVersion}")] {fieldModifier} {typeName} {name}; """; properties.Add(propertySource); initializations.Add($" {name} = __thisNameScope__?.Find<{typeName}>(\"{name}\");"); hasNames = true; } var attachDevTools = _diagnosticsAreConnected && IsWindow(view.XamlType); var baseClassPart = view.HasClass ? "" : $": global::{view.XamlType.FullName}"; return $@"// using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace {view.Namespace} {{ partial class {view.ClassName} {baseClassPart} {{ {string.Join("\n", properties)} /// /// Wires up the controls and optionally loads XAML markup and attaches dev tools (if Avalonia.Diagnostics package is referenced). /// /// Should the XAML be loaded into the component. {(attachDevTools ? AttachDevToolsParameterDocumentation : string.Empty)} [global::System.CodeDom.Compiler.GeneratedCode(""{_generatorName}"", ""{_generatorVersion}"")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public void InitializeComponent(bool loadXaml = true{(attachDevTools ? ", bool attachDevTools = true" : string.Empty)}) {{ if (loadXaml) {{ AvaloniaXamlLoader.Load(this); }} {(attachDevTools ? AttachDevToolsCodeBlock : string.Empty)} {string.Join("\n", initializations)} }} }} }} "; } private static bool IsWindow(IXamlType xamlType) { var type = xamlType; bool isWindow; do { isWindow = type.FullName == "Avalonia.Controls.Window"; type = type.BaseType; } while (!isWindow && type != null); return isWindow; } }