Просмотр исходного кода

Merge pull request #3582 from BDisp/v2_3574_self-contained-single-file

Fixes #3574. Enabling trim mode breaks program at runtime (v2 only)
Tig 1 год назад
Родитель
Сommit
f1fe7e7628
38 измененных файлов с 521 добавлено и 517 удалено
  1. 0 6
      Directory.Build.props
  2. 0 5
      Directory.Build.targets
  3. 21 20
      Example/Example.cs
  4. 3 0
      FSharpExample/FSharpExample.fsproj
  5. 36 442
      FSharpExample/Program.fs
  6. 8 6
      README.md
  7. 89 0
      SelfContained/Program.cs
  8. 16 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Debug.pubxml
  9. 16 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Release.pubxml
  10. 16 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Debug.pubxml
  11. 16 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Release.pubxml
  12. 17 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml
  13. 17 0
      SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml
  14. 9 0
      SelfContained/README.md
  15. 25 0
      SelfContained/SelfContained.csproj
  16. 11 1
      Terminal.Gui/Application/Application.cs
  17. 3 3
      Terminal.Gui/Configuration/AttributeJsonConverter.cs
  18. 1 1
      Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs
  19. 22 4
      Terminal.Gui/Configuration/ConfigurationManager.cs
  20. 3 3
      Terminal.Gui/Configuration/DictionaryJsonConverter.cs
  21. 1 1
      Terminal.Gui/Configuration/KeyCodeJsonConverter.cs
  22. 13 5
      Terminal.Gui/Configuration/ScopeJsonConverter.cs
  23. 10 1
      Terminal.Gui/Configuration/SettingsScope.cs
  24. 23 0
      Terminal.Gui/Configuration/SourceGenerationContext.cs
  25. 113 0
      Terminal.Gui/Configuration/ThemeManager.cs
  26. 2 0
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs
  27. 3 0
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  28. 3 3
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  29. 3 1
      Terminal.Gui/FileServices/FileDialogStyle.cs
  30. 5 7
      Terminal.Gui/Terminal.Gui.csproj
  31. 1 1
      Terminal.Gui/Views/Button.cs
  32. 4 4
      Terminal.Gui/Views/Dialog.cs
  33. 1 1
      Terminal.Gui/Views/FrameView.cs
  34. 1 1
      Terminal.Gui/Views/MessageBox.cs
  35. 1 1
      Terminal.Gui/Views/Window.cs
  36. 6 0
      Terminal.sln
  37. 1 0
      UICatalog/UICatalog.csproj
  38. 1 0
      UnitTests/UnitTests.csproj

+ 0 - 6
Directory.Build.props

@@ -1,6 +0,0 @@
-<Project>
-  <ItemGroup>
-    <PackageReference Include="JetBrains.Annotations" Version="[2024,)" PrivateAssets="all" />
-    <PackageReference Include="JetBrains.ExternalAnnotations" Version="[10.2.149,)" PrivateAssets="all" />
-  </ItemGroup>
-</Project>

+ 0 - 5
Directory.Build.targets

@@ -1,5 +0,0 @@
-<Project>
-  <PropertyGroup>
-    <DefineConstants>$(DefineConstants);DIMAUTO</DefineConstants>
-  </PropertyGroup>
-</Project>

+ 21 - 20
Example/Example.cs

@@ -6,19 +6,19 @@
 using System;
 using Terminal.Gui;
 
-var app = Application.Run<ExampleWindow> ();
-
-Console.WriteLine ($"Username: {app.UserNameText.Text}");
-
-app.Dispose ();
+Application.Run<ExampleWindow> ().Dispose ();
 
 // Before the application exits, reset Terminal.Gui for clean shutdown
 Application.Shutdown ();
 
+// To see this output on the screen it must be done after shutdown,
+// which restores the previous screen.
+Console.WriteLine ($@"Username: {ExampleWindow.UserName}");
+
 // Defines a top-level window with border and title
 public class ExampleWindow : Window
 {
-    public TextField UserNameText;
+    public static string UserName;
 
     public ExampleWindow ()
     {
@@ -27,7 +27,7 @@ public class ExampleWindow : Window
         // Create input components and labels
         var usernameLabel = new Label { Text = "Username:" };
 
-        UserNameText = new TextField
+        var userNameText = new TextField
         {
             // Position text field adjacent to the label
             X = Pos.Right (usernameLabel) + 1,
@@ -46,7 +46,7 @@ public class ExampleWindow : Window
             Secret = true,
 
             // align with the text box above
-            X = Pos.Left (UserNameText),
+            X = Pos.Left (userNameText),
             Y = Pos.Top (passwordLabel),
             Width = Dim.Fill ()
         };
@@ -64,19 +64,20 @@ public class ExampleWindow : Window
 
         // 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");
-                                    Application.RequestStop ();
-                                }
-                                else
-                                {
-                                    MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
-                                }
-                            };
+                           {
+                               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);
+        Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin);
     }
 }

+ 3 - 0
FSharpExample/FSharpExample.fsproj

@@ -13,4 +13,7 @@
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
   </ItemGroup>
+  <ItemGroup>
+    <PackageReference Update="FSharp.Core" Version="8.0.300" />
+  </ItemGroup>
 </Project>

+ 36 - 442
FSharpExample/Program.fs

@@ -1,454 +1,48 @@
-open System
-open System.Diagnostics
-open System.Globalization
-open System.IO
-open NStack
-open Terminal.Gui
+open Terminal.Gui
 
-let ustr (x: string) = ustring.Make(x)
-let mutable ml2 = Unchecked.defaultof<Label>
-let mutable ml = Unchecked.defaultof<Label>
-let mutable menu = Unchecked.defaultof<MenuBar>
-let mutable menuKeysStyle = Unchecked.defaultof<CheckBox>
-let mutable menuAutoMouseNav = Unchecked.defaultof<CheckBox>
-
-type Box10x (x: int, y: int) =
-    inherit View (Rect(x, y, 20, 10))
-    let w = 40
-    let h = 50
-
-    new () =
-        new Box10x ()
-
-    member _.GetContentSize () =
-        Size (w, h)
-
-    member _.SetCursorPosition (_ : Point) =
-        raise (NotImplementedException())
-
-    override this.Redraw (_: Rect) =
-        Application.Driver.SetAttribute this.ColorScheme.Focus
-        do
-        let mutable y = 0
-        while y < h do
-        this.Move (0, y)
-        Application.Driver.AddStr (ustr (string y))
-        do
-        let mutable x = 0
-        while x < w - (y.ToString ()).Length do
-            if (string y).Length < w
-            then Application.Driver.AddStr (ustr " ")
-            x <- x + 1
-        y <- y + 1
-
-type Filler (rect: Rect) =
-    inherit View(rect)
-    new () =
-        new Filler ()
-
-    override this.Redraw (_: Rect) =
-        Application.Driver.SetAttribute this.ColorScheme.Focus
-        let mutable f = this.Frame
-        do
-        let mutable y = 0
-        while y < f.Width do
-        this.Move (0, y)
-        do
-        let mutable x = 0
-        while x < f.Height do
-            let r =
-                match x % 3 with
-                | 0 ->
-                    Application.Driver.AddRune ((Rune ((string y).ToCharArray (0, 1)).[0]))
-                    if y > 9 then
-                        Application.Driver.AddRune ((Rune ((string y).ToCharArray (1, 1)).[0]))
-                    Rune '.'
-                | 1 -> Rune 'o'
-                | _ -> Rune 'O'
-            Application.Driver.AddRune r
-            x <- x + 1
-        y <- y + 1
-
-let ShowTextAlignments () =
-    let okButton = new Button (ustr "Ok", true)
-    okButton.add_Clicked (Action (Application.RequestStop))
-    let cancelButton = new Button (ustr "Cancel", true)
-    cancelButton.add_Clicked (Action (Application.RequestStop))
-
-    let container = new Dialog (ustr "Text Alignments", 50, 20, okButton, cancelButton)
-    let txt = "Hello world, how are you doing today"
-    container.Add (
-        new Label (Rect(0, 1, 40, 3), ustr ((sprintf "%O-%O" 1) txt), TextAlignment = TextAlignment.Left),
-        new Label (Rect(0, 3, 40, 3), ustr ((sprintf "%O-%O" 2) txt), TextAlignment = TextAlignment.Right),
-        new Label (Rect(0, 5, 40, 3), ustr ((sprintf "%O-%O" 3) txt), TextAlignment = TextAlignment.Centered),
-        new Label (Rect(0, 7, 40, 3), ustr ((sprintf "%O-%O" 4) txt), TextAlignment = TextAlignment.Justified))
-    Application.Run container
-
-let ShowEntries (container: View) =
-    let scrollView = 
-        new ScrollView (Rect (50, 10, 20, 8),
-            ContentSize = Size (20, 50),
-            ShowVerticalScrollIndicator = true,
-            ShowHorizontalScrollIndicator = true)
-    scrollView.Add (new Filler (Rect (0, 0, 40, 40)))
-    let scrollView2 = 
-        new ScrollView (Rect (72, 10, 3, 3),
-            ContentSize = Size (100, 100),
-            ShowVerticalScrollIndicator = true,
-            ShowHorizontalScrollIndicator = true)
-    scrollView2.Add (new Box10x (0, 0))
-    let progress = new ProgressBar (Rect(68, 1, 10, 1))
-    let timer = Func<MainLoop, bool> (fun _ ->
-        progress.Pulse ()
-        true)
-
-    Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (300.), timer) |> ignore
-
-    let login =
-        new Label (ustr "Login: ",
-            X = Pos.At 3,
-            Y = Pos.At 6)
-    let password =
-        new Label (ustr "Password: ",
-            X = Pos.Left login,
-            Y = Pos.Bottom login + Pos.At 1)
-    let loginText =
-        new TextField (ustr "",
-            X = Pos.Right password,
-            Y = Pos.Top login,
-            Width = Dim.op_Implicit 40)
-    let passText =
-        new TextField (ustr "",
-            Secret = true,
-            X = Pos.Left loginText,
-            Y = Pos.Top password,
-            Width = Dim.Width loginText)
-    let tf = new Button (3, 19, ustr "Ok")
-    container.Add (login, loginText, password, passText,
-        new FrameView (Rect (3, 10, 25, 6), ustr "Options",
-            [| new CheckBox (1, 0, ustr "Remember me")
-               new RadioGroup (1, 2, 
-                [| ustr "_Personal"; ustr "_Company"|])|]),
-        new ListView (Rect (59, 6, 16, 4),
-                [| "First row"
-                   "<>"
-                   "This is a very long row that should overflow what is shown"
-                   "4th"
-                   "There is an empty slot on the second row"
-                   "Whoa"
-                   "This is so cool" |]),
-        scrollView, scrollView2, tf,
-        new Button (10, 19, ustr "Cancel"),
-        new TimeField (3, 20, DateTime.Now.TimeOfDay),
-        new TimeField (23, 20, DateTime.Now.TimeOfDay, true),
-        new DateField (3, 22, DateTime.Now),
-        new DateField (23, 22, DateTime.Now, true),
-        progress,
-        new Label (3, 24, ustr "Press F9 (on Unix, ESC+9 is an alias) to activate the menubar"),
-        menuKeysStyle,
-        menuAutoMouseNav)
-    container.SendSubviewToBack tf
-
-let NewFile () =
-    let okButton = new Button (ustr "Ok", true)
-    okButton.add_Clicked (Action (Application.RequestStop))
-    let cancelButton = new Button (ustr "Cancel", true)
-    cancelButton.add_Clicked (Action (Application.RequestStop))
-
-    let d = new Dialog (ustr "New File", 50, 20, okButton, cancelButton)
-    ml2 <- new Label (1, 1, ustr "Mouse Debug Line")
-    d.Add ml2
-    Application.Run d
-
-let GetFileName () =
-    let mutable fname = Unchecked.defaultof<_>
-    for s in [| "/etc/passwd"; "c:\\windows\\win.ini" |] do
-        if File.Exists s
-        then fname <- s
-    fname
-
-let Editor (top: Toplevel) =
-    let tframe = top.Frame
-    let ntop = new Toplevel(tframe)
-    let menu = 
-        new MenuBar(
-            [| MenuBarItem (ustr "_File",
-                 [| MenuItem (ustr "_Close", ustring.Empty, (fun () -> Application.RequestStop ())) |]);
-                    MenuBarItem (ustr "_Edit",
-                        [| MenuItem (ustr "_Copy", ustring.Empty, Unchecked.defaultof<_>)
-                           MenuItem (ustr "C_ut", ustring.Empty, Unchecked.defaultof<_>)
-                           MenuItem (ustr "_Paste", ustring.Empty, Unchecked.defaultof<_>) |]) |])
-    ntop.Add menu
-    let fname = GetFileName ()
-    let win = 
-        new Window (
-            ustr (if not (isNull fname) then fname else "Untitled"),
-            X = Pos.At 0,
-            Y = Pos.At 1,
-            Width = Dim.Fill (),
-            Height = Dim.Fill ())
-    ntop.Add win
-    let text = new TextView (Rect(0, 0, (tframe.Width - 2), (tframe.Height - 3)))
-    if fname <> Unchecked.defaultof<_>
-    then text.Text <- ustr (File.ReadAllText fname)
-    win.Add text
-    Application.Run ntop
-
-let Quit () =
-    MessageBox.Query (50, 7, ustr "Quit Demo", ustr "Are you sure you want to quit this demo?", ustr "Yes", ustr "No") = 0
-
-let Close () =
-    MessageBox.ErrorQuery (50, 7, ustr "Error", ustr "There is nothing to close", ustr "Ok")
-    |> ignore
-
-let Open () =
-    let d = new OpenDialog (ustr "Open", ustr "Open a file", AllowsMultipleSelection = true)
-    Application.Run d
-    if not d.Canceled
-        then MessageBox.Query (50, 7, ustr "Selected File", ustr (String.Join (", ", d.FilePaths)), ustr "Ok") |> ignore
-
-let ShowHex (top: Toplevel) =
-    let tframe = top.Frame
-    let ntop = new Toplevel (tframe)
-    let menu = 
-        new MenuBar (
-            [| MenuBarItem (ustr "_File",
-                 [| MenuItem (ustr "_Close", ustring.Empty, (fun () -> Application.RequestStop ())) |]) |])
-    ntop.Add menu
-    let win =
-        new Window (ustr "/etc/passwd",
-            X = Pos.At 0,
-            Y = Pos.At 1,
-            Width = Dim.Fill (),
-            Height = Dim.Fill ())
-    ntop.Add win
-    let fname = GetFileName ()
-    let source = File.OpenRead fname
-    let hex = 
-        new HexView (source,
-            X = Pos.At 0,
-            Y = Pos.At 0,
-            Width = Dim.Fill (),
-            Height = Dim.Fill ())
-    win.Add hex
-    Application.Run ntop
-
-type MenuItemDetails () =
-    inherit MenuItem ()
-    new (title: ustring, help: ustring, action: Action) as this =
-        MenuItemDetails ()
-        then
-            this.Title <- title
-            this.Help <- help
-            this.Action <- action
-
-    static member Instance (mi: MenuItem) =
-        (mi.GetMenuItem ()) :?> MenuItemDetails
-
-type MenuItemDelegate = delegate of MenuItemDetails -> MenuItem
-
-let ShowMenuItem (mi: MenuItemDetails) =
-    MessageBox.Query (70, 7, ustr (mi.Title.ToString ()),
-        ustr ((sprintf "%O selected. Is from submenu: %O" (mi.Title.ToString ())) (mi.GetMenuBarItem ())), ustr "Ok")
-    |> ignore
-
-let MenuKeysStyleToggled (_: bool) =
-    menu.UseKeysUpDownAsKeysLeftRight <- menuKeysStyle.Checked
-
-let MenuAutoMouseNavToggled (_: bool) =
-    menu.WantMousePositionReports <- menuAutoMouseNav.Checked
-
-let Copy () =
-    let textField = menu.LastFocused :?> TextField
-    if textField <> Unchecked.defaultof<_> && textField.SelectedLength <> 0
-    then textField.Copy ()
+type ExampleWindow() as this =
+    inherit Window()
+    
+    do
+        this.Title <- sprintf "Example App (%O to quit)" Application.QuitKey
 
-let Cut () =
-    let textField = menu.LastFocused :?> TextField
-    if textField <> Unchecked.defaultof<_> && textField.SelectedLength <> 0
-    then textField.Cut ()
+        // Create input components and labels
+        let usernameLabel = new Label(Text = "Username:")
 
-let Paste () =
-    let textField = menu.LastFocused :?> TextField
-    if textField <> Unchecked.defaultof<_>
-    then textField.Paste ()
+        let userNameText = new TextField(X = Pos.Right(usernameLabel) + Pos.op_Implicit(1), Width = Dim.Fill())
 
-let Help () =
-    MessageBox.Query (50, 7, ustr "Help", ustr "This is a small help\nBe kind.", ustr "Ok")
-    |> ignore
+        let passwordLabel = new Label(Text = "Password:", X = Pos.Left(usernameLabel), Y = Pos.Bottom(usernameLabel) +  Pos.op_Implicit(1))
 
-let Load () =
-    MessageBox.Query (50, 7, ustr "Load", ustr "This is a small load\nBe kind.", ustr "Ok")
-    |> ignore
+        let passwordText = new TextField(Secret = true, X = Pos.Left(userNameText), Y = Pos.Top(passwordLabel), Width = Dim.Fill())
 
-let Save () =
-    MessageBox.Query (50, 7, ustr "Save ", ustr "This is a small save\nBe kind.", ustr "Ok")
-    |> ignore
+        // Create login button
+        let btnLogin = new Button(Text = "Login", Y = Pos.Bottom(passwordLabel) +  Pos.op_Implicit(1), X = Pos.Center(), IsDefault = true)
 
-let ListSelectionDemo (multiple: bool) =
-    let okButton = new Button (ustr "Ok", true)
-    okButton.add_Clicked (Action (Application.RequestStop))
-    let cancelButton = new Button (ustr "Cancel")
-    cancelButton.add_Clicked (Action (Application.RequestStop))
+        // When login button is clicked display a message popup
+        btnLogin.Accept.Add(fun _ ->
+            if userNameText.Text = "admin" && passwordText.Text = "password" then
+                MessageBox.Query("Logging In", "Login Successful", "Ok") |> ignore
+                ExampleWindow.UserName <- userNameText.Text.ToString()
+                Application.RequestStop()
+            else
+                MessageBox.ErrorQuery("Logging In", "Incorrect username or password", "Ok") |> ignore
+        )
 
-    let d = new Dialog (ustr "Selection Demo", 60, 20, okButton, cancelButton)
-    let animals = ResizeArray<_> ()
-    animals.AddRange([| "Alpaca"; "Llama"; "Lion"; "Shark"; "Goat" |])
-    let msg =
-        new Label (ustr "Use space bar or control-t to toggle selection",
-            X = Pos.At 1,
-            Y = Pos.At 1,
-            Width = Dim.Fill () - Dim.op_Implicit 1,
-            Height = Dim.op_Implicit 1)
-    let list =
-        new ListView (animals,
-            X = Pos.At 1,
-            Y = Pos.At 3,
-            Width = Dim.Fill () - Dim.op_Implicit 4,
-            Height = Dim.Fill () - Dim.op_Implicit 4,
-            AllowsMarking = true,
-            AllowsMultipleSelection = multiple)
-    d.Add (msg, list)
-    Application.Run d
-    let mutable result = ""
-    do
-        let mutable i = 0
-        while i < animals.Count do
-        if list.Source.IsMarked i
-        then result <- result + animals.[i] + " "
-        i <- i + 1
-    MessageBox.Query (60, 10, ustr "Selected Animals", ustr (if result = "" then "No animals selected" else result), ustr "Ok") |> ignore
+        // Add the views to the Window
+        this.Add(usernameLabel, userNameText, passwordLabel, passwordText, btnLogin)
 
-let OnKeyDownPressUpDemo () =
-    let closeButton = new Button (ustr "Close")
-    closeButton.add_Clicked (Action (Application.RequestStop))
+    static member val UserName = "" with get, set
 
-    let container = new Dialog (ustr "KeyDown & KeyPress & KeyUp demo", 80, 20, closeButton, Width = Dim.Fill (), Height = Dim.Fill ())
+[<EntryPoint>]
+let main argv =
+    Application.Init()
+    Application.Run<ExampleWindow>().Dispose()
     
-    let list = ResizeArray<_> ()
-    let listView = 
-        new ListView (list,
-            X = Pos.At 0,
-            Y = Pos.At 0,
-            Width = Dim.Fill () - Dim.op_Implicit 1,
-            Height = Dim.Fill () - Dim.op_Implicit 2,
-            ColorScheme = Colors.TopLevel)
-    container.Add (listView)
+    // Before the application exits, reset Terminal.Gui for clean shutdown
+    Application.Shutdown()
     
-    let keyDownPressUp (keyEvent: KeyEvent, updown: string) =
-        match updown with
-        | "Down"
-        | "Up"
-        | "Press" -> 
-            list.Add (keyEvent.ToString ())    
-        | _ -> failwithf "Unknown: %s" updown
-        listView.MoveDown ()
-
-    container.add_KeyDown(Action<View.KeyEventEventArgs> (fun (e: View.KeyEventEventArgs) -> keyDownPressUp (e.KeyEvent, "Down") |> ignore))
-    container.add_KeyPress(Action<View.KeyEventEventArgs> (fun (e: View.KeyEventEventArgs) -> keyDownPressUp (e.KeyEvent, "Press") |> ignore))
-    container.add_KeyUp(Action<View.KeyEventEventArgs> (fun (e: View.KeyEventEventArgs) -> keyDownPressUp (e.KeyEvent, "Up") |> ignore))
-    Application.Run (container)
-
-let Main () =
-    if Debugger.IsAttached then
-        CultureInfo.DefaultThreadCurrentUICulture <- CultureInfo.GetCultureInfo ("en-US")
-    Application.Init()
-    let top = Application.Top
-    let margin = 3
-    let win = 
-        new Window (ustr "Hello",
-            X = Pos.At 1,
-            Y = Pos.At 1,
-            Width = Dim.Fill () - Dim.op_Implicit margin,
-            Height = Dim.Fill () - Dim.op_Implicit margin)
-    let menuItems =
-        [|MenuItemDetails (ustr "F_ind",ustr "", Unchecked.defaultof<_>);
-            MenuItemDetails (ustr "_Replace", ustr "", Unchecked.defaultof<_>);
-            MenuItemDetails (ustr "_Item1", ustr "", Unchecked.defaultof<_>);
-            MenuItemDetails (ustr "_Also From Sub Menu", ustr "", Unchecked.defaultof<_>)|]
-    menuItems.[0].Action <- fun _ -> ShowMenuItem (menuItems.[0])
-    menuItems.[1].Action <- fun _ -> ShowMenuItem (menuItems.[1])
-    menuItems.[2].Action <- fun _ -> ShowMenuItem (menuItems.[2])
-    menuItems.[3].Action <- fun _ -> ShowMenuItem (menuItems.[3])
-    menu <-
-        new MenuBar (
-            [| MenuBarItem(ustr "_File",
-                    [| MenuItem (ustr "Text _Editor Demo", ustring.Empty, (fun () -> Editor top))
-                       MenuItem (ustr "_New", ustr "Creates new file", fun () -> NewFile())
-                       MenuItem (ustr "_Open", ustring.Empty, fun () -> Open())
-                       MenuItem (ustr "_Hex", ustring.Empty, (fun () -> ShowHex top))
-                       MenuItem (ustr "_Close", ustring.Empty, (fun () -> Close()))
-                       MenuItem (ustr "_Disabled", ustring.Empty, (fun () -> ()), (fun () -> false))
-                       Unchecked.defaultof<_>
-                       MenuItem (ustr "_Quit", ustring.Empty, (fun () -> if Quit() then top.Running <- false)) |])
-               MenuBarItem (ustr "_Edit",
-                    [| MenuItem (ustr "_Copy", ustring.Empty, fun () -> Copy())
-                       MenuItem (ustr "C_ut", ustring.Empty, fun () -> Cut())
-                       MenuItem (ustr "_Paste", ustring.Empty, fun () -> Paste())
-                       MenuBarItem (ustr "_Find and Replace",
-                           [| menuItems.[0] :> MenuItem
-                              menuItems.[1] :> MenuItem |]) :> MenuItem
-                       menuItems.[3] :> MenuItem
-                    |])
-               MenuBarItem (ustr "_List Demos", 
-                    [| MenuItem (ustr "Select _Multiple Items", ustring.Empty, (fun () -> ListSelectionDemo true))
-                       MenuItem (ustr "Select _Single Item", ustring.Empty, (fun () -> ListSelectionDemo false)) |])   
-               MenuBarItem (ustr "A_ssorted",
-                    [| MenuItem (ustr "_Show text alignments", ustring.Empty, (fun () -> ShowTextAlignments())) 
-                       MenuItem (ustr "_OnKeyDown/Press/Up", ustring.Empty, (fun () -> OnKeyDownPressUpDemo())) |])
-               MenuBarItem (ustr "_Test Menu and SubMenus",
-                    [| MenuBarItem (ustr "SubMenu1Item_1",
-                            [| MenuBarItem (ustr "SubMenu2Item_1",
-                                    [| MenuBarItem (ustr "SubMenu3Item_1",
-                                            [| menuItems.[2] :> MenuItem |]) :> MenuItem
-                                    |]) :> MenuItem
-                            |]) :> MenuItem
-                    |])
-               MenuBarItem (ustr "_About...", ustr "Demonstrates top-level menu item", (fun () -> MessageBox.ErrorQuery (50, 7, ustr "Error", ustr "This is a demo app for gui.cs", ustr "Ok") |> ignore)) |])
-    menuKeysStyle <- new CheckBox (3, 25, ustr "UseKeysUpDownAsKeysLeftRight", true)
-    menuKeysStyle.add_Toggled (Action<bool> (MenuKeysStyleToggled))
-    menuAutoMouseNav <- new CheckBox (40, 25, ustr "UseMenuAutoNavigation", true)
-    menuAutoMouseNav.add_Toggled (Action<bool> (MenuAutoMouseNavToggled))
-    ShowEntries win
-    let mutable count = 0
-    ml <- new Label (Rect (3, 17, 47, 1), ustr "Mouse: ")
-    Application.RootMouseEvent <- Action<MouseEvent> (
-            fun (me: MouseEvent) ->
-                ml.Text <- ustr (
-                     (((sprintf "Mouse: (%O,%O) - %O %O" me.X) me.Y) me.Flags) (count <- count + 1; count)))
-    let test = new Label (3, 18, ustr "Se iniciará el análisis")
-    win.Add test
-    win.Add ml
-    let drag = new Label (ustr "Drag: ", X = Pos.At 70, Y = Pos.At 24)
-    let dragText = 
-        new TextField (ustr "",
-            X = Pos.Right drag,
-            Y = Pos.Top drag,
-            Width = Dim.op_Implicit 40)
-    let statusBar = new StatusBar ([|
-        StatusItem(Key.F1, ustr "~F1~ Help", Action Help)
-        StatusItem(Key.F2, ustr "~F2~ Load", Action Load)
-        StatusItem(Key.F3, ustr "~F3~ Save", Action Save)
-        StatusItem(Key.Q, ustr "~^Q~ Quit", fun () -> if (Quit()) then top.Running <- false) |])
-    win.Add (drag, dragText)
-    let bottom = new Label (ustr "This should go on the bottom of the same top-level!")
-    win.Add bottom
-    let bottom2 = new Label (ustr "This should go on the bottom of another top-level!")
-    top.Add bottom2
-    top.add_LayoutComplete (Action<View.LayoutEventArgs>
-        (fun e ->
-            bottom.X <- win.X
-            bottom.Y <- Pos.Bottom win - Pos.Top win - Pos.At margin
-            bottom2.X <- Pos.Left win
-            bottom2.Y <- Pos.Bottom win)
-        )
-    top.Add win
-    top.Add (menu, statusBar)
-    Application.Run ()
-    Application.Shutdown ();
-
-module Demo =
-    [<EntryPoint>]
-    let main _ =
-        Main ()
-        0
+    // To see this output on the screen it must be done after shutdown,
+    // which restores the previous screen.
+    printfn "Username: %s" ExampleWindow.UserName
+    
+    0 // return an integer exit code

+ 8 - 6
README.md

@@ -37,10 +37,12 @@ dotnet run
 
 ## Showcase & Examples
 
-* **[UI Catalog](https://github.com/gui-cs/Terminal.GuiV2Docs/tree/master/UICatalog)** - The UI Catalog project provides an easy to use and extend sample illustrating the capabilities of **Terminal.Gui**. Run `dotnet run --project UICatalog` to run the UI Catalog.
-* **[C# Example](https://github.com/gui-cs/Terminal.GuiV2Docs/tree/master/Example)** - Run `dotnet run` in the `Example` directory to run the C# Example.
-* **[F# Example](https://github.com/gui-cs/Terminal.GuiV2Docs/tree/master/FSharpExample)** - An example showing how to build a Terminal.Gui app using F#.
-* **[Reactive Example](https://github.com/gui-cs/Terminal.GuiV2Docs/tree/master/ReactiveExample)** - A sample app that shows how to use `System.Reactive` and `ReactiveUI` with `Terminal.Gui`. The app uses the MVVM architecture that may seem familiar to folks coming from WPF, Xamarin Forms, UWP, Avalonia, or Windows Forms. In this app, we implement the data bindings using ReactiveUI `WhenAnyValue` syntax and [Pharmacist](https://github.com/reactiveui/pharmacist) — a tool that converts all events in a NuGet package into observable wrappers.
+* **[UI Catalog](./UICatalog/README.md)** - The UI Catalog project provides an easy to use and extend sample illustrating the capabilities of **Terminal.Gui**. Run `dotnet run --project UICatalog` to run the UI Catalog.
+* **[C# Example](./Example/README.md)** - Run `dotnet run` in the `Example` directory to run the C# Example.
+* **[F# Example](./FSharpExample/)** - An example showing how to build a Terminal.Gui app using F#.
+* **[Reactive Example](./ReactiveExample/README.md)** - A sample app that shows how to use `System.Reactive` and `ReactiveUI` with `Terminal.Gui`. The app uses the MVVM architecture that may seem familiar to folks coming from WPF, Xamarin Forms, UWP, Avalonia, or Windows Forms. In this app, we implement the data bindings using ReactiveUI `WhenAnyValue` syntax and [Pharmacist](https://github.com/reactiveui/pharmacist) — a tool that converts all events in a NuGet package into observable wrappers.
+* **[CommunityToolkit Example](./CommunityToolkitExample/README.md)** - A example of using the `CommunityToolkit.MVVM` framework's `ObservableObject`, `ObservableProperty`, and `IRecipient<T>` in conjunction with `Microsoft.Extensions.DependencyInjection`.
+* **[C# SelfContained](./SelfContained/README.md)** - An example showing how to publish a Terminal.Gui app using C# self-contained single file.
 * **[PowerShell's `Out-ConsoleGridView`](https://github.com/PowerShell/GraphicalTools)** - `OCGV` sends the output from a command to an interactive table. 
 * **[F7History](https://github.com/gui-cs/F7History)** - Graphical Command History for PowerShell (built on PowerShell's `Out-ConsoleGridView`).
 * **[PoshRedisViewer](https://github.com/En3Tho/PoshRedisViewer)** - A compact Redis viewer module for PowerShell written in F#.
@@ -49,9 +51,9 @@ dotnet run
 
 ## Contributing
 
-See [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.GuiV2Docs/blob/master/CONTRIBUTING.md).
+See [CONTRIBUTING.md](./CONTRIBUTING.md).
 
-Debates on architecture and design can be found in Issues tagged with [design](https://github.com/gui-cs/Terminal.GuiV2Docs/issues?q=is%3Aopen+is%3Aissue+label%3Adesign).
+Debates on architecture and design can be found in Issues tagged with [design](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Av2+label%3Adesign).
 
 ## History
 

+ 89 - 0
SelfContained/Program.cs

@@ -0,0 +1,89 @@
+// 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<T>(Func<Exception, Boolean>, ConsoleDriver)")]
+    private static void Main (string [] args)
+    {
+        Application.Run<ExampleWindow> ().Dispose ();
+
+        // Before the application exits, reset Terminal.Gui for clean shutdown
+        Application.Shutdown ();
+
+        // To see this output on the screen it must be done after shutdown,
+        // which restores the previous screen.
+        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);
+    }
+}

+ 16 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Debug.pubxml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Debug</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Debug\net8.0\publish\linux-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+  </PropertyGroup>
+</Project>

+ 16 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_linux-x64_Release.pubxml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Release</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Release\net8.0\publish\linux-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+  </PropertyGroup>
+</Project>

+ 16 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Debug.pubxml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Debug</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Debug\net8.0\publish\osx-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>osx-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+  </PropertyGroup>
+</Project>

+ 16 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_osx-x64_Release.pubxml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Release</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Release\net8.0\publish\osx-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>osx-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+  </PropertyGroup>
+</Project>

+ 17 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Debug</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Debug\net8.0\publish\win-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+    <PublishReadyToRun>false</PublishReadyToRun>
+  </PropertyGroup>
+</Project>

+ 17 - 0
SelfContained/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <Configuration>Release</Configuration>
+    <Platform>Any CPU</Platform>
+    <PublishDir>bin\Release\net8.0\publish\win-x64\</PublishDir>
+    <PublishProtocol>FileSystem</PublishProtocol>
+    <_TargetId>Folder</_TargetId>
+    <TargetFramework>net8.0</TargetFramework>
+    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+    <SelfContained>true</SelfContained>
+    <PublishReadyToRun>false</PublishReadyToRun>
+  </PropertyGroup>
+</Project>

+ 9 - 0
SelfContained/README.md

@@ -0,0 +1,9 @@
+# Terminal.Gui C# SelfContained
+
+This example shows how to use the `Terminal.Gui` library to create a simple `self-contained` `single file` GUI application in C#.
+
+With `Debug` the `.csproj` is used and with `Release` the latest `nuget package` is used, either in `Solution Configurations` or in `Profile Publish`.
+
+To publish the self-contained single file in `Debug` or `Release` mode, it is not necessary to select it in the `Solution Configurations`, just choose the `Debug` or `Release` configuration in the `Publish Profile`.
+
+When executing the file directly from the self-contained single file and needing to debug it, it will be necessary to attach it to the debugger, just like any other standalone application. However, when trying to attach the file running on `Linux` or `macOS` to the debugger, it will issue the error "`Failed to attach to process: Unknown Error: 0x80131c3c`". This issue has already been reported on [Developer Community](https://developercommunity.visualstudio.com/t/Failed-to-attach-to-process:-Unknown-Err/10694351). Maybe it would be a good idea to vote in favor of this fix because I think `Visual Studio for macOS` is going to be discontinued and we need this fix to remotely attach a process running on `Linux` or `macOS` to `Windows 11`.

+ 25 - 0
SelfContained/SelfContained.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <PublishTrimmed>true</PublishTrimmed>
+    <TrimMode>Link</TrimMode>
+    <PublishSingleFile>true</PublishSingleFile>
+    <InvariantGlobalization>true</InvariantGlobalization>
+    <DebugType>embedded</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
+    <TrimmerRootAssembly Include="Terminal.Gui" />
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+    <PackageReference Include="Terminal.Gui" Version="[2.0.0-pre.1788,3)" />
+    <TrimmerRootAssembly Include="Terminal.Gui" />
+  </ItemGroup>
+
+</Project>

+ 11 - 1
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 @@ public static partial class Application
         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 @@ public static partial class Application
     ///     <see cref="ConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are
     ///     specified the default driver for the platform will be used.
     /// </param>
+    [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 @@ public static partial class Application
     // 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 @@ public static partial class Application
 
     /// <summary>Gets of list of <see cref="ConsoleDriver"/> types that are available.</summary>
     /// <returns></returns>
+    [RequiresUnreferencedCode ("AOT")]
     public static List<Type> GetDriverTypes ()
     {
         // use reflection to get the list of drivers
@@ -660,6 +666,8 @@ public static partial class Application
     ///     </para>
     /// </remarks>
     /// <returns>The created <see cref="Toplevel"/> object. The caller is responsible for disposing this object.</returns>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public static Toplevel Run (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null) { return Run<Toplevel> (errorHandler, driver); }
 
     /// <summary>
@@ -683,6 +691,8 @@ public static partial class Application
     ///     <see langword="null"/> if <see cref="Init"/> has already been called.
     /// </param>
     /// <returns>The created T object. The caller is responsible for disposing this object.</returns>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public static T Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
         where T : Toplevel, new()
     {

+ 3 - 3
Terminal.Gui/Configuration/AttributeJsonConverter.cs

@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
 
 namespace Terminal.Gui;
 
-/// <summary>Json converter fro the <see cref="Attribute"/> class.</summary>
+/// <summary>Json converter from the <see cref="Attribute"/> class.</summary>
 internal class AttributeJsonConverter : JsonConverter<Attribute>
 {
     private static AttributeJsonConverter _instance;
@@ -57,11 +57,11 @@ internal class AttributeJsonConverter : JsonConverter<Attribute>
             switch (propertyName?.ToLower ())
             {
                 case "foreground":
-                    foreground = JsonSerializer.Deserialize<Color> (color, options);
+                    foreground = JsonSerializer.Deserialize (color, _serializerContext.Color);
 
                     break;
                 case "background":
-                    background = JsonSerializer.Deserialize<Color> (color, options);
+                    background = JsonSerializer.Deserialize (color, _serializerContext.Color);
 
                     break;
 

+ 1 - 1
Terminal.Gui/Configuration/ColorSchemeJsonConverter.cs

@@ -59,7 +59,7 @@ internal class ColorSchemeJsonConverter : JsonConverter<ColorScheme>
 
             string propertyName = reader.GetString ();
             reader.Read ();
-            var attribute = JsonSerializer.Deserialize<Attribute> (ref reader, options);
+            var attribute = JsonSerializer.Deserialize (ref reader, _serializerContext.Attribute);
 
             switch (propertyName.ToLower ())
             {

+ 22 - 4
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -106,9 +106,12 @@ public static class ConfigurationManager
         },
 
         // 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 = "<Pending>")]
     internal static StringBuilder _jsonErrors = new ();
 
@@ -150,6 +153,8 @@ public static class ConfigurationManager
     /// </summary>
     public static SettingsScope? Settings
     {
+        [RequiresUnreferencedCode ("AOT")]
+        [RequiresDynamicCode ("AOT")]
         get
         {
             if (_settings is null)
@@ -181,6 +186,8 @@ public static class ConfigurationManager
     public static event EventHandler<ConfigurationManagerEventArgs>? Applied;
 
     /// <summary>Applies the configuration settings to the running <see cref="Application"/> instance.</summary>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public static void Apply ()
     {
         var settings = false;
@@ -222,7 +229,7 @@ public static class ConfigurationManager
         var emptyScope = new SettingsScope ();
         emptyScope.Clear ();
 
-        return JsonSerializer.Serialize (emptyScope, _serializerOptions);
+        return JsonSerializer.Serialize (emptyScope, typeof (SettingsScope), _serializerContext);
     }
 
     /// <summary>
@@ -235,6 +242,8 @@ public static class ConfigurationManager
     ///     If <see langword="true"/> the state of <see cref="ConfigurationManager"/> will be reset to the
     ///     defaults.
     /// </param>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public static void Load (bool reset = false)
     {
         Debug.WriteLine ("ConfigurationManager.Load()");
@@ -322,6 +331,8 @@ public static class ConfigurationManager
     ///     <see langword="true"/>.
     /// </summary>
     /// <remarks></remarks>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public static void Reset ()
     {
         Debug.WriteLine (@"ConfigurationManager.Reset()");
@@ -475,6 +486,8 @@ public static class ConfigurationManager
     ///         make sure you copy the Theme definitions from the existing <c>Terminal.Gui.Resources.config.json</c> file.
     ///     </para>
     /// </remarks>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     internal static void GetHardCodedDefaults ()
     {
         if (_allConfigProperties is null)
@@ -496,6 +509,7 @@ public static class ConfigurationManager
     ///     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()).
     /// </summary>
+    [RequiresUnreferencedCode ("AOT")]
     internal static void Initialize ()
     {
         _allConfigProperties = new ();
@@ -585,16 +599,20 @@ public static class ConfigurationManager
 
     /// <summary>Creates a JSON document with the configuration specified.</summary>
     /// <returns></returns>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     internal static string ToJson ()
     {
         //Debug.WriteLine ("ConfigurationManager.ToJson()");
 
-        return JsonSerializer.Serialize (Settings!, _serializerOptions);
+        return JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext);
     }
 
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     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 ();

+ 3 - 3
Terminal.Gui/Configuration/DictionaryJsonConverter.cs

@@ -28,8 +28,8 @@ internal class DictionaryJsonConverter<T> : JsonConverter<Dictionary<string, T>>
                 {
                     string key = reader.GetString ();
                     reader.Read ();
-                    var value = JsonSerializer.Deserialize<T> (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 @@ internal class DictionaryJsonConverter<T> : JsonConverter<Dictionary<string, T>>
 
             //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 ();
         }
 

+ 1 - 1
Terminal.Gui/Configuration/KeyCodeJsonConverter.cs

@@ -42,7 +42,7 @@ internal class KeyCodeJsonConverter : JsonConverter<KeyCode>
                                 }
 
                                 // 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;
                                 }

+ 13 - 5
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 <see cref="ConfigurationManager"/> JSON documents.
 /// </summary>
 /// <typeparam name="scopeT"></typeparam>
-internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT : Scope<scopeT>
+internal class ScopeJsonConverter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] scopeT> : JsonConverter<scopeT> where scopeT : Scope<scopeT>
 {
+    [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)
         {
@@ -85,7 +89,7 @@ internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT :
                     try
                     {
                         scope! [propertyName].PropertyValue =
-                            JsonSerializer.Deserialize (ref reader, propertyType!, options);
+                            JsonSerializer.Deserialize (ref reader, propertyType!, _serializerContext);
                     }
                     catch (Exception ex)
                     {
@@ -133,7 +137,7 @@ internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT :
                 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 +164,8 @@ internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT :
         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<string, ConfigProperty> p in from p in scope
@@ -205,7 +210,8 @@ internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT :
             }
             else
             {
-                JsonSerializer.Serialize (writer, p.Value.PropertyValue, options);
+                object? prop = p.Value.PropertyValue;
+                JsonSerializer.Serialize (writer, prop, prop!.GetType (), _serializerContext);
             }
         }
 
@@ -221,6 +227,8 @@ internal class ScopeJsonConverter<scopeT> : JsonConverter<scopeT> where scopeT :
     internal class ReadHelper<converterT> : 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)

+ 10 - 1
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,12 +38,14 @@ public class SettingsScope : Scope<SettingsScope>
     /// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON string.</summary>
     /// <param name="stream">Json document to update the settings with.</param>
     /// <param name="source">The source (filename/resource name) the Json document was read from.</param>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public SettingsScope? Update (Stream stream, string source)
     {
         // Update the existing settings with the new settings.
         try
         {
-            Update (JsonSerializer.Deserialize<SettingsScope> (stream, _serializerOptions)!);
+            Update ((SettingsScope)JsonSerializer.Deserialize (stream, typeof (SettingsScope), _serializerOptions)!);
             OnUpdated ();
             Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\"");
             if (!Sources.Contains (source))
@@ -67,6 +70,8 @@ public class SettingsScope : Scope<SettingsScope>
 
     /// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON file.</summary>
     /// <param name="filePath"></param>
+    [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<SettingsScope>
     /// <summary>Updates the <see cref="SettingsScope"/> with the settings in a JSON string.</summary>
     /// <param name="json">Json document to update the settings with.</param>
     /// <param name="source">The source (filename/resource name) the Json document was read from.</param>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public SettingsScope? Update (string json, string source)
     {
         var stream = new MemoryStream ();
@@ -107,6 +114,8 @@ public class SettingsScope : Scope<SettingsScope>
     /// <summary>Updates the <see cref="SettingsScope"/> with the settings from a Json resource.</summary>
     /// <param name="assembly"></param>
     /// <param name="resourceName"></param>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
     public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName)
     {
         if (resourceName is null || string.IsNullOrEmpty (resourceName))

+ 23 - 0
Terminal.Gui/Configuration/SourceGenerationContext.cs

@@ -0,0 +1,23 @@
+using System.Text.Json.Serialization;
+
+namespace Terminal.Gui;
+
+/// <summary>
+///     Allow AOT and self-contained single file applications with the <see cref="System.Text.Json.Serialization"/>
+/// </summary>
+[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<ColorName, string>))]
+internal partial class SourceGenerationContext : JsonSerializerContext
+{ }

+ 113 - 0
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 @@ public class ThemeManager : IDictionary<string, ThemeScope>
     public string Theme
     {
         get => SelectedTheme;
+
+        [RequiresUnreferencedCode ("AOT")]
+        [RequiresDynamicCode ("AOT")]
         set => SelectedTheme = value;
     }
 
@@ -73,9 +77,14 @@ public class ThemeManager : IDictionary<string, ThemeScope>
     [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
     public static Dictionary<string, ThemeScope>? Themes
     {
+        [RequiresUnreferencedCode ("AOT")]
+        [RequiresDynamicCode ("AOT")]
         get => Settings? ["Themes"]
                        ?.PropertyValue as
                    Dictionary<string, ThemeScope>; // themes ?? new Dictionary<string, ThemeScope> ();
+
+        [RequiresUnreferencedCode ("AOT")]
+        [RequiresDynamicCode ("AOT")]
         set =>
 
             //if (themes is null || value is null) {
@@ -93,6 +102,9 @@ public class ThemeManager : IDictionary<string, ThemeScope>
     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 @@ public class ThemeManager : IDictionary<string, ThemeScope>
     /// <summary>Event fired he selected theme has changed. application.</summary>
     public event EventHandler<ThemeManagerEventArgs>? 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 @@ public class ThemeManager : IDictionary<string, ThemeScope>
         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 @@ public class ThemeManager : IDictionary<string, ThemeScope>
     #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 = "<Pending>")]
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     public ICollection<string> Keys => ((IDictionary<string, ThemeScope>)Themes!).Keys;
+
+    [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     public ICollection<ThemeScope> Values => ((IDictionary<string, ThemeScope>)Themes!).Values;
+
+    [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     public int Count => ((ICollection<KeyValuePair<string, ThemeScope>>)Themes!).Count;
+
+    [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     public bool IsReadOnly => ((ICollection<KeyValuePair<string, ThemeScope>>)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<string, ThemeScope>)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<string, ThemeScope>)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<string, ThemeScope>)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<string, ThemeScope>)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<string, ThemeScope>)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<string, ThemeScope>)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<string, ThemeScope> item) { ((ICollection<KeyValuePair<string, ThemeScope>>)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<KeyValuePair<string, ThemeScope>>)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<string, ThemeScope> item) { return ((ICollection<KeyValuePair<string, ThemeScope>>)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<string, ThemeScope> [] 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<KeyValuePair<string, ThemeScope>>)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<string, ThemeScope> item) { return ((ICollection<KeyValuePair<string, ThemeScope>>)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<KeyValuePair<string, ThemeScope>> GetEnumerator () { return ((IEnumerable<KeyValuePair<string, ThemeScope>>)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

+ 2 - 0
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 @@ internal class UnmanagedLibrary
         }
     }
 
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     static UnmanagedLibrary ()
     {
         PlatformID platform = Environment.OSVersion.Platform;

+ 3 - 0
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 @@ internal class NetEvents : IDisposable
         HandleKeyboardEvent (newConsoleKeyInfo);
     }
 
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     private MouseButtonState MapMouseFlags (MouseFlags mouseFlags)
     {
         MouseButtonState mbs = default;
@@ -1249,6 +1251,7 @@ internal class NetDriver : ConsoleDriver
     #region Color Handling
 
     // Cache the list of ConsoleColor values.
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     private static readonly HashSet<int> ConsoleColorValues = new (
                                                                    Enum.GetValues (typeof (ConsoleColor))
                                                                        .OfType<ConsoleColor> ()

+ 3 - 3
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -116,7 +116,7 @@ internal class WindowsConsole
 
             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 @@ internal class WindowsConsole
 
     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 @@ internal class WindowsConsole
         string lpbufer,
         uint NumberOfCharsToWriten,
         out uint lpNumberOfCharsWritten,
-        object lpReserved
+        nint lpReserved
     );
 
     [DllImport ("kernel32.dll")]

+ 3 - 1
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 class FileDialogStyle
     /// </summary>
     public string WrongFileTypeFeedback { get; set; } = Strings.fdWrongFileTypeFeedback;
 
+    [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
     private Dictionary<IDirectoryInfo, string> DefaultTreeRootGetter ()
     {
         Dictionary<IDirectoryInfo, string> roots = new ();

+ 5 - 7
Terminal.Gui/Terminal.Gui.csproj

@@ -25,10 +25,13 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <DefineTrace>true</DefineTrace>
     <DebugType>portable</DebugType>
-    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
+    <DefineConstants>$(DefineConstants);CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
     <ImplicitUsings>enable</ImplicitUsings>
     <NoLogo>true</NoLogo>
     <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
+    <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
+    <IsTrimmable>true</IsTrimmable>
+    <IsAotCompatible>true</IsAotCompatible>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
     <DefineDebug>true</DefineDebug>
@@ -50,7 +53,7 @@
   <!-- =================================================================== -->
   <ItemGroup>
     <PackageReference Include="ColorHelper" Version="[1.8.1,2)" />
-    <PackageReference Include="JetBrains.Annotations" Version="[2024,)" PrivateAssets="all" />
+    <PackageReference Include="JetBrains.Annotations" Version="[2024.2.0,)" PrivateAssets="all" />
     <PackageReference Include="Microsoft.CodeAnalysis" Version="[4.10,5)" PrivateAssets="all" />
     <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="[4.10,5)" PrivateAssets="all" />
     <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="[4.10,5)" PrivateAssets="all" />
@@ -59,11 +62,6 @@
     <PackageReference Include="System.IO.Abstractions" Version="[21.0.22,22)" />
     <PackageReference Include="System.Text.Json" Version="[8.0.4,9)" />
     <PackageReference Include="Wcwidth" Version="[2,3)" />
-    <ProjectReference Include="..\Analyzers\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
-      <PrivateAssets>all</PrivateAssets>
-      <OutputItemType>Analyzer</OutputItemType>
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
-    </ProjectReference>
   </ItemGroup>
   <!-- =================================================================== -->
   <!-- Global Usings and Type Aliases -->

+ 1 - 1
Terminal.Gui/Views/Button.cs

@@ -39,7 +39,7 @@ public class Button : View, IDesignable
     /// Gets or sets whether <see cref="Button"/>s are shown with a shadow effect by default.
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<ShadowStyle>))]
 
     public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
 

+ 4 - 4
Terminal.Gui/Views/Dialog.cs

@@ -19,13 +19,13 @@ public class Dialog : Window
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <remarks>This property can be set in a Theme.</remarks>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<Alignment>))]
     public static Alignment DefaultButtonAlignment { get; set; } = Alignment.End;
 
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <remarks>This property can be set in a Theme.</remarks>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<AlignmentModes>))]
     public static AlignmentModes DefaultButtonAlignmentModes { get; set; } = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems;
 
     /// <summary>
@@ -47,7 +47,7 @@ public class Dialog : Window
     /// Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<ShadowStyle>))]
     public new static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
 
     /// <summary>
@@ -56,7 +56,7 @@ public class Dialog : Window
     /// </summary>
 
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<LineStyle>))]
     public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
 
     private readonly List<Button> _buttons = new ();

+ 1 - 1
Terminal.Gui/Views/FrameView.cs

@@ -36,6 +36,6 @@ public class FrameView : View
     ///     <see cref="FrameView"/>s.
     /// </remarks>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<LineStyle>))]
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
 }

+ 1 - 1
Terminal.Gui/Views/MessageBox.cs

@@ -31,7 +31,7 @@ public static class MessageBox
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<LineStyle>))]
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
 
     /// <summary>

+ 1 - 1
Terminal.Gui/Views/Window.cs

@@ -73,6 +73,6 @@ public class Window : Toplevel
     ///     s.
     /// </remarks>
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
-    [JsonConverter (typeof (JsonStringEnumConverter))]
+    [JsonConverter (typeof (JsonStringEnumConverter<LineStyle>))]
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
 }

+ 6 - 0
Terminal.sln

@@ -43,6 +43,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C7A51224-5
 		README.md = README.md
 	EndProjectSection
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelfContained", "SelfContained\SelfContained.csproj", "{524DEA78-7E7C-474D-B42D-52ED4C04FF14}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -73,6 +75,10 @@ Global
 		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.Build.0 = Release|Any CPU
+		{524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 1 - 0
UICatalog/UICatalog.csproj

@@ -29,6 +29,7 @@
   <None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
   <ItemGroup>
+    <PackageReference Include="JetBrains.Annotations" Version="[2024.2.0,)" PrivateAssets="all" />
     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="[1.21,2)" />
     <PackageReference Include="SixLabors.ImageSharp" Version="[3.1.4,4)" />
     <PackageReference Include="CsvHelper" Version="[33.0.1,34)" />

+ 1 - 0
UnitTests/UnitTests.csproj

@@ -29,6 +29,7 @@
     <Optimize>true</Optimize>
   </PropertyGroup>
   <ItemGroup>
+    <PackageReference Include="JetBrains.Annotations" Version="[2024.2.0,)" PrivateAssets="all" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="[17.10,18)" />
     <PackageReference Include="ReportGenerator" Version="[5.3.7,6)" />
     <PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="[21.0.22,22)" />