From 4733685b6463e331cfdc060f210880f8d70638e4 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 22:46:17 +0100 Subject: [PATCH 01/22] Add SelfContained project. --- SelfContained/Program.cs | 87 +++++++++++++++++++ .../FolderProfile_net8.0_linux-x64.pubxml | 16 ++++ .../FolderProfile_net8.0_osx-x64.pubxml | 16 ++++ .../FolderProfile_net8.0_win-x64.pubxml | 17 ++++ SelfContained/SelfContained.csproj | 20 +++++ 5 files changed, 156 insertions(+) create mode 100644 SelfContained/Program.cs create mode 100644 SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64.pubxml create mode 100644 SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64.pubxml create mode 100644 SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64.pubxml create mode 100644 SelfContained/SelfContained.csproj diff --git a/SelfContained/Program.cs b/SelfContained/Program.cs new file mode 100644 index 0000000000..6c4aac7789 --- /dev/null +++ b/SelfContained/Program.cs @@ -0,0 +1,87 @@ +// This is a simple example application for a self-contained single file. + +using System.Diagnostics.CodeAnalysis; +using Terminal.Gui; + +namespace SelfContained; + +public static class Program +{ + [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Run(Func, ConsoleDriver)")] + private static void Main (string [] args) + { + Application.Run ().Dispose (); + + // Before the application exits, reset Terminal.Gui for clean shutdown + Application.Shutdown (); + + Console.WriteLine ($@"Username: {ExampleWindow.UserName}"); + } +} + +// Defines a top-level window with border and title +public class ExampleWindow : Window +{ + public static string? UserName; + + public ExampleWindow () + { + Title = $"Example App ({Application.QuitKey} to quit)"; + + // Create input components and labels + var usernameLabel = new Label { Text = "Username:" }; + + var usernameText = new TextField + { + // Position text field adjacent to the label + X = Pos.Right (usernameLabel) + 1, + + // Fill remaining horizontal space + Width = Dim.Fill () + }; + + var passwordLabel = new Label + { + Text = "Password:", X = Pos.Left (usernameLabel), Y = Pos.Bottom (usernameLabel) + 1 + }; + + var passwordText = new TextField + { + Secret = true, + + // align with the text box above + X = Pos.Left (usernameText), + Y = Pos.Top (passwordLabel), + Width = Dim.Fill () + }; + + // Create login button + var btnLogin = new Button + { + Text = "Login", + Y = Pos.Bottom (passwordLabel) + 1, + + // center the login button horizontally + X = Pos.Center (), + IsDefault = true + }; + + // When login button is clicked display a message popup + btnLogin.Accept += (s, e) => + { + if (usernameText.Text == "admin" && passwordText.Text == "password") + { + MessageBox.Query ("Logging In", "Login Successful", "Ok"); + UserName = usernameText.Text; + Application.RequestStop (); + } + else + { + MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok"); + } + }; + + // Add the views to the Window + Add (usernameLabel, usernameText, passwordLabel, passwordText, btnLogin); + } +} diff --git a/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64.pubxml b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64.pubxml new file mode 100644 index 0000000000..e6a8e89804 --- /dev/null +++ b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64.pubxml @@ -0,0 +1,16 @@ + + + + + Release + Any CPU + bin\Release\net8.0\publish\linux-x64\ + FileSystem + <_TargetId>Folder + net8.0 + linux-x64 + true + + \ No newline at end of file diff --git a/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64.pubxml b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64.pubxml new file mode 100644 index 0000000000..669139a88d --- /dev/null +++ b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64.pubxml @@ -0,0 +1,16 @@ + + + + + Release + Any CPU + bin\Release\net8.0\publish\osx-x64\ + FileSystem + <_TargetId>Folder + net8.0 + osx-x64 + true + + \ No newline at end of file diff --git a/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64.pubxml b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64.pubxml new file mode 100644 index 0000000000..4fadc2fd2a --- /dev/null +++ b/SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64.pubxml @@ -0,0 +1,17 @@ + + + + + Release + Any CPU + bin\Release\net8.0\publish\win-x64\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + false + + \ No newline at end of file diff --git a/SelfContained/SelfContained.csproj b/SelfContained/SelfContained.csproj new file mode 100644 index 0000000000..eb3bcb4f41 --- /dev/null +++ b/SelfContained/SelfContained.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0 + enable + enable + true + Link + true + true + embedded + + + + + + + + From 8523657bd998f2010b639acb4d5c1b25f7491766 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 22:49:39 +0100 Subject: [PATCH 02/22] Fix WriteConsole having a wrong parameter type. --- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 3c9ba9261d..89c82dd58a 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -116,7 +116,7 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord var s = _stringBuilder.ToString (); - result = WriteConsole (_screenBuffer, s, (uint)s.Length, out uint _, null); + result = WriteConsole (_screenBuffer, s, (uint)s.Length, out uint _, nint.Zero); } if (!result) @@ -134,7 +134,7 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord public bool WriteANSI (string ansi) { - return WriteConsole (_screenBuffer, ansi, (uint)ansi.Length, out uint _, null); + return WriteConsole (_screenBuffer, ansi, (uint)ansi.Length, out uint _, nint.Zero); } public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window) @@ -804,7 +804,7 @@ private static extern bool WriteConsole ( string lpbufer, uint NumberOfCharsToWriten, out uint lpNumberOfCharsWritten, - object lpReserved + nint lpReserved ); [DllImport ("kernel32.dll")] From 5ca07e145693520151bcd9e1679e084d5194151c Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 23:05:13 +0100 Subject: [PATCH 03/22] Add SourceGenerationContext and fix Serialize/Deserialize. --- Terminal.Gui/Configuration/AttributeJsonConverter.cs | 6 +++--- .../Configuration/ColorSchemeJsonConverter.cs | 2 +- Terminal.Gui/Configuration/ConfigurationManager.cs | 11 +++++++---- Terminal.Gui/Configuration/DictionaryJsonConverter.cs | 6 +++--- Terminal.Gui/Configuration/ScopeJsonConverter.cs | 10 ++++++---- Terminal.Gui/Configuration/SettingsScope.cs | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Terminal.Gui/Configuration/AttributeJsonConverter.cs b/Terminal.Gui/Configuration/AttributeJsonConverter.cs index d1e922a64c..e14748fd91 100644 --- a/Terminal.Gui/Configuration/AttributeJsonConverter.cs +++ b/Terminal.Gui/Configuration/AttributeJsonConverter.cs @@ -3,7 +3,7 @@ namespace Terminal.Gui; -/// Json converter fro the class. +/// Json converter from the class. internal class AttributeJsonConverter : JsonConverter { private static AttributeJsonConverter _instance; @@ -57,11 +57,11 @@ public override Attribute Read (ref Utf8JsonReader reader, Type typeToConvert, J switch (propertyName?.ToLower ()) { case "foreground": - foreground = JsonSerializer.Deserialize (color, options); + foreground = JsonSerializer.Deserialize (color, _serializerContext.Color); break; case "background": - background = JsonSerializer.Deserialize (color, options); + background = JsonSerializer.Deserialize (color, _serializerContext.Color); break; diff --git a/Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs b/Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs index 86f4a5f29a..ae0742b5f4 100644 --- a/Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs +++ b/Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs @@ -59,7 +59,7 @@ public override ColorScheme Read (ref Utf8JsonReader reader, Type typeToConvert, string propertyName = reader.GetString (); reader.Read (); - var attribute = JsonSerializer.Deserialize (ref reader, options); + var attribute = JsonSerializer.Deserialize (ref reader, _serializerContext.Attribute); switch (propertyName.ToLower ()) { diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index 1c9f54089e..6bed7a20ae 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -106,9 +106,12 @@ public enum ConfigLocations }, // Enables Key to be "Ctrl+Q" vs "Ctrl\u002BQ" - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = SourceGenerationContext.Default }; + internal static readonly SourceGenerationContext _serializerContext = new (_serializerOptions); + [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "")] internal static StringBuilder _jsonErrors = new (); @@ -222,7 +225,7 @@ public static string GetEmptyJson () var emptyScope = new SettingsScope (); emptyScope.Clear (); - return JsonSerializer.Serialize (emptyScope, _serializerOptions); + return JsonSerializer.Serialize (emptyScope, typeof (SettingsScope), _serializerContext); } /// @@ -589,12 +592,12 @@ internal static string ToJson () { //Debug.WriteLine ("ConfigurationManager.ToJson()"); - return JsonSerializer.Serialize (Settings!, _serializerOptions); + return JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); } internal static Stream ToStream () { - string json = JsonSerializer.Serialize (Settings!, _serializerOptions); + string json = JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); // turn it into a stream var stream = new MemoryStream (); diff --git a/Terminal.Gui/Configuration/DictionaryJsonConverter.cs b/Terminal.Gui/Configuration/DictionaryJsonConverter.cs index 29963c56b7..bed7f874b4 100644 --- a/Terminal.Gui/Configuration/DictionaryJsonConverter.cs +++ b/Terminal.Gui/Configuration/DictionaryJsonConverter.cs @@ -28,8 +28,8 @@ JsonSerializerOptions options { string key = reader.GetString (); reader.Read (); - var value = JsonSerializer.Deserialize (ref reader, options); - dictionary.Add (key, value); + var value = JsonSerializer.Deserialize (ref reader, typeof (T), _serializerContext); + dictionary.Add (key, (T)value); } } else if (reader.TokenType == JsonTokenType.EndArray) @@ -51,7 +51,7 @@ public override void Write (Utf8JsonWriter writer, Dictionary value, //writer.WriteString (item.Key, item.Key); writer.WritePropertyName (item.Key); - JsonSerializer.Serialize (writer, item.Value, options); + JsonSerializer.Serialize (writer, item.Value, typeof (T), _serializerContext); writer.WriteEndObject (); } diff --git a/Terminal.Gui/Configuration/ScopeJsonConverter.cs b/Terminal.Gui/Configuration/ScopeJsonConverter.cs index 5419619e2e..3b41d09764 100644 --- a/Terminal.Gui/Configuration/ScopeJsonConverter.cs +++ b/Terminal.Gui/Configuration/ScopeJsonConverter.cs @@ -85,7 +85,7 @@ public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, Json try { scope! [propertyName].PropertyValue = - JsonSerializer.Deserialize (ref reader, propertyType!, options); + JsonSerializer.Deserialize (ref reader, propertyType!, _serializerContext); } catch (Exception ex) { @@ -133,7 +133,7 @@ public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, Json if (property is { }) { PropertyInfo prop = scope.GetType ().GetProperty (propertyName!)!; - prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); + prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, _serializerContext)); } else { @@ -160,7 +160,8 @@ public override void Write (Utf8JsonWriter writer, scopeT scope, JsonSerializerO foreach (PropertyInfo p in properties) { writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); - JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); + object? prop = scope.GetType ().GetProperty (p.Name)?.GetValue (scope); + JsonSerializer.Serialize (writer, prop, prop!.GetType (), _serializerContext); } foreach (KeyValuePair p in from p in scope @@ -205,7 +206,8 @@ SerializableConfigurationProperty scp } else { - JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); + object? prop = p.Value.PropertyValue; + JsonSerializer.Serialize (writer, prop, prop!.GetType (), _serializerContext); } } diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 145ad3cdc7..81c934d796 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -42,7 +42,7 @@ public class SettingsScope : Scope // Update the existing settings with the new settings. try { - Update (JsonSerializer.Deserialize (stream, _serializerOptions)!); + Update ((SettingsScope)JsonSerializer.Deserialize (stream, typeof (SettingsScope), _serializerOptions)!); OnUpdated (); Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); if (!Sources.Contains (source)) From 62b151e5c91c3427d0db114b23508b8dd957a14a Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 23:09:46 +0100 Subject: [PATCH 04/22] Add SourceGenerationContext. --- .../Configuration/SourceGenerationContext.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Terminal.Gui/Configuration/SourceGenerationContext.cs diff --git a/Terminal.Gui/Configuration/SourceGenerationContext.cs b/Terminal.Gui/Configuration/SourceGenerationContext.cs new file mode 100644 index 0000000000..ed93b68cae --- /dev/null +++ b/Terminal.Gui/Configuration/SourceGenerationContext.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace Terminal.Gui; + +/// +/// Allow AOT and self-contained single file applications with the +/// +[JsonSerializable (typeof (Attribute))] +[JsonSerializable (typeof (Color))] +[JsonSerializable (typeof (ThemeScope))] +[JsonSerializable (typeof (ColorScheme))] +[JsonSerializable (typeof (SettingsScope))] +[JsonSerializable (typeof (AppScope))] +[JsonSerializable (typeof (Key))] +[JsonSerializable (typeof (GlyphDefinitions))] +[JsonSerializable (typeof (ConfigProperty))] +[JsonSerializable (typeof (ShadowStyle))] +[JsonSerializable (typeof (string))] +[JsonSerializable (typeof (bool))] +[JsonSerializable (typeof (bool?))] +[JsonSerializable (typeof (Dictionary))] +internal partial class SourceGenerationContext : JsonSerializerContext +{ } From 7647de7679d7e11ed9df65554b2eea76f636463a Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 23:12:04 +0100 Subject: [PATCH 05/22] Fix compile warnings. --- Terminal.Gui/Application/Application.cs | 12 +- .../Configuration/ConfigurationManager.cs | 15 +++ .../Configuration/KeyCodeJsonConverter.cs | 2 +- .../Configuration/ScopeJsonConverter.cs | 8 +- Terminal.Gui/Configuration/SettingsScope.cs | 9 ++ Terminal.Gui/Configuration/ThemeManager.cs | 113 ++++++++++++++++++ .../CursesDriver/UnmanagedLibrary.cs | 2 + Terminal.Gui/ConsoleDrivers/NetDriver.cs | 3 + Terminal.Gui/FileServices/FileDialogStyle.cs | 4 +- 9 files changed, 164 insertions(+), 4 deletions(-) diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 9e501f22c0..b8a1be6ad8 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; @@ -56,7 +57,7 @@ internal static List GetSupportedCultures () string assemblyLocation = AppDomain.CurrentDomain.BaseDirectory; // Find the resource file name of the assembly - var resourceFilename = $"{Path.GetFileNameWithoutExtension (assembly.Location)}.resources.dll"; + var resourceFilename = $"{Path.GetFileNameWithoutExtension (AppContext.BaseDirectory)}.resources.dll"; // Return all culture for which satellite folder found with culture code. return culture.Where ( @@ -192,6 +193,8 @@ internal static void ResetState (bool ignoreDisposed = false) /// to use. If neither or are /// specified the default driver for the platform will be used. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (driver, driverName); } internal static bool _initialized; @@ -206,6 +209,8 @@ internal static void ResetState (bool ignoreDisposed = false) // Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset. // // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static void InternalInit ( ConsoleDriver driver = null, string driverName = null, @@ -318,6 +323,7 @@ internal static void InternalInit ( /// Gets of list of types that are available. /// + [RequiresUnreferencedCode ("AOT")] public static List GetDriverTypes () { // use reflection to get the list of drivers @@ -660,6 +666,8 @@ internal static bool PositionCursor (View view) /// /// /// The created object. The caller is responsible for disposing this object. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static Toplevel Run (Func errorHandler = null, ConsoleDriver driver = null) { return Run (errorHandler, driver); } /// @@ -683,6 +691,8 @@ internal static bool PositionCursor (View view) /// if has already been called. /// /// The created T object. The caller is responsible for disposing this object. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static T Run (Func errorHandler = null, ConsoleDriver driver = null) where T : Toplevel, new() { diff --git a/Terminal.Gui/Configuration/ConfigurationManager.cs b/Terminal.Gui/Configuration/ConfigurationManager.cs index 6bed7a20ae..68c8c184c6 100644 --- a/Terminal.Gui/Configuration/ConfigurationManager.cs +++ b/Terminal.Gui/Configuration/ConfigurationManager.cs @@ -153,6 +153,8 @@ public enum ConfigLocations /// public static SettingsScope? Settings { + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] get { if (_settings is null) @@ -184,6 +186,8 @@ public static SettingsScope? Settings public static event EventHandler? Applied; /// Applies the configuration settings to the running instance. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static void Apply () { var settings = false; @@ -238,6 +242,8 @@ public static string GetEmptyJson () /// If the state of will be reset to the /// defaults. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static void Load (bool reset = false) { Debug.WriteLine ("ConfigurationManager.Load()"); @@ -325,6 +331,8 @@ public static void PrintJsonErrors () /// . /// /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public static void Reset () { Debug.WriteLine (@"ConfigurationManager.Reset()"); @@ -478,6 +486,8 @@ where destProp.CanWrite /// make sure you copy the Theme definitions from the existing Terminal.Gui.Resources.config.json file. /// /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static void GetHardCodedDefaults () { if (_allConfigProperties is null) @@ -499,6 +509,7 @@ internal static void GetHardCodedDefaults () /// Initializes the internal state of ConfigurationManager. Nominally called once as part of application startup /// to initialize global state. Also called from some Unit Tests to ensure correctness (e.g. Reset()). /// + [RequiresUnreferencedCode ("AOT")] internal static void Initialize () { _allConfigProperties = new (); @@ -588,6 +599,8 @@ from p in enumerable /// Creates a JSON document with the configuration specified. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static string ToJson () { //Debug.WriteLine ("ConfigurationManager.ToJson()"); @@ -595,6 +608,8 @@ internal static string ToJson () return JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static Stream ToStream () { string json = JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); diff --git a/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs b/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs index c7b7053113..9b24c7d0a6 100644 --- a/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs +++ b/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs @@ -42,7 +42,7 @@ public override KeyCode Read (ref Utf8JsonReader reader, Type typeToConvert, Jso } // The enum uses "D0..D9" for the number keys - if (Enum.TryParse (reader.GetString ().TrimStart ('D', 'd'), false, out key)) + if (Enum.TryParse (reader.GetString ()!.TrimStart ('D', 'd'), false, out key)) { break; } diff --git a/Terminal.Gui/Configuration/ScopeJsonConverter.cs b/Terminal.Gui/Configuration/ScopeJsonConverter.cs index 3b41d09764..a23216ea00 100644 --- a/Terminal.Gui/Configuration/ScopeJsonConverter.cs +++ b/Terminal.Gui/Configuration/ScopeJsonConverter.cs @@ -1,5 +1,6 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -11,9 +12,12 @@ namespace Terminal.Gui; /// data to/from JSON documents. /// /// -internal class ScopeJsonConverter : JsonConverter where scopeT : Scope +internal class ScopeJsonConverter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] scopeT> : JsonConverter where scopeT : Scope { + [RequiresDynamicCode ("Calls System.Type.MakeGenericType(params Type[])")] +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. { if (reader.TokenType != JsonTokenType.StartObject) { @@ -223,6 +227,8 @@ internal abstract class ReadHelper internal class ReadHelper : ReadHelper { private readonly ReadDelegate _readDelegate; + + [RequiresUnreferencedCode ("Calls System.Delegate.CreateDelegate(Type, Object, String)")] public ReadHelper (object converter) { _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); } public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 81c934d796..8ce37bbbcf 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -1,5 +1,6 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -37,6 +38,8 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON string. /// Json document to update the settings with. /// The source (filename/resource name) the Json document was read from. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (Stream stream, string source) { // Update the existing settings with the new settings. @@ -67,6 +70,8 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON file. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (string filePath) { string realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); @@ -93,6 +98,8 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON string. /// Json document to update the settings with. /// The source (filename/resource name) the Json document was read from. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (string json, string source) { var stream = new MemoryStream (); @@ -107,6 +114,8 @@ public class SettingsScope : Scope /// Updates the with the settings from a Json resource. /// /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) { if (resourceName is null || string.IsNullOrEmpty (resourceName)) diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs index 9787daa8d6..e6efe32e08 100644 --- a/Terminal.Gui/Configuration/ThemeManager.cs +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace Terminal.Gui; @@ -64,6 +65,9 @@ private ThemeManager () { } // Prevent instantiation outside public string Theme { get => SelectedTheme; + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] set => SelectedTheme = value; } @@ -73,9 +77,14 @@ public string Theme [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] public static Dictionary? Themes { + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] get => Settings? ["Themes"] ?.PropertyValue as Dictionary; // themes ?? new Dictionary (); + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] set => //if (themes is null || value is null) { @@ -93,6 +102,9 @@ public static Dictionary? Themes internal static string SelectedTheme { get => _theme; + + [RequiresUnreferencedCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] + [RequiresDynamicCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] set { string oldTheme = _theme; @@ -109,6 +121,8 @@ internal static string SelectedTheme /// Event fired he selected theme has changed. application. public event EventHandler? ThemeChanged; + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void GetHardCodedDefaults () { //Debug.WriteLine ("Themes.GetHardCodedDefaults()"); @@ -129,6 +143,8 @@ internal void OnThemeChanged (string theme) ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); } + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void Reset () { Debug.WriteLine ("Themes.Reset()"); @@ -140,33 +156,130 @@ internal static void Reset () #region IDictionary #pragma warning disable 1591 + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Keys => ((IDictionary)Themes!).Keys; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Values => ((IDictionary)Themes!).Values; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public int Count => ((ICollection>)Themes!).Count; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; public ThemeScope this [string key] { + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. get => ((IDictionary)Themes!) [key]; +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. set => ((IDictionary)Themes!) [key] = value; +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Add (string key, ThemeScope value) { ((IDictionary)Themes!).Add (key, value); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool ContainsKey (string key) { return ((IDictionary)Themes!).ContainsKey (key); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Remove (string key) { return ((IDictionary)Themes!).Remove (key); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool TryGetValue (string key, out ThemeScope value) { return ((IDictionary)Themes!).TryGetValue (key, out value!); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Add (KeyValuePair item) { ((ICollection>)Themes!).Add (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Clear () { ((ICollection>)Themes!).Clear (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Contains (KeyValuePair item) { return ((ICollection>)Themes!).Contains (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void CopyTo (KeyValuePair [] array, int arrayIndex) +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. { ((ICollection>)Themes!).CopyTo (array, arrayIndex); } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Remove (KeyValuePair item) { return ((ICollection>)Themes!).Remove (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public IEnumerator> GetEnumerator () { return ((IEnumerable>)Themes!).GetEnumerator (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable)Themes!).GetEnumerator (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore 1591 #endregion diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs index 6aef4230fd..7400214ecc 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs @@ -13,6 +13,7 @@ // limitations under the License. #define GUICS +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Unix.Terminal; @@ -69,6 +70,7 @@ private static string GetUname () } } + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] static UnmanagedLibrary () { PlatformID platform = Environment.OSVersion.Platform; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 0dd0e9038c..86ef134664 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -3,6 +3,7 @@ // using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping; using static Terminal.Gui.NetEvents; @@ -452,6 +453,7 @@ ref ConsoleModifiers mod HandleKeyboardEvent (newConsoleKeyInfo); } + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private MouseButtonState MapMouseFlags (MouseFlags mouseFlags) { MouseButtonState mbs = default; @@ -1249,6 +1251,7 @@ public virtual void ResizeScreen () #region Color Handling // Cache the list of ConsoleColor values. + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private static readonly HashSet ConsoleColorValues = new ( Enum.GetValues (typeof (ConsoleColor)) .OfType () diff --git a/Terminal.Gui/FileServices/FileDialogStyle.cs b/Terminal.Gui/FileServices/FileDialogStyle.cs index 83adb448cd..9cc6557f15 100644 --- a/Terminal.Gui/FileServices/FileDialogStyle.cs +++ b/Terminal.Gui/FileServices/FileDialogStyle.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO.Abstractions; using Terminal.Gui.Resources; using static System.Environment; @@ -143,6 +144,7 @@ public FileDialogStyle (IFileSystem fileSystem) /// public string WrongFileTypeFeedback { get; set; } = Strings.fdWrongFileTypeFeedback; + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private Dictionary DefaultTreeRootGetter () { Dictionary roots = new (); From b704b307746ea340597dab97b14060e7774b8342 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 Jul 2024 23:13:56 +0100 Subject: [PATCH 06/22] Using JsonStringEnumConverter for AOT compatible. --- Terminal.Gui/Views/Button.cs | 2 +- Terminal.Gui/Views/Dialog.cs | 8 ++++---- Terminal.Gui/Views/FrameView.cs | 2 +- Terminal.Gui/Views/MessageBox.cs | 2 +- Terminal.Gui/Views/Window.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index f6acd3338f..81d70ba9fc 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -39,7 +39,7 @@ public class Button : View, IDesignable /// Gets or sets whether s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; diff --git a/Terminal.Gui/Views/Dialog.cs b/Terminal.Gui/Views/Dialog.cs index 7e6d82ffde..bcdca4fa80 100644 --- a/Terminal.Gui/Views/Dialog.cs +++ b/Terminal.Gui/Views/Dialog.cs @@ -19,13 +19,13 @@ public class Dialog : Window /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static Alignment DefaultButtonAlignment { get; set; } = Alignment.End; /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static AlignmentModes DefaultButtonAlignmentModes { get; set; } = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems; /// @@ -47,7 +47,7 @@ public class Dialog : Window /// Gets or sets whether all s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public new static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; /// @@ -56,7 +56,7 @@ public class Dialog : Window /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single; private readonly List