浏览代码

Merge pull request #3591 from gui-cs/v2_develop

Updates `v2` to match `v2_develop`
Tig 1 年之前
父节点
当前提交
41fa134860
共有 100 个文件被更改,包括 10221 次插入2004 次删除
  1. 25 0
      .dockerignore
  2. 1877 14
      .editorconfig
  3. 37 0
      .filenesting.json
  4. 42 39
      .github/workflows/api-docs.yml
  5. 30 25
      .github/workflows/dotnet-core.yml
  6. 42 48
      .github/workflows/publish.yml
  7. 49 15
      .gitignore
  8. 33 0
      .vsconfig
  9. 10 0
      Analyzers.slnf
  10. 23 0
      Analyzers/Directory.Build.props
  11. 23 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Program.cs
  12. 25 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj
  13. 42 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/EnumMemberValues.cs
  14. 51 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum.cs
  15. 51 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt.cs
  16. 52 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt_NoFastIsDefined.cs
  17. 51 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt.cs
  18. 51 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt_NoFastIsDefined.cs
  19. 51 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_NoFastIsDefined.cs
  20. 52 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum.cs
  21. 53 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitInt.cs
  22. 52 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitUInt.cs
  23. 48 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum.cs
  24. 50 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitInt.cs
  25. 48 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitUint.cs
  26. 45 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum.cs
  27. 45 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitInt.cs
  28. 45 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitUInt.cs
  29. 306 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGeneratorTests.cs
  30. 3 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/GlobalSuppressions.cs
  31. 111 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/IndentedTextWriterExtensionsTests.cs
  32. 48 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj
  33. 3 0
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj.DotSettings
  34. 20 0
      Analyzers/Terminal.Gui.Analyzers.Internal/AccessibilityExtensions.cs
  35. 8 0
      Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Shipped.md
  36. 4 0
      Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Unshipped.md
  37. 117 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Analyzers/GenerateEnumExtensionMethodsAttributeAnalyzer.cs
  38. 3 0
      Analyzers/Terminal.Gui.Analyzers.Internal/ApiCompatExcludedAttributes.txt
  39. 27 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs
  40. 37 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/ExtensionsForEnumTypeAttribute.cs
  41. 110 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumExtensionMethodsAttribute.cs
  42. 14 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/IExtensionsForEnumTypeAttribute.cs
  43. 11 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IEqualityOperators.cs
  44. 6 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IntrinsicAttribute.cs
  45. 43 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NumericExtensions.cs
  46. 204 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs
  47. 235 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs
  48. 443 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs
  49. 452 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs
  50. 3 0
      Analyzers/Terminal.Gui.Analyzers.Internal/GlobalSuppressions.cs
  51. 38 0
      Analyzers/Terminal.Gui.Analyzers.Internal/IGeneratedTypeMetadata.cs
  52. 28 0
      Analyzers/Terminal.Gui.Analyzers.Internal/IStandardCSharpCodeGenerator.cs
  53. 71 0
      Analyzers/Terminal.Gui.Analyzers.Internal/IndentedTextWriterExtensions.cs
  54. 8 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Properties/launchSettings.json
  55. 63 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj
  56. 4 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj.DotSettings
  57. 19 13
      CONTRIBUTING.md
  58. 19 0
      CommunityToolkitExample/CommunityToolkitExample.csproj
  59. 8 0
      CommunityToolkitExample/LoginActions.cs
  60. 62 0
      CommunityToolkitExample/LoginView.Designer.cs
  61. 72 0
      CommunityToolkitExample/LoginView.cs
  62. 128 0
      CommunityToolkitExample/LoginViewModel.cs
  63. 6 0
      CommunityToolkitExample/Message.cs
  64. 26 0
      CommunityToolkitExample/Program.cs
  65. 154 0
      CommunityToolkitExample/README.md
  66. 6 0
      Directory.Build.props
  67. 5 0
      Directory.Build.targets
  68. 69 59
      Example/Example.cs
  69. 1 1
      Example/Example.csproj
  70. 74 33
      GitVersion.yml
  71. 12 0
      NoSamples.slnf
  72. 11 130
      README.md
  73. 200 180
      ReactiveExample/LoginView.cs
  74. 81 70
      ReactiveExample/LoginViewModel.cs
  75. 14 11
      ReactiveExample/Program.cs
  76. 1 1
      ReactiveExample/README.md
  77. 4 4
      ReactiveExample/ReactiveExample.csproj
  78. 55 36
      ReactiveExample/TerminalScheduler.cs
  79. 11 0
      Release.slnf
  80. 16 0
      Scripts/COPYRIGHT
  81. 46 0
      Scripts/README.md
  82. 117 0
      Scripts/Terminal.Gui.PowerShell.Analyzers.psd1
  83. 96 0
      Scripts/Terminal.Gui.PowerShell.Analyzers.psm1
  84. 131 0
      Scripts/Terminal.Gui.PowerShell.Build.psd1
  85. 32 0
      Scripts/Terminal.Gui.PowerShell.Build.psm1
  86. 138 0
      Scripts/Terminal.Gui.PowerShell.Core.psd1
  87. 151 0
      Scripts/Terminal.Gui.PowerShell.Core.psm1
  88. 135 0
      Scripts/Terminal.Gui.PowerShell.Git.psd1
  89. 111 0
      Scripts/Terminal.Gui.PowerShell.Git.psm1
  90. 150 0
      Scripts/Terminal.Gui.PowerShell.psd1
  91. 0 1325
      Terminal.Gui/Application.cs
  92. 1500 0
      Terminal.Gui/Application/Application.cs
  93. 303 0
      Terminal.Gui/Application/ApplicationKeyboard.cs
  94. 302 0
      Terminal.Gui/Application/ApplicationMouse.cs
  95. 5 0
      Terminal.Gui/Application/IterationEventArgs.cs
  96. 392 0
      Terminal.Gui/Application/MainLoop.cs
  97. 48 0
      Terminal.Gui/Application/MainLoopSyncContext.cs
  98. 57 0
      Terminal.Gui/Application/RunState.cs
  99. 12 0
      Terminal.Gui/Application/RunStateEventArgs.cs
  100. 18 0
      Terminal.Gui/Application/Timeout.cs

+ 25 - 0
.dockerignore

@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md

+ 1877 - 14
.editorconfig

@@ -1,23 +1,1886 @@
 [*.cs]
-indent_style = tab
-indent_size = 8
-tab_width = 8
-csharp_new_line_before_open_brace = methods,local_functions
-csharp_new_line_before_else = false
-csharp_new_line_before_catch = false
-csharp_new_line_before_finally = false
-end_of_line = crlf
-
 csharp_indent_case_contents = true
-csharp_indent_switch_labels = false
 csharp_indent_labels = flush_left
 csharp_space_after_keywords_in_control_flow_statements = true
 csharp_space_between_method_declaration_parameter_list_parentheses = false
 csharp_space_between_method_call_parameter_list_parentheses = false
 csharp_preserve_single_line_blocks = true
-dotnet_style_require_accessibility_modifiers = never
-csharp_style_var_when_type_is_apparent = true
-csharp_prefer_braces = false
-csharp_space_before_open_square_brackets = true
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
+csharp_prefer_braces = true:warning
 csharp_space_between_method_call_name_and_opening_parenthesis = true
 csharp_space_between_method_declaration_name_and_open_parenthesis = true
+
+# Microsoft .NET properties
+csharp_indent_braces = false
+csharp_indent_switch_labels = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = false
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:warning
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+dotnet_diagnostic.bc40000.severity = warning
+dotnet_diagnostic.bc400005.severity = warning
+dotnet_diagnostic.bc40008.severity = warning
+dotnet_diagnostic.bc40056.severity = warning
+dotnet_diagnostic.bc42016.severity = warning
+dotnet_diagnostic.bc42024.severity = warning
+dotnet_diagnostic.bc42025.severity = warning
+dotnet_diagnostic.bc42104.severity = warning
+dotnet_diagnostic.bc42105.severity = warning
+dotnet_diagnostic.bc42106.severity = warning
+dotnet_diagnostic.bc42107.severity = warning
+dotnet_diagnostic.bc42304.severity = warning
+dotnet_diagnostic.bc42309.severity = warning
+dotnet_diagnostic.bc42322.severity = warning
+dotnet_diagnostic.bc42349.severity = warning
+dotnet_diagnostic.bc42353.severity = warning
+dotnet_diagnostic.bc42354.severity = warning
+dotnet_diagnostic.bc42355.severity = warning
+dotnet_diagnostic.bc42356.severity = warning
+dotnet_diagnostic.bc42358.severity = warning
+dotnet_diagnostic.bc42504.severity = warning
+dotnet_diagnostic.bc42505.severity = warning
+dotnet_diagnostic.ca2252.severity = error
+dotnet_diagnostic.cs0067.severity = warning
+dotnet_diagnostic.cs0078.severity = warning
+dotnet_diagnostic.cs0108.severity = warning
+dotnet_diagnostic.cs0109.severity = warning
+dotnet_diagnostic.cs0114.severity = warning
+dotnet_diagnostic.cs0162.severity = warning
+dotnet_diagnostic.cs0164.severity = warning
+dotnet_diagnostic.cs0168.severity = warning
+dotnet_diagnostic.cs0169.severity = warning
+dotnet_diagnostic.cs0183.severity = warning
+dotnet_diagnostic.cs0184.severity = warning
+dotnet_diagnostic.cs0197.severity = warning
+dotnet_diagnostic.cs0219.severity = warning
+dotnet_diagnostic.cs0252.severity = warning
+dotnet_diagnostic.cs0253.severity = warning
+dotnet_diagnostic.cs0282.severity = warning
+dotnet_diagnostic.cs0414.severity = warning
+dotnet_diagnostic.cs0420.severity = warning
+dotnet_diagnostic.cs0458.severity = warning
+dotnet_diagnostic.cs0464.severity = warning
+dotnet_diagnostic.cs0465.severity = warning
+dotnet_diagnostic.cs0469.severity = warning
+dotnet_diagnostic.cs0472.severity = warning
+dotnet_diagnostic.cs0612.severity = warning
+dotnet_diagnostic.cs0618.severity = warning
+dotnet_diagnostic.cs0628.severity = warning
+dotnet_diagnostic.cs0642.severity = warning
+dotnet_diagnostic.cs0649.severity = warning
+dotnet_diagnostic.cs0652.severity = warning
+dotnet_diagnostic.cs0657.severity = warning
+dotnet_diagnostic.cs0658.severity = warning
+dotnet_diagnostic.cs0659.severity = warning
+dotnet_diagnostic.cs0660.severity = warning
+dotnet_diagnostic.cs0661.severity = warning
+dotnet_diagnostic.cs0665.severity = warning
+dotnet_diagnostic.cs0672.severity = warning
+dotnet_diagnostic.cs0675.severity = warning
+dotnet_diagnostic.cs0693.severity = warning
+dotnet_diagnostic.cs0728.severity = warning
+dotnet_diagnostic.cs1030.severity = warning
+dotnet_diagnostic.cs1058.severity = warning
+dotnet_diagnostic.cs1066.severity = warning
+dotnet_diagnostic.cs1522.severity = warning
+dotnet_diagnostic.cs1570.severity = warning
+dotnet_diagnostic.cs1571.severity = warning
+dotnet_diagnostic.cs1572.severity = warning
+dotnet_diagnostic.cs1573.severity = warning
+dotnet_diagnostic.cs1574.severity = warning
+dotnet_diagnostic.cs1580.severity = warning
+dotnet_diagnostic.cs1581.severity = warning
+dotnet_diagnostic.cs1584.severity = warning
+dotnet_diagnostic.cs1587.severity = warning
+dotnet_diagnostic.cs1589.severity = warning
+dotnet_diagnostic.cs1590.severity = warning
+dotnet_diagnostic.cs1591.severity = warning
+dotnet_diagnostic.cs1592.severity = warning
+dotnet_diagnostic.cs1710.severity = warning
+dotnet_diagnostic.cs1711.severity = warning
+dotnet_diagnostic.cs1712.severity = warning
+dotnet_diagnostic.cs1717.severity = warning
+dotnet_diagnostic.cs1723.severity = warning
+dotnet_diagnostic.cs1911.severity = warning
+dotnet_diagnostic.cs1957.severity = warning
+dotnet_diagnostic.cs1981.severity = warning
+dotnet_diagnostic.cs1998.severity = warning
+dotnet_diagnostic.cs4014.severity = warning
+dotnet_diagnostic.cs7022.severity = warning
+dotnet_diagnostic.cs7023.severity = warning
+dotnet_diagnostic.cs7095.severity = warning
+dotnet_diagnostic.cs8073.severity = warning
+dotnet_diagnostic.cs8094.severity = warning
+dotnet_diagnostic.cs8123.severity = warning
+dotnet_diagnostic.cs8321.severity = warning
+dotnet_diagnostic.cs8383.severity = warning
+dotnet_diagnostic.cs8424.severity = warning
+dotnet_diagnostic.cs8425.severity = warning
+dotnet_diagnostic.cs8500.severity = warning
+dotnet_diagnostic.cs8509.severity = warning
+dotnet_diagnostic.cs8519.severity = warning
+dotnet_diagnostic.cs8520.severity = warning
+dotnet_diagnostic.cs8524.severity = warning
+dotnet_diagnostic.cs8597.severity = warning
+dotnet_diagnostic.cs8600.severity = warning
+dotnet_diagnostic.cs8601.severity = warning
+dotnet_diagnostic.cs8602.severity = warning
+dotnet_diagnostic.cs8603.severity = warning
+dotnet_diagnostic.cs8604.severity = warning
+dotnet_diagnostic.cs8605.severity = warning
+dotnet_diagnostic.cs8607.severity = warning
+dotnet_diagnostic.cs8608.severity = warning
+dotnet_diagnostic.cs8609.severity = warning
+dotnet_diagnostic.cs8610.severity = warning
+dotnet_diagnostic.cs8611.severity = warning
+dotnet_diagnostic.cs8612.severity = warning
+dotnet_diagnostic.cs8613.severity = warning
+dotnet_diagnostic.cs8614.severity = warning
+dotnet_diagnostic.cs8615.severity = warning
+dotnet_diagnostic.cs8616.severity = warning
+dotnet_diagnostic.cs8617.severity = warning
+dotnet_diagnostic.cs8618.severity = warning
+dotnet_diagnostic.cs8619.severity = warning
+dotnet_diagnostic.cs8620.severity = warning
+dotnet_diagnostic.cs8621.severity = warning
+dotnet_diagnostic.cs8622.severity = warning
+dotnet_diagnostic.cs8624.severity = warning
+dotnet_diagnostic.cs8625.severity = warning
+dotnet_diagnostic.cs8629.severity = warning
+dotnet_diagnostic.cs8631.severity = warning
+dotnet_diagnostic.cs8632.severity = warning
+dotnet_diagnostic.cs8633.severity = warning
+dotnet_diagnostic.cs8634.severity = warning
+dotnet_diagnostic.cs8643.severity = warning
+dotnet_diagnostic.cs8644.severity = warning
+dotnet_diagnostic.cs8645.severity = warning
+dotnet_diagnostic.cs8655.severity = warning
+dotnet_diagnostic.cs8656.severity = warning
+dotnet_diagnostic.cs8667.severity = warning
+dotnet_diagnostic.cs8669.severity = warning
+dotnet_diagnostic.cs8670.severity = warning
+dotnet_diagnostic.cs8714.severity = warning
+dotnet_diagnostic.cs8762.severity = warning
+dotnet_diagnostic.cs8763.severity = warning
+dotnet_diagnostic.cs8764.severity = warning
+dotnet_diagnostic.cs8765.severity = warning
+dotnet_diagnostic.cs8766.severity = warning
+dotnet_diagnostic.cs8767.severity = warning
+dotnet_diagnostic.cs8768.severity = warning
+dotnet_diagnostic.cs8769.severity = warning
+dotnet_diagnostic.cs8770.severity = warning
+dotnet_diagnostic.cs8774.severity = warning
+dotnet_diagnostic.cs8775.severity = warning
+dotnet_diagnostic.cs8776.severity = warning
+dotnet_diagnostic.cs8777.severity = warning
+dotnet_diagnostic.cs8794.severity = warning
+dotnet_diagnostic.cs8819.severity = warning
+dotnet_diagnostic.cs8824.severity = warning
+dotnet_diagnostic.cs8825.severity = warning
+dotnet_diagnostic.cs8846.severity = warning
+dotnet_diagnostic.cs8847.severity = warning
+dotnet_diagnostic.cs8851.severity = warning
+dotnet_diagnostic.cs8860.severity = warning
+dotnet_diagnostic.cs8892.severity = warning
+dotnet_diagnostic.cs8907.severity = warning
+dotnet_diagnostic.cs8947.severity = warning
+dotnet_diagnostic.cs8960.severity = warning
+dotnet_diagnostic.cs8961.severity = warning
+dotnet_diagnostic.cs8962.severity = warning
+dotnet_diagnostic.cs8963.severity = warning
+dotnet_diagnostic.cs8965.severity = warning
+dotnet_diagnostic.cs8966.severity = warning
+dotnet_diagnostic.cs8971.severity = warning
+dotnet_diagnostic.cs8974.severity = warning
+dotnet_diagnostic.cs8981.severity = warning
+dotnet_diagnostic.cs9042.severity = warning
+dotnet_diagnostic.cs9073.severity = warning
+dotnet_diagnostic.cs9074.severity = warning
+dotnet_diagnostic.cs9080.severity = warning
+dotnet_diagnostic.cs9081.severity = warning
+dotnet_diagnostic.cs9082.severity = warning
+dotnet_diagnostic.cs9083.severity = warning
+dotnet_diagnostic.cs9084.severity = warning
+dotnet_diagnostic.cs9085.severity = warning
+dotnet_diagnostic.cs9086.severity = warning
+dotnet_diagnostic.cs9087.severity = warning
+dotnet_diagnostic.cs9088.severity = warning
+dotnet_diagnostic.cs9089.severity = warning
+dotnet_diagnostic.cs9090.severity = warning
+dotnet_diagnostic.cs9091.severity = warning
+dotnet_diagnostic.cs9092.severity = warning
+dotnet_diagnostic.cs9093.severity = warning
+dotnet_diagnostic.cs9094.severity = warning
+dotnet_diagnostic.cs9095.severity = warning
+dotnet_diagnostic.cs9097.severity = warning
+dotnet_diagnostic.cs9099.severity = warning
+dotnet_diagnostic.cs9100.severity = warning
+dotnet_diagnostic.cs9107.severity = warning
+dotnet_diagnostic.cs9113.severity = warning
+dotnet_diagnostic.cs9124.severity = warning
+dotnet_diagnostic.cs9154.severity = warning
+dotnet_diagnostic.cs9158.severity = warning
+dotnet_diagnostic.cs9159.severity = warning
+dotnet_diagnostic.cs9179.severity = warning
+dotnet_diagnostic.cs9181.severity = warning
+dotnet_diagnostic.cs9182.severity = warning
+dotnet_diagnostic.cs9183.severity = warning
+dotnet_diagnostic.cs9184.severity = warning
+dotnet_diagnostic.cs9191.severity = warning
+dotnet_diagnostic.cs9192.severity = warning
+dotnet_diagnostic.cs9193.severity = warning
+dotnet_diagnostic.cs9195.severity = warning
+dotnet_diagnostic.cs9196.severity = warning
+dotnet_diagnostic.cs9200.severity = warning
+dotnet_diagnostic.cs9208.severity = warning
+dotnet_diagnostic.cs9209.severity = warning
+dotnet_diagnostic.wme006.severity = warning
+dotnet_naming_rule.constants_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.constants_rule.severity = warning
+dotnet_naming_rule.constants_rule.style = upper_camel_case_style
+dotnet_naming_rule.constants_rule.symbols = constants_symbols
+dotnet_naming_rule.event_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.event_rule.severity = warning
+dotnet_naming_rule.event_rule.style = upper_camel_case_style
+dotnet_naming_rule.event_rule.symbols = event_symbols
+dotnet_naming_rule.interfaces_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.interfaces_rule.severity = warning
+dotnet_naming_rule.interfaces_rule.style = i_upper_camel_case_style
+dotnet_naming_rule.interfaces_rule.symbols = interfaces_symbols
+dotnet_naming_rule.locals_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.locals_rule.severity = warning
+dotnet_naming_rule.locals_rule.style = lower_camel_case_style_1
+dotnet_naming_rule.locals_rule.symbols = locals_symbols
+dotnet_naming_rule.local_constants_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.local_constants_rule.severity = warning
+dotnet_naming_rule.local_constants_rule.style = lower_camel_case_style_1
+dotnet_naming_rule.local_constants_rule.symbols = local_constants_symbols
+dotnet_naming_rule.local_functions_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.local_functions_rule.severity = warning
+dotnet_naming_rule.local_functions_rule.style = upper_camel_case_style
+dotnet_naming_rule.local_functions_rule.symbols = local_functions_symbols
+dotnet_naming_rule.method_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.method_rule.severity = warning
+dotnet_naming_rule.method_rule.style = upper_camel_case_style
+dotnet_naming_rule.method_rule.symbols = method_symbols
+dotnet_naming_rule.parameters_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.parameters_rule.severity = warning
+dotnet_naming_rule.parameters_rule.style = lower_camel_case_style_1
+dotnet_naming_rule.parameters_rule.symbols = parameters_symbols
+dotnet_naming_rule.private_constants_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.private_constants_rule.severity = warning
+dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style
+dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
+dotnet_naming_rule.private_instance_fields_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.private_instance_fields_rule.severity = warning
+dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
+dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
+dotnet_naming_rule.private_static_fields_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.private_static_fields_rule.severity = warning
+dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
+dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
+dotnet_naming_rule.private_static_readonly_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.private_static_readonly_rule.severity = warning
+dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
+dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
+dotnet_naming_rule.property_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.property_rule.severity = warning
+dotnet_naming_rule.property_rule.style = upper_camel_case_style
+dotnet_naming_rule.property_rule.symbols = property_symbols
+dotnet_naming_rule.public_fields_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.public_fields_rule.severity = warning
+dotnet_naming_rule.public_fields_rule.style = upper_camel_case_style
+dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols
+dotnet_naming_rule.static_readonly_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.static_readonly_rule.severity = warning
+dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style
+dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols
+dotnet_naming_rule.types_and_namespaces_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.types_and_namespaces_rule.severity = warning
+dotnet_naming_rule.types_and_namespaces_rule.style = upper_camel_case_style
+dotnet_naming_rule.types_and_namespaces_rule.symbols = types_and_namespaces_symbols
+dotnet_naming_rule.type_parameters_rule.import_to_resharper = as_predefined
+dotnet_naming_rule.type_parameters_rule.severity = warning
+dotnet_naming_rule.type_parameters_rule.style = t_upper_camel_case_style
+dotnet_naming_rule.type_parameters_rule.symbols = type_parameters_symbols
+dotnet_naming_style.all_upper_style.capitalization = all_upper
+dotnet_naming_style.all_upper_style.word_separator = _
+dotnet_naming_style.i_upper_camel_case_style.capitalization = pascal_case
+dotnet_naming_style.i_upper_camel_case_style.required_prefix = I
+dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
+dotnet_naming_style.lower_camel_case_style.required_prefix = _
+dotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case
+dotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case
+dotnet_naming_style.t_upper_camel_case_style.required_prefix = T
+dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
+dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.constants_symbols.applicable_kinds = field
+dotnet_naming_symbols.constants_symbols.required_modifiers = const
+dotnet_naming_symbols.event_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.event_symbols.applicable_kinds = event
+dotnet_naming_symbols.interfaces_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.interfaces_symbols.applicable_kinds = interface
+dotnet_naming_symbols.locals_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.locals_symbols.applicable_kinds = local
+dotnet_naming_symbols.local_constants_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.local_constants_symbols.applicable_kinds = local
+dotnet_naming_symbols.local_constants_symbols.required_modifiers = const
+dotnet_naming_symbols.local_functions_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.local_functions_symbols.applicable_kinds = local_function
+dotnet_naming_symbols.method_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.method_symbols.applicable_kinds = method
+dotnet_naming_symbols.parameters_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.parameters_symbols.applicable_kinds = parameter
+dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
+dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
+dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
+dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
+dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
+dotnet_naming_symbols.property_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.property_symbols.applicable_kinds = property
+dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field
+dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
+dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly
+dotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,class,struct,enum,delegate
+dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:suggestion
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:error
+dotnet_style_predefined_type_for_member_access = true:error
+dotnet_style_qualification_for_event = false:warning
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_property = false:warning
+file_header_template = 
+
+# ReSharper properties
+csharp_space_around_binary_operators = before_and_after
+csharp_using_directive_placement = outside_namespace:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_namespace_declarations = file_scoped:error
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_primary_constructors = true:suggestion
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_throw_expression = true:suggestion
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+csharp_prefer_static_local_function = true:suggestion
+csharp_style_prefer_readonly_struct = true:suggestion
+csharp_style_prefer_readonly_struct_member = true:suggestion
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
+csharp_style_conditional_delegate_call = true:suggestion
+csharp_style_prefer_switch_expression = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+csharp_style_var_for_built_in_types = false:suggestion
+resharper_accessor_owner_body = expression_body
+resharper_alignment_tab_fill_style = use_spaces
+resharper_align_first_arg_by_paren = true
+resharper_align_linq_query = true
+resharper_align_multiline_argument = true
+resharper_align_multiline_array_and_object_initializer = false
+resharper_align_multiline_array_initializer = true
+resharper_align_multiline_binary_expressions_chain = true
+resharper_align_multiline_binary_patterns = true
+resharper_align_multiline_calls_chain = true
+resharper_align_multiline_comments = true
+resharper_align_multiline_expression = true
+resharper_align_multiline_extends_list = true
+resharper_align_multiline_for_stmt = false
+resharper_align_multiline_implements_list = true
+resharper_align_multiline_list_pattern = true
+resharper_align_multiline_parameter = true
+resharper_align_multiline_property_pattern = true
+resharper_align_multiline_statement_conditions = true
+resharper_align_multiline_switch_expression = true
+resharper_align_multiple_declaration = true
+resharper_align_multline_type_parameter_constrains = true
+resharper_align_multline_type_parameter_list = true
+resharper_align_tuple_components = true
+resharper_allow_alias = true
+resharper_allow_comment_after_lbrace = true
+resharper_apply_auto_detected_rules = false
+resharper_apply_on_completion = true
+resharper_arguments_anonymous_function = positional
+resharper_arguments_literal = positional
+resharper_arguments_named = positional
+resharper_arguments_other = positional
+resharper_arguments_skip_single = false
+resharper_arguments_string_literal = positional
+resharper_attribute_style = do_not_touch
+resharper_autodetect_indent_settings = false
+resharper_blank_lines_after_block_statements = 1
+resharper_blank_lines_after_case = 0
+resharper_blank_lines_after_control_transfer_statements = 1
+resharper_blank_lines_after_file_scoped_namespace_directive = 1
+resharper_blank_lines_after_imports = 1
+resharper_blank_lines_after_multiline_statements = 0
+resharper_blank_lines_after_options = 1
+resharper_blank_lines_after_start_comment = 1
+resharper_blank_lines_after_using_list = 1
+resharper_blank_lines_around_accessor = 0
+resharper_blank_lines_around_auto_property = 1
+resharper_blank_lines_around_block_case_section = 0
+resharper_blank_lines_around_field = 1
+resharper_blank_lines_around_global_attribute = 0
+resharper_blank_lines_around_invocable = 1
+resharper_blank_lines_around_local_method = 1
+resharper_blank_lines_around_multiline_case_section = 0
+resharper_blank_lines_around_namespace = 1
+resharper_blank_lines_around_property = 1
+resharper_blank_lines_around_region = 1
+resharper_blank_lines_around_single_line_accessor = 0
+resharper_blank_lines_around_single_line_auto_property = 0
+resharper_blank_lines_around_single_line_field = 0
+resharper_blank_lines_around_single_line_invocable = 0
+resharper_blank_lines_around_single_line_local_method = 1
+resharper_blank_lines_around_single_line_property = 0
+resharper_blank_lines_around_single_line_type = 1
+resharper_blank_lines_around_type = 1
+resharper_blank_lines_before_block_statements = 0
+resharper_blank_lines_before_case = 0
+resharper_blank_lines_before_control_transfer_statements = 1
+resharper_blank_lines_before_multiline_statements = 1
+resharper_blank_lines_before_single_line_comment = 1
+resharper_blank_lines_inside_namespace = 0
+resharper_blank_lines_inside_region = 1
+resharper_blank_lines_inside_type = 0
+resharper_blank_line_after_pi = true
+resharper_braces_redundant = true
+resharper_builtin_type_apply_to_native_integer = true
+resharper_can_use_global_alias = true
+resharper_configure_await_analysis_mode = disabled
+resharper_constructor_or_destructor_body = block_body
+resharper_continuous_indent_multiplier = 1
+resharper_csharp_allow_far_alignment = false
+resharper_csharp_insert_final_newline = true
+resharper_csharp_keep_blank_lines_in_code = 1
+resharper_csharp_keep_blank_lines_in_declarations = 1
+resharper_csharp_keep_nontrivial_alias = false
+resharper_csharp_max_line_length = 160
+resharper_csharp_naming_rule.enum_member = AaBb
+resharper_csharp_naming_rule.method_property_event = AaBb
+resharper_csharp_naming_rule.other = AaBb
+resharper_csharp_space_after_unary_operator = false
+resharper_csharp_use_indent_from_vs = false
+resharper_csharp_wrap_arguments_style = chop_if_long
+resharper_csharp_wrap_before_binary_opsign = true
+resharper_csharp_wrap_lines = true
+resharper_csharp_wrap_parameters_style = chop_if_long
+resharper_default_exception_variable_name = e
+resharper_default_value_when_type_evident = default_literal
+resharper_default_value_when_type_not_evident = default_expression
+resharper_disable_blank_line_changes = false
+resharper_disable_formatter = false
+resharper_disable_indenter = false
+resharper_disable_int_align = false
+resharper_disable_line_break_changes = false
+resharper_disable_line_break_removal = false
+resharper_disable_space_changes = false
+resharper_empty_block_style = together
+resharper_enforce_line_ending_style = false
+resharper_event_handler_pattern_long = $object$On$event$
+resharper_event_handler_pattern_short = On$event$
+resharper_existing_test_class_name_suffixes = Test, Fixture
+resharper_extra_spaces = remove_all
+resharper_force_attribute_style = separate
+resharper_force_chop_compound_do_expression = false
+resharper_force_chop_compound_if_expression = false
+resharper_force_chop_compound_while_expression = false
+resharper_formatter_off_tag = 
+resharper_formatter_on_tag = 
+resharper_formatter_tags_accept_regexp = false
+resharper_formatter_tags_enabled = false
+resharper_format_leading_spaces_decl = false
+resharper_for_built_in_types = use_var_when_evident
+resharper_for_other_types = use_explicit_type
+resharper_for_simple_types = use_var_when_evident
+resharper_ignore_space_preservation = false
+resharper_include_prefix_comment_in_indent = false
+resharper_indent_anonymous_method_block = true
+resharper_indent_braces_inside_statement_conditions = true
+resharper_indent_case_from_select = true
+resharper_indent_child_elements = OneIndent
+resharper_indent_inside_namespace = true
+resharper_indent_invocation_pars = inside
+resharper_indent_method_decl_pars = inside
+resharper_indent_nested_fixed_stmt = false
+resharper_indent_nested_foreach_stmt = false
+resharper_indent_nested_for_stmt = false
+resharper_indent_nested_lock_stmt = false
+resharper_indent_nested_usings_stmt = false
+resharper_indent_nested_while_stmt = false
+resharper_indent_pars = inside
+resharper_indent_preprocessor_if = no_indent
+resharper_indent_preprocessor_other = no_indent
+resharper_indent_preprocessor_region = usual_indent
+resharper_indent_primary_constructor_decl_pars = inside
+resharper_indent_raw_literal_string = align
+resharper_indent_statement_pars = inside
+resharper_indent_text = OneIndent
+resharper_indent_typearg_angles = inside
+resharper_indent_typeparam_angles = inside
+resharper_indent_type_constraints = true
+resharper_instance_members_qualify_declared_in = this_class, base_class
+resharper_int_align = false
+resharper_int_align_fix_in_adjacent = true
+resharper_keep_existing_attribute_arrangement = false
+resharper_keep_existing_declaration_block_arrangement = false
+resharper_keep_existing_declaration_parens_arrangement = true
+resharper_keep_existing_embedded_arrangement = true
+resharper_keep_existing_embedded_block_arrangement = false
+resharper_keep_existing_enum_arrangement = false
+resharper_keep_existing_expr_member_arrangement = true
+resharper_keep_existing_invocation_parens_arrangement = true
+resharper_keep_existing_list_patterns_arrangement = true
+resharper_keep_existing_primary_constructor_declaration_parens_arrangement = true
+resharper_keep_existing_property_patterns_arrangement = true
+resharper_keep_existing_switch_expression_arrangement = true
+resharper_keep_user_linebreaks = true
+resharper_keep_user_wrapping = true
+resharper_linebreaks_inside_tags_for_elements_with_child_elements = true
+resharper_linebreaks_inside_tags_for_multiline_elements = true
+resharper_linebreak_before_multiline_elements = true
+resharper_linebreak_before_singleline_elements = false
+resharper_local_function_body = block_body
+resharper_max_array_initializer_elements_on_line = 10000
+resharper_max_attribute_length_for_same_line = 60
+resharper_max_enum_members_on_line = 1
+resharper_max_formal_parameters_on_line = 8
+resharper_max_initializer_elements_on_line = 4
+resharper_max_invocation_arguments_on_line = 8
+resharper_max_primary_constructor_parameters_on_line = 8
+resharper_method_or_operator_body = block_body
+resharper_nested_ternary_style = autodetect
+resharper_new_line_before_while = true
+resharper_new_test_class_name_suffix = Tests
+resharper_null_checking_pattern_style = empty_recursive_pattern
+resharper_object_creation_when_type_evident = target_typed
+resharper_object_creation_when_type_not_evident = explicitly_typed
+resharper_old_engine = false
+resharper_outdent_binary_ops = false
+resharper_outdent_binary_pattern_ops = false
+resharper_outdent_commas = true
+resharper_outdent_dots = false
+resharper_outdent_statement_labels = false
+resharper_outdent_ternary_ops = false
+resharper_parentheses_non_obvious_operations = none, shift, bitwise_and, bitwise_exclusive_or, bitwise_inclusive_or, bitwise
+resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence
+resharper_parentheses_same_type_operations = false
+resharper_pi_attributes_indent = align_by_first_attribute
+resharper_pi_attribute_style = do_not_touch
+resharper_place_accessorholder_attribute_on_same_line = false
+resharper_place_accessor_attribute_on_same_line = false
+resharper_place_comments_at_first_column = false
+resharper_place_constructor_initializer_on_same_line = true
+resharper_place_event_attribute_on_same_line = false
+resharper_place_expr_accessor_on_single_line = if_owner_is_single_line
+resharper_place_expr_method_on_single_line = if_owner_is_single_line
+resharper_place_expr_property_on_single_line = if_owner_is_single_line
+resharper_place_field_attribute_on_same_line = false
+resharper_place_linq_into_on_new_line = true
+resharper_place_method_attribute_on_same_line = false
+resharper_place_property_attribute_on_same_line = false
+resharper_place_record_field_attribute_on_same_line = if_owner_is_single_line
+resharper_place_simple_case_statement_on_same_line = false
+resharper_place_simple_embedded_statement_on_same_line = false
+resharper_place_simple_initializer_on_single_line = true
+resharper_place_simple_list_pattern_on_single_line = true
+resharper_place_simple_property_pattern_on_single_line = true
+resharper_place_simple_switch_expression_on_single_line = false
+resharper_place_type_attribute_on_same_line = false
+resharper_place_type_constraints_on_same_line = true
+resharper_prefer_explicit_discard_declaration = false
+resharper_prefer_qualified_reference = false
+resharper_prefer_separate_deconstructed_variables_declaration = true
+resharper_qualified_using_at_nested_scope = false
+resharper_remove_blank_lines_near_braces_in_code = true
+resharper_remove_blank_lines_near_braces_in_declarations = true
+resharper_remove_only_unused_aliases = true
+resharper_remove_unused_only_aliases = false
+resharper_resx_allow_far_alignment = false
+resharper_resx_attribute_indent = single_indent
+resharper_resx_insert_final_newline = false
+resharper_resx_linebreaks_inside_tags_for_elements_longer_than = 2147483647
+resharper_resx_linebreak_before_elements = 
+resharper_resx_max_blank_lines_between_tags = 0
+resharper_resx_max_line_length = 2147483647
+resharper_resx_space_before_self_closing = false
+resharper_resx_use_indent_from_vs = true
+resharper_resx_wrap_lines = false
+resharper_resx_wrap_tags_and_pi = false
+resharper_resx_wrap_text = false
+resharper_show_autodetect_configure_formatting_tip = true
+resharper_sort_usings = true
+resharper_sort_usings_lowercase_first = false
+resharper_spaces_around_eq_in_attribute = false
+resharper_spaces_around_eq_in_pi_attribute = false
+resharper_spaces_inside_tags = false
+resharper_space_after_attributes = true
+resharper_space_after_attribute_target_colon = true
+resharper_space_after_colon = true
+resharper_space_after_colon_in_case = true
+resharper_space_after_comma = true
+resharper_space_after_last_attribute = false
+resharper_space_after_last_pi_attribute = false
+resharper_space_after_operator_keyword = true
+resharper_space_after_triple_slash = true
+resharper_space_after_type_parameter_constraint_colon = true
+resharper_space_around_additive_op = true
+resharper_space_around_alias_eq = true
+resharper_space_around_assignment_op = true
+resharper_space_around_lambda_arrow = true
+resharper_space_around_member_access_operator = false
+resharper_space_around_relational_op = true
+resharper_space_around_shift_op = true
+resharper_space_around_stmt_colon = true
+resharper_space_around_ternary_operator = true
+resharper_space_before_array_rank_parentheses = false
+resharper_space_before_attribute_target_colon = false
+resharper_space_before_checked_parentheses = true
+resharper_space_before_colon = false
+resharper_space_before_colon_in_case = false
+resharper_space_before_comma = false
+resharper_space_before_default_parentheses = true
+resharper_space_before_empty_invocation_parentheses = false
+resharper_space_before_invocation_parentheses = false
+resharper_space_before_label_colon = false
+resharper_space_before_nameof_parentheses = true
+resharper_space_before_new_parentheses = true
+resharper_space_before_nullable_mark = false
+resharper_space_before_pointer_asterik_declaration = false
+resharper_space_before_semicolon = false
+resharper_space_before_singleline_accessorholder = true
+resharper_space_before_sizeof_parentheses = true
+resharper_space_before_trailing_comment = true
+resharper_space_before_typeof_parentheses = true
+resharper_space_before_type_argument_angle = false
+resharper_space_before_type_parameter_angle = false
+resharper_space_before_type_parameter_constraint_colon = true
+resharper_space_before_type_parameter_parentheses = true
+resharper_space_between_accessors_in_singleline_property = true
+resharper_space_between_attribute_sections = true
+resharper_space_between_keyword_and_expression = true
+resharper_space_between_keyword_and_type = true
+resharper_space_in_singleline_accessorholder = true
+resharper_space_in_singleline_anonymous_method = true
+resharper_space_in_singleline_method = true
+resharper_space_near_postfix_and_prefix_op = false
+resharper_space_within_array_initialization_braces = false
+resharper_space_within_array_rank_empty_parentheses = false
+resharper_space_within_array_rank_parentheses = false
+resharper_space_within_attribute_angles = false
+resharper_space_within_checked_parentheses = false
+resharper_space_within_default_parentheses = false
+resharper_space_within_empty_braces = true
+resharper_space_within_empty_invocation_parentheses = false
+resharper_space_within_empty_method_parentheses = false
+resharper_space_within_expression_parentheses = false
+resharper_space_within_invocation_parentheses = false
+resharper_space_within_method_parentheses = false
+resharper_space_within_nameof_parentheses = false
+resharper_space_within_new_parentheses = false
+resharper_space_within_single_line_array_initializer_braces = true
+resharper_space_within_sizeof_parentheses = false
+resharper_space_within_slice_pattern = true
+resharper_space_within_tuple_parentheses = false
+resharper_space_within_typeof_parentheses = false
+resharper_space_within_type_argument_angles = false
+resharper_space_within_type_parameter_angles = false
+resharper_space_within_type_parameter_parentheses = false
+resharper_special_else_if_treatment = true
+resharper_static_members_qualify_members = none
+resharper_static_members_qualify_with = declared_type
+resharper_stick_comment = true
+resharper_support_vs_event_naming_pattern = true
+resharper_tests_project_name = 
+resharper_tests_project_sub_namespace = 
+resharper_trailing_comma_in_multiline_lists = false
+resharper_trailing_comma_in_singleline_lists = false
+resharper_use_continuous_indent_inside_initializer_braces = true
+resharper_use_continuous_indent_inside_parens = true
+resharper_use_heuristics_for_body_style = true
+resharper_use_indents_from_main_language_in_file = true
+resharper_use_indent_from_previous_element = true
+resharper_use_roslyn_logic_for_evident_types = false
+resharper_vb_allow_far_alignment = false
+resharper_vb_insert_final_newline = false
+resharper_vb_keep_blank_lines_in_code = 2
+resharper_vb_keep_blank_lines_in_declarations = 2
+resharper_vb_keep_nontrivial_alias = true
+resharper_vb_max_line_length = 120
+resharper_vb_place_field_attribute_on_same_line = true
+resharper_vb_place_method_attribute_on_same_line = false
+resharper_vb_place_type_attribute_on_same_line = false
+resharper_vb_space_after_unary_operator = true
+resharper_vb_space_around_multiplicative_op = false
+resharper_vb_space_before_empty_method_parentheses = false
+resharper_vb_space_before_method_parentheses = false
+resharper_vb_use_indent_from_vs = true
+resharper_vb_wrap_arguments_style = wrap_if_long
+resharper_vb_wrap_before_binary_opsign = false
+resharper_vb_wrap_lines = true
+resharper_vb_wrap_parameters_style = wrap_if_long
+resharper_wrap_after_declaration_lpar = true
+resharper_wrap_after_dot_in_method_calls = false
+resharper_wrap_after_invocation_lpar = true
+resharper_wrap_after_primary_constructor_declaration_lpar = true
+resharper_wrap_after_property_in_chained_method_calls = false
+resharper_wrap_around_elements = true
+resharper_wrap_array_initializer_style = wrap_if_long
+resharper_wrap_before_arrow_with_expressions = false
+resharper_wrap_before_binary_pattern_op = true
+resharper_wrap_before_comma = false
+resharper_wrap_before_declaration_lpar = false
+resharper_wrap_before_declaration_rpar = true
+resharper_wrap_before_eq = false
+resharper_wrap_before_extends_colon = false
+resharper_wrap_before_first_method_call = false
+resharper_wrap_before_first_type_parameter_constraint = true
+resharper_wrap_before_invocation_lpar = false
+resharper_wrap_before_invocation_rpar = false
+resharper_wrap_before_linq_expression = false
+resharper_wrap_before_primary_constructor_declaration_lpar = false
+resharper_wrap_before_primary_constructor_declaration_rpar = false
+resharper_wrap_before_ternary_opsigns = true
+resharper_wrap_before_type_parameter_langle = true
+resharper_wrap_chained_binary_expressions = chop_if_long
+resharper_wrap_chained_binary_patterns = chop_if_long
+resharper_wrap_chained_method_calls = chop_if_long
+resharper_wrap_enum_declaration = chop_always
+resharper_wrap_extends_list_style = wrap_if_long
+resharper_wrap_for_stmt_header_style = chop_if_long
+resharper_wrap_list_pattern = chop_if_long
+resharper_wrap_multiple_declaration_style = chop_if_long
+resharper_wrap_multiple_type_parameter_constraints_style = chop_if_long
+resharper_wrap_object_and_collection_initializer_style = chop_if_long
+resharper_wrap_primary_constructor_parameters_style = chop_if_long
+resharper_wrap_property_pattern = chop_if_long
+resharper_wrap_switch_expression = chop_always
+resharper_wrap_ternary_expr_style = chop_if_long
+resharper_wrap_verbatim_interpolated_strings = no_wrap
+resharper_xmldoc_allow_far_alignment = true
+resharper_xmldoc_attribute_indent = align_by_first_attribute
+resharper_xmldoc_insert_final_newline = false
+resharper_xmldoc_linebreaks_inside_tags_for_elements_longer_than = 120
+resharper_xmldoc_linebreak_before_elements = summary,remarks,example,returns,param,typeparam,value,para
+resharper_xmldoc_max_blank_lines_between_tags = 0
+resharper_xmldoc_max_line_length = 120
+resharper_xmldoc_space_before_self_closing = false
+resharper_xmldoc_use_indent_from_vs = false
+resharper_xmldoc_wrap_lines = true
+resharper_xmldoc_wrap_tags_and_pi = true
+resharper_xmldoc_wrap_text = true
+resharper_xml_allow_far_alignment = false
+resharper_xml_attribute_indent = align_by_first_attribute
+resharper_xml_insert_final_newline = false
+resharper_xml_linebreaks_inside_tags_for_elements_longer_than = 2147483647
+resharper_xml_linebreak_before_elements = 
+resharper_xml_max_blank_lines_between_tags = 2
+resharper_xml_max_line_length = 120
+resharper_xml_space_before_self_closing = true
+resharper_xml_use_indent_from_vs = true
+resharper_xml_wrap_lines = true
+resharper_xml_wrap_tags_and_pi = true
+resharper_xml_wrap_text = false
+
+# ReSharper inspection severities
+resharper_access_rights_in_text_highlighting = warning
+resharper_access_to_disposed_closure_highlighting = warning
+resharper_access_to_for_each_variable_in_closure_highlighting = warning
+resharper_access_to_modified_closure_highlighting = warning
+resharper_access_to_static_member_via_derived_type_highlighting = warning
+resharper_address_of_marshal_by_ref_object_highlighting = warning
+resharper_all_underscore_local_parameter_name_highlighting = warning
+resharper_annotate_can_be_null_parameter_highlighting = none
+resharper_annotate_can_be_null_type_member_highlighting = none
+resharper_annotate_not_null_parameter_highlighting = none
+resharper_annotate_not_null_type_member_highlighting = none
+resharper_annotation_conflict_in_hierarchy_highlighting = warning
+resharper_annotation_redundancy_at_value_type_highlighting = warning
+resharper_annotation_redundancy_in_hierarchy_highlighting = warning
+resharper_append_to_collection_expression_highlighting = suggestion
+resharper_arguments_style_anonymous_function_highlighting = none
+resharper_arguments_style_literal_highlighting = none
+resharper_arguments_style_named_expression_highlighting = none
+resharper_arguments_style_other_highlighting = none
+resharper_arguments_style_string_literal_highlighting = none
+resharper_argument_exception_constructor_argument_highlighting = warning
+resharper_arrange_accessor_owner_body_highlighting = suggestion
+resharper_arrange_attributes_highlighting = suggestion
+resharper_arrange_constructor_or_destructor_body_highlighting = error
+resharper_arrange_default_value_when_type_evident_highlighting = suggestion
+resharper_arrange_default_value_when_type_not_evident_highlighting = suggestion
+resharper_arrange_local_function_body_highlighting = warning
+resharper_arrange_method_or_operator_body_highlighting = hint
+resharper_arrange_null_checking_pattern_highlighting = error
+resharper_arrange_object_creation_when_type_evident_highlighting = suggestion
+resharper_arrange_object_creation_when_type_not_evident_highlighting = warning
+resharper_arrange_redundant_parentheses_highlighting = warning
+resharper_arrange_static_member_qualifier_highlighting = warning
+resharper_arrange_trailing_comma_in_multiline_lists_highlighting = hint
+resharper_arrange_trailing_comma_in_singleline_lists_highlighting = hint
+resharper_arrange_var_keywords_in_deconstructing_declaration_highlighting = suggestion
+resharper_array_with_default_values_initialization_highlighting = suggestion
+resharper_assignment_instead_of_discard_highlighting = warning
+resharper_assignment_in_conditional_expression_highlighting = warning
+resharper_assignment_is_fully_discarded_highlighting = warning
+resharper_assign_null_to_not_null_attribute_highlighting = warning
+resharper_async_iterator_invocation_without_await_foreach_highlighting = warning
+resharper_async_void_function_expression_highlighting = warning
+resharper_async_void_lambda_highlighting = warning
+resharper_async_void_method_highlighting = none
+resharper_auto_property_can_be_made_get_only_global_highlighting = suggestion
+resharper_auto_property_can_be_made_get_only_local_highlighting = suggestion
+resharper_avoid_async_void_highlighting = warning
+resharper_bad_attribute_brackets_spaces_highlighting = none
+resharper_bad_braces_spaces_highlighting = none
+resharper_bad_child_statement_indent_highlighting = warning
+resharper_bad_colon_spaces_highlighting = none
+resharper_bad_comma_spaces_highlighting = none
+resharper_bad_control_braces_indent_highlighting = suggestion
+resharper_bad_control_braces_line_breaks_highlighting = none
+resharper_bad_declaration_braces_indent_highlighting = none
+resharper_bad_declaration_braces_line_breaks_highlighting = none
+resharper_bad_empty_braces_line_breaks_highlighting = none
+resharper_bad_expression_braces_indent_highlighting = none
+resharper_bad_expression_braces_line_breaks_highlighting = none
+resharper_bad_generic_brackets_spaces_highlighting = none
+resharper_bad_indent_highlighting = none
+resharper_bad_linq_line_breaks_highlighting = none
+resharper_bad_list_line_breaks_highlighting = none
+resharper_bad_member_access_spaces_highlighting = none
+resharper_bad_namespace_braces_indent_highlighting = none
+resharper_bad_parens_line_breaks_highlighting = none
+resharper_bad_parens_spaces_highlighting = none
+resharper_bad_preprocessor_indent_highlighting = none
+resharper_bad_semicolon_spaces_highlighting = none
+resharper_bad_spaces_after_keyword_highlighting = none
+resharper_bad_square_brackets_spaces_highlighting = none
+resharper_bad_switch_braces_indent_highlighting = none
+resharper_bad_symbol_spaces_highlighting = none
+resharper_base_member_has_params_highlighting = warning
+resharper_base_method_call_with_default_parameter_highlighting = warning
+resharper_base_object_equals_is_object_equals_highlighting = warning
+resharper_base_object_get_hash_code_call_in_get_hash_code_highlighting = warning
+resharper_bitwise_operator_on_enum_without_flags_highlighting = warning
+resharper_by_ref_argument_is_volatile_field_highlighting = warning
+resharper_cannot_apply_equality_operator_to_type_highlighting = warning
+resharper_can_simplify_dictionary_lookup_with_try_add_highlighting = suggestion
+resharper_can_simplify_dictionary_lookup_with_try_get_value_highlighting = suggestion
+resharper_can_simplify_dictionary_removing_with_single_call_highlighting = suggestion
+resharper_can_simplify_dictionary_try_get_value_with_get_value_or_default_highlighting = suggestion
+resharper_can_simplify_set_adding_with_single_call_highlighting = suggestion
+resharper_catch_all_clause_highlighting = suggestion
+resharper_catch_clause_without_variable_highlighting = suggestion
+resharper_check_for_reference_equality_instead_1_highlighting = suggestion
+resharper_check_for_reference_equality_instead_2_highlighting = suggestion
+resharper_check_for_reference_equality_instead_3_highlighting = suggestion
+resharper_check_for_reference_equality_instead_4_highlighting = suggestion
+resharper_check_namespace_highlighting = warning
+resharper_class_cannot_be_instantiated_highlighting = warning
+resharper_class_can_be_sealed_global_highlighting = none
+resharper_class_can_be_sealed_local_highlighting = none
+resharper_class_never_instantiated_global_highlighting = suggestion
+resharper_class_never_instantiated_local_highlighting = suggestion
+resharper_class_with_virtual_members_never_inherited_global_highlighting = suggestion
+resharper_class_with_virtual_members_never_inherited_local_highlighting = suggestion
+resharper_collection_never_queried_global_highlighting = warning
+resharper_collection_never_queried_local_highlighting = warning
+resharper_collection_never_updated_global_highlighting = warning
+resharper_collection_never_updated_local_highlighting = warning
+resharper_comment_typo_highlighting = suggestion
+resharper_compare_non_constrained_generic_with_null_highlighting = warning
+resharper_compare_of_floats_by_equality_operator_highlighting = warning
+resharper_conditional_access_qualifier_is_non_nullable_according_to_api_contract_highlighting = warning
+resharper_conditional_annotation_highlighting = hint
+resharper_conditional_invocation_highlighting = hint
+resharper_conditional_ternary_equal_branch_highlighting = warning
+resharper_condition_is_always_true_or_false_according_to_nullable_api_contract_highlighting = warning
+resharper_condition_is_always_true_or_false_highlighting = warning
+resharper_conflicting_annotation_highlighting = warning
+resharper_confusing_char_as_integer_in_constructor_highlighting = warning
+resharper_constant_conditional_access_qualifier_highlighting = warning
+resharper_constant_null_coalescing_condition_highlighting = warning
+resharper_constructor_initializer_loop_highlighting = warning
+resharper_constructor_with_must_dispose_resource_attribute_base_is_not_annotated_highlighting = warning
+resharper_container_annotation_redundancy_highlighting = warning
+resharper_context_value_is_provided_highlighting = none
+resharper_contract_annotation_not_parsed_highlighting = warning
+resharper_convert_closure_to_method_group_highlighting = suggestion
+resharper_convert_conditional_ternary_expression_to_switch_expression_highlighting = hint
+resharper_convert_constructor_to_member_initializers_highlighting = suggestion
+resharper_convert_if_do_to_while_highlighting = suggestion
+resharper_convert_if_statement_to_conditional_ternary_expression_highlighting = suggestion
+resharper_convert_if_statement_to_null_coalescing_assignment_highlighting = suggestion
+resharper_convert_if_statement_to_null_coalescing_expression_highlighting = suggestion
+resharper_convert_if_statement_to_return_statement_highlighting = hint
+resharper_convert_if_statement_to_switch_statement_highlighting = hint
+resharper_convert_if_to_or_expression_highlighting = suggestion
+resharper_convert_nullable_to_short_form_highlighting = suggestion
+resharper_convert_switch_statement_to_switch_expression_highlighting = hint
+resharper_convert_to_auto_property_highlighting = suggestion
+resharper_convert_to_auto_property_when_possible_highlighting = hint
+resharper_convert_to_auto_property_with_private_setter_highlighting = hint
+resharper_convert_to_compound_assignment_highlighting = hint
+resharper_convert_to_constant_global_highlighting = hint
+resharper_convert_to_constant_local_highlighting = hint
+resharper_convert_to_lambda_expression_highlighting = suggestion
+resharper_convert_to_local_function_highlighting = suggestion
+resharper_convert_to_null_coalescing_compound_assignment_highlighting = suggestion
+resharper_convert_to_primary_constructor_highlighting = suggestion
+resharper_convert_to_static_class_highlighting = suggestion
+resharper_convert_to_using_declaration_highlighting = suggestion
+resharper_convert_to_vb_auto_property_highlighting = suggestion
+resharper_convert_to_vb_auto_property_when_possible_highlighting = hint
+resharper_convert_to_vb_auto_property_with_private_setter_highlighting = hint
+resharper_convert_type_check_pattern_to_null_check_highlighting = warning
+resharper_convert_type_check_to_null_check_highlighting = warning
+resharper_co_variant_array_conversion_highlighting = warning
+resharper_default_value_attribute_for_optional_parameter_highlighting = warning
+resharper_dispose_on_using_variable_highlighting = warning
+resharper_double_negation_in_pattern_highlighting = suggestion
+resharper_double_negation_operator_highlighting = suggestion
+resharper_duplicate_resource_highlighting = warning
+resharper_empty_constructor_highlighting = warning
+resharper_empty_destructor_highlighting = warning
+resharper_empty_embedded_statement_highlighting = warning
+resharper_empty_for_statement_highlighting = warning
+resharper_empty_general_catch_clause_highlighting = warning
+resharper_empty_namespace_highlighting = warning
+resharper_empty_region_highlighting = suggestion
+resharper_empty_statement_highlighting = warning
+resharper_enforce_do_while_statement_braces_highlighting = error
+resharper_enforce_fixed_statement_braces_highlighting = error
+resharper_enforce_foreach_statement_braces_highlighting = error
+resharper_enforce_for_statement_braces_highlighting = error
+resharper_enforce_if_statement_braces_highlighting = error
+resharper_enforce_lock_statement_braces_highlighting = error
+resharper_enforce_using_statement_braces_highlighting = error
+resharper_enforce_while_statement_braces_highlighting = error
+resharper_entity_framework_model_validation_circular_dependency_highlighting = hint
+resharper_entity_framework_model_validation_unlimited_string_length_highlighting = warning
+resharper_entity_name_captured_only_global_highlighting = warning
+resharper_entity_name_captured_only_local_highlighting = warning
+resharper_enumerable_sum_in_explicit_unchecked_context_highlighting = warning
+resharper_enum_underlying_type_is_int_highlighting = warning
+resharper_equal_expression_comparison_highlighting = warning
+resharper_event_exception_not_documented_highlighting = suggestion
+resharper_event_never_invoked_global_highlighting = suggestion
+resharper_event_never_subscribed_to_global_highlighting = suggestion
+resharper_event_never_subscribed_to_local_highlighting = suggestion
+resharper_event_unsubscription_via_anonymous_delegate_highlighting = warning
+resharper_exception_not_documented_highlighting = warning
+resharper_exception_not_documented_optional_highlighting = hint
+resharper_exception_not_thrown_highlighting = warning
+resharper_exception_not_thrown_optional_highlighting = hint
+resharper_explicit_caller_info_argument_highlighting = warning
+resharper_expression_is_always_null_highlighting = warning
+resharper_extract_common_property_pattern_highlighting = hint
+resharper_field_can_be_made_read_only_global_highlighting = suggestion
+resharper_field_can_be_made_read_only_local_highlighting = suggestion
+resharper_field_hides_interface_property_with_default_implementation_highlighting = warning
+resharper_foreach_can_be_converted_to_query_using_another_get_enumerator_highlighting = hint
+resharper_foreach_can_be_partly_converted_to_query_using_another_get_enumerator_highlighting = hint
+resharper_format_string_placeholders_mismatch_highlighting = warning
+resharper_format_string_problem_highlighting = warning
+resharper_for_can_be_converted_to_foreach_highlighting = suggestion
+resharper_for_statement_condition_is_true_highlighting = warning
+resharper_function_complexity_overflow_highlighting = none
+resharper_function_never_returns_highlighting = warning
+resharper_function_recursive_on_all_paths_highlighting = warning
+resharper_gc_suppress_finalize_for_type_without_destructor_highlighting = warning
+resharper_grammar_mistake_in_comment_highlighting = suggestion
+resharper_grammar_mistake_in_markup_attribute_highlighting = suggestion
+resharper_grammar_mistake_in_markup_text_highlighting = suggestion
+resharper_grammar_mistake_in_string_literal_highlighting = none
+resharper_heap_view_boxing_allocation_highlighting = hint
+resharper_heap_view_can_avoid_closure_highlighting = suggestion
+resharper_heap_view_closure_allocation_highlighting = hint
+resharper_heap_view_delegate_allocation_highlighting = hint
+resharper_heap_view_implicit_capture_highlighting = none
+resharper_heap_view_object_allocation_evident_highlighting = hint
+resharper_heap_view_object_allocation_highlighting = hint
+resharper_heap_view_object_allocation_possible_highlighting = hint
+resharper_heap_view_possible_boxing_allocation_highlighting = hint
+resharper_heuristic_unreachable_code_highlighting = warning
+resharper_identifier_typo_highlighting = suggestion
+resharper_implement_comparison_operators_for_classes_highlighting = suggestion
+resharper_implement_comparison_operators_for_records_highlighting = suggestion
+resharper_implement_comparison_operators_for_structs_highlighting = suggestion
+resharper_implement_equality_operators_for_classes_highlighting = suggestion
+resharper_implement_equality_operators_for_records_highlighting = suggestion
+resharper_implement_equality_operators_for_structs_highlighting = suggestion
+resharper_implement_equatable_highlighting = warning
+resharper_inactive_preprocessor_branch_highlighting = warning
+resharper_inconsistently_synchronized_field_highlighting = warning
+resharper_inconsistent_naming_highlighting = warning
+resharper_inconsistent_order_of_locks_highlighting = warning
+resharper_incorrect_blank_lines_near_braces_highlighting = none
+resharper_indexing_by_invalid_range_highlighting = warning
+resharper_inheritdoc_consider_usage_highlighting = none
+resharper_inheritdoc_invalid_usage_highlighting = warning
+resharper_inline_out_variable_declaration_highlighting = suggestion
+resharper_inline_temporary_variable_highlighting = hint
+resharper_intentional_blocking_attempt_highlighting = warning
+resharper_internal_constructor_visibility_highlighting = suggestion
+resharper_internal_or_private_member_not_documented_highlighting = none
+resharper_interpolated_string_expression_is_not_i_formattable_highlighting = warning
+resharper_introduce_optional_parameters_global_highlighting = suggestion
+resharper_introduce_optional_parameters_local_highlighting = suggestion
+resharper_int_division_by_zero_highlighting = warning
+resharper_int_variable_overflow_highlighting = warning
+resharper_int_variable_overflow_in_checked_context_highlighting = warning
+resharper_int_variable_overflow_in_unchecked_context_highlighting = warning
+resharper_invalid_value_range_boundary_highlighting = warning
+resharper_invalid_value_type_highlighting = warning
+resharper_invalid_xml_doc_comment_highlighting = warning
+resharper_invert_condition_1_highlighting = hint
+resharper_invert_if_highlighting = hint
+resharper_invocation_is_skipped_highlighting = hint
+resharper_invoke_as_extension_method_highlighting = suggestion
+resharper_in_parameter_with_must_dispose_resource_attribute_highlighting = warning
+resharper_is_expression_always_false_highlighting = warning
+resharper_is_expression_always_true_highlighting = warning
+resharper_iterator_method_result_is_ignored_highlighting = warning
+resharper_iterator_never_returns_highlighting = warning
+resharper_join_declaration_and_initializer_highlighting = suggestion
+resharper_join_null_check_with_usage_highlighting = suggestion
+resharper_lambda_expression_can_be_made_static_highlighting = none
+resharper_lambda_expression_must_be_static_highlighting = suggestion
+resharper_lambda_should_not_capture_context_highlighting = warning
+resharper_localizable_element_highlighting = warning
+resharper_local_function_can_be_made_static_highlighting = none
+resharper_local_function_hides_method_highlighting = warning
+resharper_local_suppression_highlighting = warning
+resharper_local_variable_hides_member_highlighting = warning
+resharper_local_variable_hides_primary_constructor_parameter_highlighting = warning
+resharper_lock_on_object_with_weak_identity_highlighting = warning
+resharper_long_literal_ending_lower_l_highlighting = warning
+resharper_loop_can_be_converted_to_query_highlighting = hint
+resharper_loop_can_be_partly_converted_to_query_highlighting = none
+resharper_loop_variable_is_never_changed_inside_loop_highlighting = warning
+resharper_markup_attribute_typo_highlighting = suggestion
+resharper_markup_text_typo_highlighting = suggestion
+resharper_math_abs_method_is_redundant_highlighting = warning
+resharper_math_clamp_min_greater_than_max_highlighting = warning
+resharper_meaningless_default_parameter_value_highlighting = warning
+resharper_member_can_be_file_local_highlighting = none
+resharper_member_can_be_internal_highlighting = none
+resharper_member_can_be_made_static_global_highlighting = hint
+resharper_member_can_be_made_static_local_highlighting = hint
+resharper_member_can_be_private_global_highlighting = suggestion
+resharper_member_can_be_private_local_highlighting = suggestion
+resharper_member_can_be_protected_global_highlighting = suggestion
+resharper_member_can_be_protected_local_highlighting = suggestion
+resharper_member_hides_interface_member_with_default_implementation_highlighting = warning
+resharper_member_hides_static_from_outer_class_highlighting = warning
+resharper_member_initializer_value_ignored_highlighting = warning
+resharper_merge_and_pattern_highlighting = suggestion
+resharper_merge_cast_with_type_check_highlighting = suggestion
+resharper_merge_conditional_expression_highlighting = suggestion
+resharper_merge_into_logical_pattern_highlighting = hint
+resharper_merge_into_negated_pattern_highlighting = hint
+resharper_merge_into_pattern_highlighting = suggestion
+resharper_merge_nested_property_patterns_highlighting = suggestion
+resharper_merge_sequential_checks_highlighting = hint
+resharper_method_has_async_overload_highlighting = suggestion
+resharper_method_has_async_overload_with_cancellation_highlighting = suggestion
+resharper_method_overload_with_optional_parameter_highlighting = warning
+resharper_method_supports_cancellation_highlighting = suggestion
+resharper_missing_annotation_highlighting = warning
+resharper_missing_blank_lines_highlighting = none
+resharper_missing_indent_highlighting = none
+resharper_missing_linebreak_highlighting = none
+resharper_missing_space_highlighting = none
+resharper_missing_suppression_justification_highlighting = warning
+resharper_missing_xml_doc_highlighting = warning
+resharper_more_specific_foreach_variable_type_available_highlighting = suggestion
+resharper_move_local_function_after_jump_statement_highlighting = hint
+resharper_move_to_existing_positional_deconstruction_pattern_highlighting = hint
+resharper_move_variable_declaration_inside_loop_condition_highlighting = suggestion
+resharper_multiple_nullable_attributes_usage_highlighting = warning
+resharper_multiple_order_by_highlighting = warning
+resharper_multiple_resolve_candidates_in_text_highlighting = warning
+resharper_multiple_spaces_highlighting = none
+resharper_multiple_statements_on_one_line_highlighting = none
+resharper_multiple_type_members_on_one_line_highlighting = none
+resharper_must_use_return_value_highlighting = warning
+resharper_negation_of_relational_pattern_highlighting = suggestion
+resharper_negative_equality_expression_highlighting = suggestion
+resharper_negative_index_highlighting = warning
+resharper_nested_string_interpolation_highlighting = suggestion
+resharper_non_atomic_compound_operator_highlighting = warning
+resharper_non_constant_equality_expression_has_constant_result_highlighting = warning
+resharper_non_parsable_element_highlighting = warning
+resharper_non_readonly_member_in_get_hash_code_highlighting = warning
+resharper_non_volatile_field_in_double_check_locking_highlighting = warning
+resharper_notify_property_changed_invocator_from_constructor_highlighting = warning
+resharper_not_accessed_field_global_highlighting = suggestion
+resharper_not_accessed_field_local_highlighting = warning
+resharper_not_accessed_out_parameter_variable_highlighting = warning
+resharper_not_accessed_positional_property_global_highlighting = warning
+resharper_not_accessed_positional_property_local_highlighting = warning
+resharper_not_accessed_variable_highlighting = warning
+resharper_not_allowed_annotation_highlighting = warning
+resharper_not_assigned_out_parameter_highlighting = warning
+resharper_not_declared_in_parent_culture_highlighting = warning
+resharper_not_disposed_resource_highlighting = warning
+resharper_not_disposed_resource_is_returned_by_property_highlighting = warning
+resharper_not_disposed_resource_is_returned_highlighting = warning
+resharper_not_null_or_required_member_is_not_initialized_highlighting = warning
+resharper_not_observable_annotation_redundancy_highlighting = warning
+resharper_not_overridden_in_specific_culture_highlighting = warning
+resharper_not_resolved_in_text_highlighting = warning
+resharper_nullable_warning_suppression_is_used_highlighting = none
+resharper_nullness_annotation_conflict_with_jet_brains_annotations_highlighting = warning
+resharper_null_coalescing_condition_is_always_not_null_according_to_api_contract_highlighting = warning
+resharper_n_unit_async_method_must_be_task_highlighting = warning
+resharper_n_unit_attribute_produces_too_many_tests_highlighting = none
+resharper_n_unit_auto_fixture_incorrect_argument_type_highlighting = warning
+resharper_n_unit_auto_fixture_missed_test_attribute_highlighting = warning
+resharper_n_unit_auto_fixture_missed_test_or_test_fixture_attribute_highlighting = warning
+resharper_n_unit_auto_fixture_redundant_argument_in_inline_auto_data_attribute_highlighting = warning
+resharper_n_unit_duplicate_values_highlighting = warning
+resharper_n_unit_ignored_parameter_attribute_highlighting = warning
+resharper_n_unit_implicit_unspecified_null_values_highlighting = warning
+resharper_n_unit_incorrect_argument_type_highlighting = warning
+resharper_n_unit_incorrect_expected_result_type_highlighting = warning
+resharper_n_unit_incorrect_range_bounds_highlighting = warning
+resharper_n_unit_method_with_parameters_and_test_attribute_highlighting = warning
+resharper_n_unit_missing_arguments_in_test_case_attribute_highlighting = warning
+resharper_n_unit_non_public_method_with_test_attribute_highlighting = warning
+resharper_n_unit_no_values_provided_highlighting = warning
+resharper_n_unit_parameter_type_is_not_compatible_with_attribute_highlighting = warning
+resharper_n_unit_range_attribute_bounds_are_out_of_range_highlighting = warning
+resharper_n_unit_range_step_sign_mismatch_highlighting = warning
+resharper_n_unit_range_step_value_must_not_be_zero_highlighting = warning
+resharper_n_unit_range_to_value_is_not_reachable_highlighting = warning
+resharper_n_unit_redundant_argument_instead_of_expected_result_highlighting = warning
+resharper_n_unit_redundant_argument_in_test_case_attribute_highlighting = warning
+resharper_n_unit_redundant_expected_result_in_test_case_attribute_highlighting = warning
+resharper_n_unit_test_case_attribute_requires_expected_result_highlighting = warning
+resharper_n_unit_test_case_result_property_duplicates_expected_result_highlighting = warning
+resharper_n_unit_test_case_result_property_is_obsolete_highlighting = warning
+resharper_n_unit_test_case_source_cannot_be_resolved_highlighting = warning
+resharper_n_unit_test_case_source_must_be_field_property_method_highlighting = warning
+resharper_n_unit_test_case_source_must_be_static_highlighting = warning
+resharper_n_unit_test_case_source_should_implement_i_enumerable_highlighting = warning
+resharper_object_creation_as_statement_highlighting = warning
+resharper_obsolete_element_error_highlighting = error
+resharper_obsolete_element_highlighting = warning
+resharper_one_way_operation_contract_with_return_type_highlighting = warning
+resharper_operation_contract_without_service_contract_highlighting = warning
+resharper_operator_is_can_be_used_highlighting = warning
+resharper_operator_without_matched_checked_operator_highlighting = warning
+resharper_optional_parameter_hierarchy_mismatch_highlighting = warning
+resharper_optional_parameter_ref_out_highlighting = warning
+resharper_outdent_is_off_prev_level_highlighting = none
+resharper_out_parameter_value_is_always_discarded_global_highlighting = suggestion
+resharper_out_parameter_value_is_always_discarded_local_highlighting = warning
+resharper_overridden_with_empty_value_highlighting = warning
+resharper_overridden_with_same_value_highlighting = suggestion
+resharper_override_equals_highlighting = warning
+resharper_parameter_hides_member_highlighting = warning
+resharper_parameter_hides_primary_constructor_parameter_highlighting = warning
+resharper_parameter_only_used_for_precondition_check_global_highlighting = suggestion
+resharper_parameter_only_used_for_precondition_check_local_highlighting = warning
+resharper_parameter_type_can_be_enumerable_global_highlighting = hint
+resharper_parameter_type_can_be_enumerable_local_highlighting = hint
+resharper_partial_method_parameter_name_mismatch_highlighting = warning
+resharper_partial_method_with_single_part_highlighting = warning
+resharper_partial_type_with_single_part_highlighting = warning
+resharper_pass_string_interpolation_highlighting = hint
+resharper_pattern_always_matches_highlighting = warning
+resharper_pattern_is_always_true_or_false_highlighting = warning
+resharper_pattern_is_redundant_highlighting = warning
+resharper_pattern_never_matches_highlighting = warning
+resharper_place_assignment_expression_into_block_highlighting = none
+resharper_polymorphic_field_like_event_invocation_highlighting = warning
+resharper_possible_infinite_inheritance_highlighting = warning
+resharper_possible_intended_rethrow_highlighting = warning
+resharper_possible_interface_member_ambiguity_highlighting = warning
+resharper_possible_invalid_cast_exception_highlighting = warning
+resharper_possible_invalid_cast_exception_in_foreach_loop_highlighting = warning
+resharper_possible_invalid_operation_exception_highlighting = warning
+resharper_possible_loss_of_fraction_highlighting = warning
+resharper_possible_mistaken_argument_highlighting = warning
+resharper_possible_mistaken_call_to_get_type_1_highlighting = warning
+resharper_possible_mistaken_call_to_get_type_2_highlighting = warning
+resharper_possible_multiple_consumption_highlighting = warning
+resharper_possible_multiple_enumeration_highlighting = warning
+resharper_possible_multiple_write_access_in_double_check_locking_highlighting = warning
+resharper_possible_null_reference_exception_highlighting = warning
+resharper_possible_struct_member_modification_of_non_variable_struct_highlighting = warning
+resharper_possible_unintended_linear_search_in_set_highlighting = warning
+resharper_possible_unintended_queryable_as_enumerable_highlighting = suggestion
+resharper_possible_unintended_reference_comparison_highlighting = warning
+resharper_possible_write_to_me_highlighting = warning
+resharper_possibly_impure_method_call_on_readonly_variable_highlighting = warning
+resharper_possibly_missing_indexer_initializer_comma_highlighting = warning
+resharper_possibly_mistaken_use_of_interpolated_string_insert_highlighting = warning
+resharper_possibly_unintended_usage_parameterless_get_expression_type_highlighting = error
+resharper_private_field_can_be_converted_to_local_variable_highlighting = warning
+resharper_property_can_be_made_init_only_global_highlighting = suggestion
+resharper_property_can_be_made_init_only_local_highlighting = suggestion
+resharper_property_field_keyword_is_never_assigned_highlighting = warning
+resharper_property_field_keyword_is_never_used_highlighting = warning
+resharper_property_not_resolved_highlighting = error
+resharper_public_constructor_in_abstract_class_highlighting = suggestion
+resharper_pure_attribute_on_void_method_highlighting = warning
+resharper_raw_string_can_be_simplified_highlighting = hint
+resharper_read_access_in_double_check_locking_highlighting = warning
+resharper_redundant_abstract_modifier_highlighting = warning
+resharper_redundant_accessor_body_highlighting = suggestion
+resharper_redundant_always_match_subpattern_highlighting = suggestion
+resharper_redundant_annotation_argument_highlighting = suggestion
+resharper_redundant_annotation_highlighting = suggestion
+resharper_redundant_anonymous_type_property_name_highlighting = warning
+resharper_redundant_argument_default_value_highlighting = warning
+resharper_redundant_array_creation_expression_highlighting = hint
+resharper_redundant_array_lower_bound_specification_highlighting = warning
+resharper_redundant_assertion_statement_highlighting = suggestion
+resharper_redundant_assignment_highlighting = warning
+resharper_redundant_attribute_parentheses_highlighting = hint
+resharper_redundant_attribute_suffix_highlighting = warning
+resharper_redundant_attribute_usage_property_highlighting = suggestion
+resharper_redundant_base_constructor_call_highlighting = warning
+resharper_redundant_blank_lines_highlighting = none
+resharper_redundant_bool_compare_highlighting = warning
+resharper_redundant_caller_argument_expression_default_value_highlighting = warning
+resharper_redundant_captured_context_highlighting = suggestion
+resharper_redundant_case_label_highlighting = warning
+resharper_redundant_cast_highlighting = warning
+resharper_redundant_catch_clause_highlighting = warning
+resharper_redundant_check_before_assignment_highlighting = warning
+resharper_redundant_collection_initializer_element_braces_highlighting = hint
+resharper_redundant_configure_await_highlighting = suggestion
+resharper_redundant_declaration_semicolon_highlighting = hint
+resharper_redundant_default_member_initializer_highlighting = warning
+resharper_redundant_delegate_creation_highlighting = warning
+resharper_redundant_delegate_invoke_highlighting = suggestion
+resharper_redundant_dictionary_contains_key_before_adding_highlighting = warning
+resharper_redundant_disable_warning_comment_highlighting = warning
+resharper_redundant_discard_designation_highlighting = suggestion
+resharper_redundant_empty_case_else_highlighting = warning
+resharper_redundant_empty_finally_block_highlighting = warning
+resharper_redundant_empty_object_creation_argument_list_highlighting = hint
+resharper_redundant_empty_object_or_collection_initializer_highlighting = warning
+resharper_redundant_empty_switch_section_highlighting = warning
+resharper_redundant_enumerable_cast_call_highlighting = warning
+resharper_redundant_enum_case_label_for_default_section_highlighting = none
+resharper_redundant_explicit_array_creation_highlighting = warning
+resharper_redundant_explicit_array_size_highlighting = warning
+resharper_redundant_explicit_nullable_creation_highlighting = warning
+resharper_redundant_explicit_params_array_creation_highlighting = suggestion
+resharper_redundant_explicit_positional_property_declaration_highlighting = warning
+resharper_redundant_explicit_tuple_component_name_highlighting = warning
+resharper_redundant_extends_list_entry_highlighting = warning
+resharper_redundant_fixed_pointer_declaration_highlighting = suggestion
+resharper_redundant_if_else_block_highlighting = hint
+resharper_redundant_if_statement_then_keyword_highlighting = none
+resharper_redundant_immediate_delegate_invocation_highlighting = suggestion
+resharper_redundant_inline_assertion_highlighting = suggestion
+resharper_redundant_is_before_relational_pattern_highlighting = suggestion
+resharper_redundant_iterator_keyword_highlighting = warning
+resharper_redundant_jump_statement_highlighting = warning
+resharper_redundant_lambda_parameter_type_highlighting = warning
+resharper_redundant_lambda_signature_parentheses_highlighting = hint
+resharper_redundant_linebreak_highlighting = none
+resharper_redundant_logical_conditional_expression_operand_highlighting = warning
+resharper_redundant_me_qualifier_highlighting = warning
+resharper_redundant_my_base_qualifier_highlighting = warning
+resharper_redundant_my_class_qualifier_highlighting = warning
+resharper_redundant_name_qualifier_highlighting = warning
+resharper_redundant_not_null_constraint_highlighting = warning
+resharper_redundant_nullable_annotation_on_reference_type_constraint_highlighting = warning
+resharper_redundant_nullable_annotation_on_type_constraint_has_non_nullable_base_type_highlighting = warning
+resharper_redundant_nullable_annotation_on_type_constraint_has_non_nullable_type_kind_highlighting = warning
+resharper_redundant_nullable_directive_highlighting = warning
+resharper_redundant_nullable_flow_attribute_highlighting = warning
+resharper_redundant_nullable_type_mark_highlighting = warning
+resharper_redundant_nullness_attribute_with_nullable_reference_types_highlighting = warning
+resharper_redundant_overflow_checking_context_highlighting = warning
+resharper_redundant_overload_global_highlighting = suggestion
+resharper_redundant_overload_local_highlighting = suggestion
+resharper_redundant_overridden_member_highlighting = warning
+resharper_redundant_params_highlighting = warning
+resharper_redundant_parentheses_highlighting = none
+resharper_redundant_pattern_parentheses_highlighting = hint
+resharper_redundant_property_parentheses_highlighting = hint
+resharper_redundant_property_pattern_clause_highlighting = suggestion
+resharper_redundant_qualifier_highlighting = warning
+resharper_redundant_query_order_by_ascending_keyword_highlighting = hint
+resharper_redundant_range_bound_highlighting = suggestion
+resharper_redundant_readonly_modifier_highlighting = suggestion
+resharper_redundant_record_class_keyword_highlighting = warning
+resharper_redundant_scoped_parameter_modifier_highlighting = warning
+resharper_redundant_setter_value_parameter_declaration_highlighting = hint
+resharper_redundant_space_highlighting = none
+resharper_redundant_string_format_call_highlighting = warning
+resharper_redundant_string_interpolation_highlighting = suggestion
+resharper_redundant_string_to_char_array_call_highlighting = warning
+resharper_redundant_string_type_highlighting = suggestion
+resharper_redundant_suppress_nullable_warning_expression_highlighting = warning
+resharper_redundant_ternary_expression_highlighting = warning
+resharper_redundant_to_string_call_for_value_type_highlighting = hint
+resharper_redundant_to_string_call_highlighting = warning
+resharper_redundant_type_arguments_of_method_highlighting = warning
+resharper_redundant_type_check_in_pattern_highlighting = warning
+resharper_redundant_type_declaration_body_highlighting = warning
+resharper_redundant_unsafe_context_highlighting = warning
+resharper_redundant_using_directive_global_highlighting = warning
+resharper_redundant_using_directive_highlighting = warning
+resharper_redundant_verbatim_prefix_highlighting = suggestion
+resharper_redundant_verbatim_string_prefix_highlighting = suggestion
+resharper_redundant_virtual_modifier_highlighting = warning
+resharper_redundant_with_cancellation_highlighting = warning
+resharper_redundant_with_expression_highlighting = suggestion
+resharper_reference_equals_with_value_type_highlighting = warning
+resharper_region_within_type_member_body_highlighting = warning
+resharper_region_with_single_element_highlighting = suggestion
+resharper_reg_exp_inspections_highlighting = warning
+resharper_remove_constructor_invocation_highlighting = none
+resharper_remove_redundant_or_statement_false_highlighting = suggestion
+resharper_remove_redundant_or_statement_true_highlighting = suggestion
+resharper_remove_to_list_1_highlighting = suggestion
+resharper_remove_to_list_2_highlighting = suggestion
+resharper_replace_async_with_task_return_highlighting = suggestion
+resharper_replace_auto_property_with_computed_property_highlighting = hint
+resharper_replace_conditional_expression_with_null_coalescing_highlighting = suggestion
+resharper_replace_object_pattern_with_var_pattern_highlighting = suggestion
+resharper_replace_sequence_equal_with_constant_pattern_highlighting = suggestion
+resharper_replace_slice_with_range_indexer_highlighting = hint
+resharper_replace_substring_with_range_indexer_highlighting = hint
+resharper_replace_with_field_keyword_highlighting = suggestion
+resharper_replace_with_first_or_default_1_highlighting = suggestion
+resharper_replace_with_first_or_default_2_highlighting = suggestion
+resharper_replace_with_first_or_default_3_highlighting = suggestion
+resharper_replace_with_first_or_default_4_highlighting = suggestion
+resharper_replace_with_last_or_default_1_highlighting = suggestion
+resharper_replace_with_last_or_default_2_highlighting = suggestion
+resharper_replace_with_last_or_default_3_highlighting = suggestion
+resharper_replace_with_last_or_default_4_highlighting = suggestion
+resharper_replace_with_of_type_1_highlighting = suggestion
+resharper_replace_with_of_type_2_highlighting = suggestion
+resharper_replace_with_of_type_3_highlighting = suggestion
+resharper_replace_with_of_type_any_1_highlighting = suggestion
+resharper_replace_with_of_type_any_2_highlighting = suggestion
+resharper_replace_with_of_type_count_1_highlighting = suggestion
+resharper_replace_with_of_type_count_2_highlighting = suggestion
+resharper_replace_with_of_type_first_1_highlighting = suggestion
+resharper_replace_with_of_type_first_2_highlighting = suggestion
+resharper_replace_with_of_type_first_or_default_1_highlighting = suggestion
+resharper_replace_with_of_type_first_or_default_2_highlighting = suggestion
+resharper_replace_with_of_type_last_1_highlighting = suggestion
+resharper_replace_with_of_type_last_2_highlighting = suggestion
+resharper_replace_with_of_type_last_or_default_1_highlighting = suggestion
+resharper_replace_with_of_type_last_or_default_2_highlighting = suggestion
+resharper_replace_with_of_type_long_count_highlighting = suggestion
+resharper_replace_with_of_type_single_1_highlighting = suggestion
+resharper_replace_with_of_type_single_2_highlighting = suggestion
+resharper_replace_with_of_type_single_or_default_1_highlighting = suggestion
+resharper_replace_with_of_type_single_or_default_2_highlighting = suggestion
+resharper_replace_with_of_type_where_highlighting = suggestion
+resharper_replace_with_primary_constructor_parameter_highlighting = suggestion
+resharper_replace_with_simple_assignment_false_highlighting = suggestion
+resharper_replace_with_simple_assignment_true_highlighting = suggestion
+resharper_replace_with_single_assignment_false_highlighting = suggestion
+resharper_replace_with_single_assignment_true_highlighting = suggestion
+resharper_replace_with_single_call_to_any_highlighting = suggestion
+resharper_replace_with_single_call_to_count_highlighting = suggestion
+resharper_replace_with_single_call_to_first_highlighting = suggestion
+resharper_replace_with_single_call_to_first_or_default_highlighting = suggestion
+resharper_replace_with_single_call_to_last_highlighting = suggestion
+resharper_replace_with_single_call_to_last_or_default_highlighting = suggestion
+resharper_replace_with_single_call_to_single_highlighting = suggestion
+resharper_replace_with_single_call_to_single_or_default_highlighting = suggestion
+resharper_replace_with_single_or_default_1_highlighting = suggestion
+resharper_replace_with_single_or_default_2_highlighting = suggestion
+resharper_replace_with_single_or_default_3_highlighting = suggestion
+resharper_replace_with_single_or_default_4_highlighting = suggestion
+resharper_replace_with_string_is_null_or_empty_highlighting = suggestion
+resharper_required_base_types_conflict_highlighting = warning
+resharper_required_base_types_direct_conflict_highlighting = warning
+resharper_required_base_types_is_not_inherited_highlighting = warning
+resharper_resource_item_not_resolved_highlighting = error
+resharper_resource_not_resolved_highlighting = error
+resharper_resx_not_resolved_highlighting = warning
+resharper_return_of_task_produced_by_using_variable_highlighting = warning
+resharper_return_of_using_variable_highlighting = warning
+resharper_return_type_can_be_enumerable_global_highlighting = hint
+resharper_return_type_can_be_enumerable_local_highlighting = hint
+resharper_return_type_can_be_not_nullable_highlighting = warning
+resharper_return_value_of_pure_method_is_not_used_highlighting = warning
+resharper_safe_cast_is_used_as_type_check_highlighting = suggestion
+resharper_sealed_member_in_sealed_class_highlighting = warning
+resharper_separate_control_transfer_statement_highlighting = none
+resharper_separate_local_functions_with_jump_statement_highlighting = hint
+resharper_service_contract_without_operations_highlighting = warning
+resharper_shift_expression_real_shift_count_is_zero_highlighting = warning
+resharper_shift_expression_result_equals_zero_highlighting = warning
+resharper_shift_expression_right_operand_not_equal_real_count_highlighting = warning
+resharper_shift_expression_zero_left_operand_highlighting = warning
+resharper_similar_anonymous_type_nearby_highlighting = hint
+resharper_simplify_conditional_operator_highlighting = suggestion
+resharper_simplify_conditional_ternary_expression_highlighting = suggestion
+resharper_simplify_i_if_highlighting = suggestion
+resharper_simplify_linq_expression_use_all_highlighting = suggestion
+resharper_simplify_linq_expression_use_any_highlighting = suggestion
+resharper_simplify_linq_expression_use_min_by_and_max_by_highlighting = suggestion
+resharper_simplify_string_interpolation_highlighting = suggestion
+resharper_specify_a_culture_in_string_conversion_explicitly_highlighting = warning
+resharper_specify_string_comparison_highlighting = hint
+resharper_spin_lock_in_readonly_field_highlighting = warning
+resharper_stack_alloc_inside_loop_highlighting = warning
+resharper_static_member_initializer_referes_to_member_below_highlighting = warning
+resharper_static_member_in_generic_type_highlighting = warning
+resharper_static_problem_in_text_highlighting = warning
+resharper_string_compare_is_culture_specific_1_highlighting = warning
+resharper_string_compare_is_culture_specific_2_highlighting = warning
+resharper_string_compare_is_culture_specific_3_highlighting = warning
+resharper_string_compare_is_culture_specific_4_highlighting = warning
+resharper_string_compare_is_culture_specific_5_highlighting = warning
+resharper_string_compare_is_culture_specific_6_highlighting = warning
+resharper_string_compare_to_is_culture_specific_highlighting = warning
+resharper_string_ends_with_is_culture_specific_highlighting = none
+resharper_string_index_of_is_culture_specific_1_highlighting = warning
+resharper_string_index_of_is_culture_specific_2_highlighting = warning
+resharper_string_index_of_is_culture_specific_3_highlighting = warning
+resharper_string_last_index_of_is_culture_specific_1_highlighting = warning
+resharper_string_last_index_of_is_culture_specific_2_highlighting = warning
+resharper_string_last_index_of_is_culture_specific_3_highlighting = warning
+resharper_string_literal_as_interpolation_argument_highlighting = suggestion
+resharper_string_literal_typo_highlighting = suggestion
+resharper_string_starts_with_is_culture_specific_highlighting = none
+resharper_structured_message_template_problem_highlighting = warning
+resharper_struct_can_be_made_read_only_highlighting = suggestion
+resharper_struct_member_can_be_made_read_only_highlighting = none
+resharper_suggest_base_type_for_parameter_highlighting = hint
+resharper_suggest_base_type_for_parameter_in_constructor_highlighting = hint
+resharper_suggest_discard_declaration_var_style_highlighting = hint
+resharper_suggest_var_or_type_built_in_types_highlighting = hint
+resharper_suggest_var_or_type_deconstruction_declarations_highlighting = hint
+resharper_suggest_var_or_type_elsewhere_highlighting = suggestion
+resharper_suggest_var_or_type_simple_types_highlighting = hint
+csharp_space_before_open_square_brackets = true
+resharper_suppress_nullable_warning_expression_as_inverted_is_expression_highlighting = warning
+resharper_suspicious_lock_over_synchronization_primitive_highlighting = warning
+resharper_suspicious_math_sign_method_highlighting = warning
+resharper_suspicious_parameter_name_in_argument_null_exception_highlighting = warning
+resharper_suspicious_type_conversion_global_highlighting = warning
+resharper_swap_via_deconstruction_highlighting = suggestion
+resharper_switch_expression_handles_some_known_enum_values_with_exception_in_default_highlighting = hint
+resharper_switch_statement_for_enum_misses_default_section_highlighting = hint
+resharper_switch_statement_handles_some_known_enum_values_with_default_highlighting = hint
+resharper_switch_statement_missing_some_enum_cases_no_default_highlighting = hint
+resharper_symbol_from_not_copied_locally_reference_used_warning_highlighting = warning
+resharper_tabs_and_spaces_mismatch_highlighting = warning
+resharper_tabs_are_disallowed_highlighting = warning
+resharper_tabs_outside_indent_highlighting = none
+resharper_tail_recursive_call_highlighting = hint
+resharper_thread_static_at_instance_field_highlighting = warning
+resharper_thread_static_field_has_initializer_highlighting = warning
+resharper_throwing_system_exception_highlighting = suggestion
+resharper_throw_exception_in_unexpected_location_highlighting = warning
+resharper_throw_from_catch_with_no_inner_exception_highlighting = warning
+resharper_too_wide_local_variable_scope_highlighting = suggestion
+resharper_try_cast_always_succeeds_highlighting = suggestion
+resharper_try_statements_can_be_merged_highlighting = hint
+resharper_type_parameter_can_be_variant_highlighting = suggestion
+resharper_unassigned_field_global_highlighting = suggestion
+resharper_unassigned_field_local_highlighting = warning
+resharper_unassigned_get_only_auto_property_highlighting = warning
+resharper_unassigned_readonly_field_highlighting = warning
+resharper_uncatchable_exception_highlighting = warning
+resharper_unnecessary_whitespace_highlighting = warning
+resharper_unreachable_switch_arm_due_to_integer_analysis_highlighting = warning
+resharper_unreachable_switch_case_due_to_integer_analysis_highlighting = warning
+resharper_unsupported_required_base_type_highlighting = warning
+resharper_unthrowable_exception_highlighting = warning
+resharper_unused_anonymous_method_signature_highlighting = warning
+resharper_unused_auto_property_accessor_global_highlighting = warning
+resharper_unused_auto_property_accessor_local_highlighting = warning
+resharper_unused_import_clause_highlighting = warning
+resharper_unused_local_function_highlighting = warning
+resharper_unused_local_function_parameter_highlighting = warning
+resharper_unused_local_function_return_value_highlighting = warning
+resharper_unused_member_global_highlighting = suggestion
+resharper_unused_member_hierarchy_global_highlighting = suggestion
+resharper_unused_member_hierarchy_local_highlighting = warning
+resharper_unused_member_in_super_global_highlighting = suggestion
+resharper_unused_member_in_super_local_highlighting = warning
+resharper_unused_member_local_highlighting = warning
+resharper_unused_method_return_value_global_highlighting = suggestion
+resharper_unused_method_return_value_local_highlighting = warning
+resharper_unused_nullable_directive_highlighting = warning
+resharper_unused_parameter_global_highlighting = suggestion
+resharper_unused_parameter_in_partial_method_highlighting = warning
+resharper_unused_parameter_local_highlighting = warning
+resharper_unused_tuple_component_in_return_value_highlighting = warning
+resharper_unused_type_global_highlighting = suggestion
+resharper_unused_type_local_highlighting = warning
+resharper_unused_type_parameter_highlighting = warning
+resharper_unused_variable_highlighting = warning
+resharper_useless_binary_operation_highlighting = warning
+resharper_useless_comparison_to_integral_constant_highlighting = warning
+resharper_use_array_creation_expression_1_highlighting = suggestion
+resharper_use_array_creation_expression_2_highlighting = suggestion
+resharper_use_array_empty_method_highlighting = suggestion
+resharper_use_await_using_highlighting = suggestion
+resharper_use_cancellation_token_for_i_async_enumerable_highlighting = suggestion
+resharper_use_collection_count_property_highlighting = suggestion
+resharper_use_collection_expression_highlighting = suggestion
+resharper_use_configure_await_false_for_async_disposable_highlighting = none
+resharper_use_configure_await_false_highlighting = suggestion
+resharper_use_deconstruction_highlighting = hint
+resharper_use_discard_assignment_highlighting = suggestion
+resharper_use_empty_for_array_initialization_highlighting = warning
+resharper_use_empty_types_field_highlighting = suggestion
+resharper_use_event_args_empty_field_highlighting = suggestion
+resharper_use_format_specifier_in_format_string_highlighting = suggestion
+resharper_use_implicitly_typed_variable_evident_highlighting = hint
+resharper_use_implicitly_typed_variable_highlighting = none
+resharper_use_implicit_by_val_modifier_highlighting = hint
+resharper_use_indexed_property_highlighting = suggestion
+resharper_use_index_from_end_expression_highlighting = suggestion
+resharper_use_is_operator_1_highlighting = suggestion
+resharper_use_is_operator_2_highlighting = suggestion
+resharper_use_method_any_0_highlighting = suggestion
+resharper_use_method_any_1_highlighting = suggestion
+resharper_use_method_any_2_highlighting = suggestion
+resharper_use_method_any_3_highlighting = suggestion
+resharper_use_method_any_4_highlighting = suggestion
+resharper_use_method_is_instance_of_type_highlighting = suggestion
+resharper_use_nameof_expression_for_part_of_the_string_highlighting = none
+resharper_use_nameof_expression_highlighting = suggestion
+resharper_use_nameof_for_dependency_property_highlighting = suggestion
+resharper_use_name_of_instead_of_type_of_highlighting = suggestion
+resharper_use_negated_pattern_in_is_expression_highlighting = hint
+resharper_use_negated_pattern_matching_highlighting = hint
+resharper_use_nullable_annotation_instead_of_attribute_highlighting = suggestion
+resharper_use_nullable_attributes_supported_by_compiler_highlighting = suggestion
+resharper_use_nullable_reference_types_annotation_syntax_highlighting = warning
+resharper_use_null_propagation_highlighting = hint
+resharper_use_object_or_collection_initializer_highlighting = suggestion
+resharper_use_pattern_matching_highlighting = suggestion
+resharper_use_positional_deconstruction_pattern_highlighting = none
+resharper_use_raw_string_highlighting = hint
+resharper_use_string_interpolation_highlighting = suggestion
+resharper_use_string_interpolation_when_possible_highlighting = hint
+resharper_use_switch_case_pattern_variable_highlighting = suggestion
+resharper_use_symbol_alias_highlighting = hint
+resharper_use_target_typed_collection_expression_highlighting = suggestion
+resharper_use_throw_if_null_method_highlighting = warning
+resharper_use_unsigned_right_shift_operator_highlighting = suggestion
+resharper_use_verbatim_string_highlighting = hint
+resharper_use_with_expression_to_copy_anonymous_object_highlighting = suggestion
+resharper_use_with_expression_to_copy_record_highlighting = suggestion
+resharper_use_with_expression_to_copy_struct_highlighting = suggestion
+resharper_use_with_expression_to_copy_tuple_highlighting = suggestion
+resharper_using_statement_resource_initialization_expression_highlighting = hint
+resharper_using_statement_resource_initialization_highlighting = warning
+resharper_value_parameter_not_used_highlighting = warning
+resharper_value_range_attribute_violation_highlighting = warning
+resharper_variable_can_be_not_nullable_highlighting = warning
+resharper_variable_hides_outer_variable_highlighting = warning
+resharper_vb_check_for_reference_equality_instead_1_highlighting = suggestion
+resharper_vb_check_for_reference_equality_instead_2_highlighting = suggestion
+resharper_vb_possible_mistaken_argument_highlighting = warning
+resharper_vb_possible_mistaken_call_to_get_type_1_highlighting = warning
+resharper_vb_possible_mistaken_call_to_get_type_2_highlighting = warning
+resharper_vb_remove_to_list_1_highlighting = suggestion
+resharper_vb_remove_to_list_2_highlighting = suggestion
+resharper_vb_replace_with_first_or_default_highlighting = suggestion
+resharper_vb_replace_with_last_or_default_highlighting = suggestion
+resharper_vb_replace_with_of_type_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_any_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_any_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_count_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_count_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_first_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_first_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_first_or_default_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_first_or_default_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_last_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_last_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_last_or_default_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_last_or_default_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_single_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_single_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_single_or_default_1_highlighting = suggestion
+resharper_vb_replace_with_of_type_single_or_default_2_highlighting = suggestion
+resharper_vb_replace_with_of_type_where_highlighting = suggestion
+resharper_vb_replace_with_single_assignment_1_highlighting = suggestion
+resharper_vb_replace_with_single_assignment_2_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_any_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_count_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_first_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_first_or_default_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_last_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_last_or_default_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_single_highlighting = suggestion
+resharper_vb_replace_with_single_call_to_single_or_default_highlighting = suggestion
+resharper_vb_replace_with_single_or_default_highlighting = suggestion
+resharper_vb_simplify_linq_expression_10_highlighting = hint
+resharper_vb_simplify_linq_expression_1_highlighting = suggestion
+resharper_vb_simplify_linq_expression_2_highlighting = suggestion
+resharper_vb_simplify_linq_expression_3_highlighting = suggestion
+resharper_vb_simplify_linq_expression_4_highlighting = suggestion
+resharper_vb_simplify_linq_expression_5_highlighting = suggestion
+resharper_vb_simplify_linq_expression_6_highlighting = suggestion
+resharper_vb_simplify_linq_expression_7_highlighting = hint
+resharper_vb_simplify_linq_expression_8_highlighting = hint
+resharper_vb_simplify_linq_expression_9_highlighting = hint
+resharper_vb_string_compare_is_culture_specific_1_highlighting = warning
+resharper_vb_string_compare_is_culture_specific_2_highlighting = warning
+resharper_vb_string_compare_is_culture_specific_3_highlighting = warning
+resharper_vb_string_compare_is_culture_specific_4_highlighting = warning
+resharper_vb_string_compare_is_culture_specific_5_highlighting = warning
+resharper_vb_string_compare_is_culture_specific_6_highlighting = warning
+resharper_vb_string_compare_to_is_culture_specific_highlighting = warning
+resharper_vb_string_ends_with_is_culture_specific_highlighting = none
+resharper_vb_string_index_of_is_culture_specific_1_highlighting = warning
+resharper_vb_string_index_of_is_culture_specific_2_highlighting = warning
+resharper_vb_string_index_of_is_culture_specific_3_highlighting = warning
+resharper_vb_string_last_index_of_is_culture_specific_1_highlighting = warning
+resharper_vb_string_last_index_of_is_culture_specific_2_highlighting = warning
+resharper_vb_string_last_index_of_is_culture_specific_3_highlighting = warning
+resharper_vb_string_starts_with_is_culture_specific_highlighting = none
+resharper_vb_unreachable_code_highlighting = warning
+resharper_vb_use_array_creation_expression_1_highlighting = suggestion
+resharper_vb_use_array_creation_expression_2_highlighting = suggestion
+resharper_vb_use_first_instead_highlighting = warning
+resharper_vb_use_method_any_1_highlighting = suggestion
+resharper_vb_use_method_any_2_highlighting = suggestion
+resharper_vb_use_method_any_3_highlighting = suggestion
+resharper_vb_use_method_any_4_highlighting = suggestion
+resharper_vb_use_method_any_5_highlighting = suggestion
+resharper_vb_use_method_is_instance_of_type_highlighting = suggestion
+resharper_vb_use_type_of_is_operator_1_highlighting = suggestion
+resharper_vb_use_type_of_is_operator_2_highlighting = suggestion
+resharper_virtual_member_call_in_constructor_highlighting = warning
+resharper_virtual_member_never_overridden_global_highlighting = suggestion
+resharper_virtual_member_never_overridden_local_highlighting = suggestion
+resharper_void_method_with_must_dispose_resource_attribute_highlighting = warning
+resharper_void_method_with_must_use_return_value_attribute_highlighting = warning
+resharper_vulnerable_api_highlighting = warning
+resharper_with_expression_instead_of_initializer_highlighting = suggestion
+resharper_with_expression_modifies_all_members_highlighting = warning
+resharper_wrong_indent_size_highlighting = none
+resharper_xaml_assign_null_to_not_null_attribute_highlighting = warning
+resharper_xaml_avalonia_wrong_binding_mode_for_stream_binding_operator_highlighting = warning
+resharper_xaml_binding_without_context_not_resolved_highlighting = hint
+resharper_xaml_binding_without_mode_highlighting = warning
+resharper_xaml_binding_with_context_not_resolved_highlighting = warning
+resharper_xaml_compiled_binding_missing_data_type_error_highlighting_highlighting = error
+resharper_xaml_constructor_warning_highlighting = warning
+resharper_xaml_decimal_parsing_is_culture_dependent_highlighting = warning
+resharper_xaml_dependency_property_resolve_error_highlighting = warning
+resharper_xaml_duplicate_style_setter_highlighting = warning
+resharper_xaml_dynamic_resource_error_highlighting = error
+resharper_xaml_element_name_reference_not_resolved_highlighting = error
+resharper_xaml_empty_grid_length_definition_highlighting = error
+resharper_xaml_field_modifier_requires_name_attribute_highlighting = warning
+resharper_xaml_grid_definitions_can_be_converted_to_attribute_highlighting = hint
+resharper_xaml_ignored_path_highlighting_highlighting = none
+resharper_xaml_index_out_of_grid_definition_highlighting = warning
+resharper_xaml_invalid_member_type_highlighting = error
+resharper_xaml_invalid_resource_target_type_highlighting = error
+resharper_xaml_invalid_resource_type_highlighting = error
+resharper_xaml_invalid_type_highlighting = error
+resharper_xaml_language_level_highlighting = error
+resharper_xaml_mapped_path_highlighting_highlighting = hint
+resharper_xaml_method_arguments_will_be_ignored_highlighting = warning
+resharper_xaml_missing_grid_index_highlighting = warning
+resharper_xaml_overloads_collision_highlighting = warning
+resharper_xaml_parent_is_out_of_current_component_tree_highlighting = warning
+resharper_xaml_path_error_highlighting = warning
+resharper_xaml_possible_null_reference_exception_highlighting = suggestion
+resharper_xaml_redundant_attached_property_highlighting = warning
+resharper_xaml_redundant_binding_mode_attribute_highlighting = warning
+resharper_xaml_redundant_collection_property_highlighting = warning
+resharper_xaml_redundant_freeze_attribute_highlighting = warning
+resharper_xaml_redundant_grid_definitions_highlighting = warning
+resharper_xaml_redundant_grid_span_highlighting = warning
+resharper_xaml_redundant_modifiers_attribute_highlighting = warning
+resharper_xaml_redundant_namespace_alias_highlighting = warning
+resharper_xaml_redundant_name_attribute_highlighting = warning
+resharper_xaml_redundant_property_type_qualifier_highlighting = warning
+resharper_xaml_redundant_resource_highlighting = warning
+resharper_xaml_redundant_styled_value_highlighting = warning
+resharper_xaml_redundant_update_source_trigger_attribute_highlighting = warning
+resharper_xaml_redundant_xamarin_forms_class_declaration_highlighting = warning
+resharper_xaml_resource_file_path_case_mismatch_highlighting = warning
+resharper_xaml_routed_event_resolve_error_highlighting = warning
+resharper_xaml_static_resource_not_resolved_highlighting = warning
+resharper_xaml_style_class_not_found_highlighting = warning
+resharper_xaml_style_invalid_target_type_highlighting = error
+resharper_xaml_unexpected_element_highlighting = error
+resharper_xaml_unexpected_text_token_highlighting = error
+resharper_xaml_xaml_duplicate_device_family_type_view_highlighting_highlighting = error
+resharper_xaml_xaml_mismatched_device_family_view_clr_name_highlighting_highlighting = warning
+resharper_xaml_xaml_relative_source_default_mode_warning_highlighting_highlighting = warning
+resharper_xaml_xaml_unknown_device_family_type_highlighting_highlighting = warning
+resharper_xaml_xaml_xamarin_forms_data_type_and_binding_context_type_mismatched_highlighting_highlighting = warning
+resharper_xaml_x_key_attribute_disallowed_highlighting = error
+resharper_xunit_xunit_test_with_console_output_highlighting = warning
+resharper_yield_return_within_lock_highlighting = warning
+resharper_zero_index_from_end_highlighting = warning
+
+# Standard properties
+end_of_line = native
+
+[*.{cs,vb}]
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+end_of_line = crlf
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_prefer_collection_expression = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+[*.{cs,vb}]
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers = 
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers = 
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers = 
+
+# Naming styles
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix = 
+dotnet_naming_style.begins_with_i.word_separator = 
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix = 
+dotnet_naming_style.pascal_case.required_suffix = 
+dotnet_naming_style.pascal_case.word_separator = 
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix = 
+dotnet_naming_style.pascal_case.required_suffix = 
+dotnet_naming_style.pascal_case.word_separator = 
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+dotnet_style_require_accessibility_modifiers = never:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_code_quality_unused_parameters = all:suggestion
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+
+[*.{cshtml,htm,html,razor}]
+indent_style = tab
+indent_size = tab
+tab_width = 4
+
+[*.{asax,ascx,aspx,axaml,cs,master,paml,skin,vb,xaml,xamlx,xoml}]
+indent_style = space
+indent_size = 4
+tab_width = 4
+
+[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]
+indent_style = space
+indent_size = 2
+tab_width = 2
+
+[*.{appxmanifest,axaml,axml,build,config,cs,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,paml,proj,props,resw,resx,StyleCop,targets,tasks,vb,vbproj,xaml,xamlx,xml,xoml,xsd}]
+indent_style = space
+indent_size = 4
+tab_width = 4

+ 37 - 0
.filenesting.json

@@ -0,0 +1,37 @@
+{
+  "help": "https://go.microsoft.com/fwlink/?linkid=866610",
+  "root": true,
+
+  "dependentFileProviders": {
+    "add": {
+      "addedExtension": {},
+      "pathSegment": {
+        "add": {
+          ".*": [
+            ".config",
+            ".cs",
+            ".json",
+            ".resx"
+          ]
+        }
+      },
+      "extensionToExtension": {
+        "add": {
+          ".designer.cs": [
+            ".resx"
+          ],
+          ".cs.d.ts": [
+            ".cs"
+          ]
+        }
+      },
+      "fileToFile": {
+        "add": {
+          "package-lock.json": [
+            "package.json"
+          ]
+        }
+      }
+    }
+  }
+}

+ 42 - 39
.github/workflows/api-docs.yml

@@ -2,53 +2,56 @@ name: Build and publish API docs
 
 on:
   push:
-    branches: [main]
+    branches: [main, develop, v2_develop]
+
+permissions:
+  id-token: write 
+  pages: write
 
 jobs:
-  generate-docs:
+  deploy:
+    name: Build and Deploy API docs to github-pages ${{ github.ref_name }}
+    environment:
+      name: github-pages
+      url: ${{ steps.deployment.outputs.page_url }}
     runs-on: windows-latest
-
     steps:
     - name: Checkout
-      uses: actions/checkout@v3
-
-    - name: Setup .NET Core
-      uses: actions/[email protected]
-      with:
-        dotnet-version: 6.0.100
-    
-    - name: Setup DocFX
-      uses: crazy-max/ghaction-chocolatey@v2
-      with:
-        args: install docfx    
-
-    - name: Install dependencies
-      run: dotnet restore        
+      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      uses: actions/checkout@v4
 
     - name: DocFX Build
+      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
       working-directory: docfx
-      # https://stackoverflow.com/questions/56726429/how-to-run-multiple-commands-in-one-github-actions-docker
       run: |
-        rm ../docs -Recurse -Force -ErrorAction SilentlyContinue
-        docfx docfx.json
-      continue-on-error: false      
-
-    - name: Publish
-      if: github.event_name == 'push'
-      uses: peaceiris/actions-gh-pages@v3
+        dotnet tool install -g docfx
+        $env:DOCFX_SOURCE_BRANCH_NAME="${{ github.ref_name }}"
+        docfx metadata
+        docfx build
+      continue-on-error: false
+
+    - name: Setup Pages
+      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      uses: actions/configure-pages@v4
+      
+    - name: Upload artifact
+      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      uses: actions/upload-pages-artifact@v3
       with:
-        github_token: ${{ secrets.GITHUB_TOKEN }}
-        publish_dir: docs
-        force_orphan: true
-
-    # - name: Use docfx to build API Docs
-    #   uses: nikeee/[email protected]
-    #   with:
-    #     args: docfx/docfx.json
+        path: docfx/_site
+       
+    - name: Deploy to GitHub Pages
+      if: github.ref_name == 'main' ||  github.ref_name == 'develop'
+      id: deployment
+      uses: actions/deploy-pages@v4
+      with:
+        token: ${{ secrets.GITHUB_TOKEN }}
 
-    # # Publish generated site using GitHub Pages
-    # - uses: maxheld83/ghpages@master
-    #   name: Publish API Documentation on GitHub Pages
-    #   env:
-    #     BUILD_DIR: docs # docfx's default output directory is _site
-    #     GH_PAT: ${{ secrets.GH_PAT }} # See https://github.com/maxheld83/ghpages
+    - name: v2_develop Repository Dispatch ${{ github.ref_name }}
+      if: github.ref_name == 'v2_develop'
+      uses: peter-evans/repository-dispatch@v2
+      with:
+        token: ${{ secrets.V2DOCS_TOKEN }}
+        repository: gui-cs/Terminal.GuiV2Docs
+        event-type: v2_develop_push
+        client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'

+ 30 - 25
.github/workflows/dotnet-core.yml

@@ -2,22 +2,27 @@ name: Build & Test Terminal.Gui with .NET Core
 
 on:
   push:
-    branches: [ main, develop, v2_develop ]
+    branches: [ v2, v2_develop ]
+    paths-ignore:
+      - '**.md'
   pull_request:
-    branches: [ main, develop, v2_develop ]
-
+    branches: [ v2, v2_develop ]
+    paths-ignore:
+      - '**.md'
+      
 jobs:
   build_and_test:
 
     runs-on: ubuntu-latest
-
+    timeout-minutes: 10
     steps:
-    - uses: actions/checkout@v3
     
-    - name: Setup dotnet
-      uses: actions/setup-dotnet@v3
+    - uses: actions/checkout@v4
+
+    - name: Setup .NET Core
+      uses: actions/setup-dotnet@v4
       with:
-        dotnet-version: 7.0
+        dotnet-version: 8.x
         dotnet-quality: 'ga'
 
     - name: Install dependencies
@@ -30,23 +35,23 @@ jobs:
     - name: Test
       run: |
         sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
-        dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage"  --settings UnitTests/coverlet.runsettings
+        dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage"  --settings UnitTests/coverlet.runsettings --blame
         mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
 
     # Note: this step is currently not writing to the gist for some reason
-    - name: Create Test Coverage Badge
-      uses: simon-k/[email protected]
-      id: create_coverage_badge
-      with:
-        label: Unit Test Coverage
-        color: brightgreen
-        path: UnitTests/TestResults/coverage.opencover.xml
-        gist-filename: code-coverage.json
-        # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
-        gist-id: 90ef67a684cb71db1817921a970f8d27
-        gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
-
-    - name: Print Code Coverage
-      run: |
-        echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
-        echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
+    # - name: Create Test Coverage Badge
+    #   uses: simon-k/[email protected]
+    #   id: create_coverage_badge
+    #   with:
+    #     label: Unit Test Coverage
+    #     color: brightgreen
+    #     path: UnitTests/TestResults/coverage.opencover.xml
+    #     gist-filename: code-coverage.json
+    #     # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
+    #     gist-id: 90ef67a684cb71db1817921a970f8d27
+    #     gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
+
+    # - name: Print Code Coverage
+    #   run: |
+    #     echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
+    #     echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"

+ 42 - 48
.github/workflows/publish.yml

@@ -1,81 +1,75 @@
-name: Publish Terminal.Gui v2
+name: Publish Terminal.Gui
+
 on:
   push:
+    branches: [ main, develop, v2_release, v2_develop ]
     tags:
-      - v2.0.0-alpha.*
+      - v*
+    paths-ignore:
+      - '**.md'
 
 jobs:
   publish:
-    name: Build and Publish v2 to Nuget.org
+    name: Build and Publish to Nuget.org
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v3
+    - uses: actions/checkout@v4
       with:
-        fetch-depth: 0 #fetch-depth is needed for GitVersion
+        fetch-depth: 0 # fetch-depth is needed for GitVersion
 
-    - name: Install and calculate the new version with GitVersion 
+    - name: Install GitVersion 
       uses: gittools/actions/gitversion/setup@v0
       with:
-          versionSpec: '6.x'
+          versionSpec: '5.x'
           includePrerelease: true
 
     - name: Determine Version
-      uses: gittools/actions/gitversion/execute@v0
+      uses: gittools/actions/gitversion/execute@v1
       with:
-        useConfigFile: true      
+        useConfigFile: true
+        #additionalArguments: /b develop
       id: gitversion # step id used as reference for output values
 
-    - name: Display GitVersion outputs
-      run: |
-        echo "Version: ${{ steps.gitversion.outputs.SemVer }}"
-        echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.CommitsSinceVersionSource }}"
-
     - name: Setup dotnet
-      uses: actions/setup-dotnet@v3
+      uses: actions/setup-dotnet@v4
       with:
-        dotnet-version: 7.0
+        dotnet-version: 8.0
         dotnet-quality: 'ga'
-
+        
     - name: Install dependencies
       run: dotnet restore
 
     - name: Build Release
       run: |
         dotnet-gitversion /updateprojectfiles
-        dotnet build --no-restore -c Release
+        dotnet build ./Analyzers/Terminal.Gui.Analyzers.Internal --no-incremental --nologo --force --configuration Release
+        dotnet build --no-incremental --nologo --force --configuration Release
 
     - name: Pack
       run: dotnet pack -c Release --include-symbols -p:Version='${{ steps.gitversion.outputs.SemVer }}' 
 
-    #- name: Test to generate Code Coverage Report
-    #  run: |
-    #    sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
-    #    dotnet test --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings
-    #    mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
-
-    #- name: Create Test Coverage Badge
-    #  uses: simon-k/[email protected]
-    #  id: create_coverage_badge
-    #  with:
-    #    label: Unit Test Coverage
-    #    color: brightgreen
-    #    path: UnitTests/TestResults/coverage.opencover.xml
-    #    gist-filename: code-coverage.json
-    #    # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
-    #    gist-id: 90ef67a684cb71db1817921a970f8d27
-    #    gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
-
-    #- name: Print Code Coverage
-    #  run: |
-    #    echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
-    #    echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
-
+    # - name: Test to generate Code Coverage Report
+    #   run: |
+    #     sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
+    #     dotnet test --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings
+    #     mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
+
+    # - name: Create Test Coverage Badge
+    #   uses: simon-k/[email protected]
+    #   id: create_coverage_badge
+    #   with:
+    #     label: Unit Test Coverage
+    #     color: brightgreen
+    #     path: UnitTests/TestResults/coverage.opencover.xml
+    #     gist-filename: code-coverage.json
+    #     gist-id: 90ef67a684cb71db1817921a970f8d27
+    #     gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
+
+    # - name: Print Code Coverage
+    #   run: |
+    #     echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
+    #     echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
+        
     - name: Publish to NuGet.org
-      run: dotnet nuget push Terminal.Gui/bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
-
-    - name: Unlist from NuGet.org if it's an alpha
-      run: dotnet nuget delete  --non-interactive Terminal.Gui ${{ steps.gitversion.outputs.SemVer }} --api-key ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
-      if: contains(steps.gitversion.outputs.SemVer, 'alpha')
-
-
+      run: dotnet nuget push Terminal.Gui/bin/Release/Terminal.Gui.${{ steps.gitversion.outputs.SemVer }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} 

+ 49 - 15
.gitignore

@@ -1,29 +1,63 @@
-bin
-obj
-~$*
+# Build artifacts
+[Bb]in/
+[Oo]bj/
+[Rr]elease/
+[Dd]ebug/
+[Xx]64/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+
+# User-local settings and caches
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
 *.userprefs
+_ReSharper.**
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+.devcontainer/
+.vscode/
+.vs/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Roslyn generated cs files
+**.g.cs
+
+# Common temporary files
+~$*
 *~
-packages
-.vs
-# User-specific files
-*.user
+
+# NuGet Stuff
+*.nupkg
+*.snupkg
+# Exclude everything in packages directory except the packages/build directory
+**/[Pp]ackages/*
+!**/[Pp]ackages/build/
 
 # API Docs
 docfx/api
+docfx/_site
 
-# Never push ./docs folder - the gh-pages branch is now used to publish to GH Pages
-docs/
-
+# Test Results
 UnitTests/TestResults
 TestResults
 
-#git merge files
-*.orig
-
-.vscode/
+# git merge files
+.orig
+.theirs
+.ours
 
 demo.*
 
 *.deb
 
-*.tui/
+*.tui/
+
+*.dotCover

+ 33 - 0
.vsconfig

@@ -0,0 +1,33 @@
+{
+  "version": "1.0",
+  "components": [
+    "Microsoft.VisualStudio.Component.DependencyValidation.Community",
+    "Microsoft.VisualStudio.Component.CoreEditor",
+    "Microsoft.VisualStudio.Workload.CoreEditor",
+    "Microsoft.Net.Component.4.8.SDK",
+    "Microsoft.Net.Component.4.7.2.TargetingPack",
+    "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
+    "Microsoft.VisualStudio.Component.Roslyn.Compiler",
+    "Microsoft.Component.MSBuild",
+    "Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
+    "Microsoft.VisualStudio.Component.TextTemplating",
+    "Microsoft.VisualStudio.Component.NuGet",
+    "Microsoft.VisualStudio.Component.ManagedDesktop.Core",
+    "Microsoft.NetCore.Component.Runtime.8.0",
+    "Microsoft.NetCore.Component.SDK",
+    "Microsoft.VisualStudio.Component.FSharp",
+    "Microsoft.NetCore.Component.DevelopmentTools",
+    "Microsoft.VisualStudio.Component.AppInsights.Tools",
+    "Microsoft.VisualStudio.Component.Debugger.JustInTime",
+    "Microsoft.Net.Component.4.6.2.TargetingPack",
+    "Microsoft.Net.Component.4.8.1.TargetingPack",
+    "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
+    "Microsoft.VisualStudio.Component.NuGet.BuildTools",
+    "Microsoft.Net.Component.4.6.TargetingPack",
+    "Microsoft.VisualStudio.Component.VSSDK",
+    "Microsoft.VisualStudio.ComponentGroup.VisualStudioExtension.Prerequisites",
+    "Microsoft.Component.CodeAnalysis.SDK",
+    "Microsoft.VisualStudio.Workload.VisualStudioExtension"
+  ],
+  "extensions": []
+}

+ 10 - 0
Analyzers.slnf

@@ -0,0 +1,10 @@
+{
+  "solution": {
+    "path": "Terminal.sln",
+    "projects": [
+      "Analyzers\\Terminal.Gui.Analyzers.Internal.Debugging\\Terminal.Gui.Analyzers.Internal.Debugging.csproj",
+      "Analyzers\\Terminal.Gui.Analyzers.Internal.Tests\\Terminal.Gui.Analyzers.Internal.Tests.csproj",
+      "Analyzers\\Terminal.Gui.Analyzers.Internal\\Terminal.Gui.Analyzers.Internal.csproj",
+    ]
+  }
+}

+ 23 - 0
Analyzers/Directory.Build.props

@@ -0,0 +1,23 @@
+<Project>
+  <PropertyGroup>
+    <Nullable>enable</Nullable>
+    <AnalysisLevel>latest-recommended</AnalysisLevel>
+    <WarningLevel>8</WarningLevel>
+    <CharacterSet>UTF-8</CharacterSet>
+    <Deterministic>true</Deterministic>
+    <UTF8OutPut>true</UTF8OutPut>
+    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
+    <NoLogo>True</NoLogo>
+    <DefineTrace>True</DefineTrace>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
+    <PackageReference Include="JetBrains.ExternalAnnotations" Version="10.2.149" />
+  </ItemGroup>
+  <ItemGroup>
+      <Using Include="System.Buffers" />
+      <Using Include="System.Collections.Specialized" />
+      <Using Include="System.Numerics" />
+      <Using Include="System.Runtime.CompilerServices" />
+  </ItemGroup>
+</Project>

+ 23 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Program.cs

@@ -0,0 +1,23 @@
+using System.Diagnostics.CodeAnalysis;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Debugging;
+
+static class Program
+{
+    static void Main (string [] args)
+    {
+        
+    }
+}
+
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "It's not that deep")]
+public enum TestEnum
+{
+    Zero = 0,
+    One,
+    Two = 2,
+    Three,
+    Six = 6
+}

+ 25 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.9.2" PrivateAssets="all" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
+      <PrivateAssets>all</PrivateAssets>
+      <OutputItemType>Analyzer</OutputItemType>
+      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+
+</Project>

+ 42 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/EnumMemberValues.cs

@@ -0,0 +1,42 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+internal sealed class SignedEnumMemberValues
+{
+    internal const int Bit31 = ~0b_01111111_11111111_11111111_11111111;
+    internal const int Bit30 =  0b_01000000_00000000_00000000_00000000;
+    internal const int Bit29 =  0b_00100000_00000000_00000000_00000000;
+    internal const int Bit28 =  0b_00010000_00000000_00000000_00000000;
+    internal const int Bit27 =  0b_00001000_00000000_00000000_00000000;
+    internal const int Bit26 =  0b_00000100_00000000_00000000_00000000;
+    internal const int Bit25 =  0b_00000010_00000000_00000000_00000000;
+    internal const int Bit24 =  0b_00000001_00000000_00000000_00000000;
+    internal const int Bit23 =  0b_00000000_10000000_00000000_00000000;
+    internal const int Bit22 =  0b_00000000_01000000_00000000_00000000;
+    internal const int Bit21 =  0b_00000000_00100000_00000000_00000000;
+    internal const int Bit20 =  0b_00000000_00010000_00000000_00000000;
+    internal const int Bit19 =  0b_00000000_00001000_00000000_00000000;
+    internal const int Bit18 =  0b_00000000_00000100_00000000_00000000;
+    internal const int Bit17 =  0b_00000000_00000010_00000000_00000000;
+    internal const int Bit16 =  0b_00000000_00000001_00000000_00000000;
+    internal const int Bit15 =  0b_00000000_00000000_10000000_00000000;
+    internal const int Bit14 =  0b_00000000_00000000_01000000_00000000;
+    internal const int Bit13 =  0b_00000000_00000000_00100000_00000000;
+    internal const int Bit12 =  0b_00000000_00000000_00010000_00000000;
+    internal const int Bit11 =  0b_00000000_00000000_00001000_00000000;
+    internal const int Bit10 =  0b_00000000_00000000_00000100_00000000;
+    internal const int Bit09 =  0b_00000000_00000000_00000010_00000000;
+    internal const int Bit08 =  0b_00000000_00000000_00000001_00000000;
+    internal const int Bit07 =  0b_00000000_00000000_00000000_10000000;
+    internal const int Bit06 =  0b_00000000_00000000_00000000_01000000;
+    internal const int Bit05 =  0b_00000000_00000000_00000000_00100000;
+    internal const int Bit04 =  0b_00000000_00000000_00000000_00010000;
+    internal const int Bit03 =  0b_00000000_00000000_00000000_00001000;
+    internal const int Bit02 =  0b_00000000_00000000_00000000_00000100;
+    internal const int Bit01 =  0b_00000000_00000000_00000000_00000010;
+    internal const int Bit00 =  0b_00000000_00000000_00000000_00000001;
+    internal const int All_0 =  0;
+    internal const int All_1 =  ~All_0;
+    internal const int Alternating_01 = 0b_01010101_01010101_01010101_01010101;
+    internal const int Alternating_10 = ~Alternating_01;
+    internal const int EvenBytesHigh = 0b_00000000_11111111_00000000_11111111;
+    internal const int OddBytesHigh = ~EvenBytesHigh;
+}

+ 51 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum.cs

@@ -0,0 +1,51 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BasicEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 =  0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 =  0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 =  0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 51 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt.cs

@@ -0,0 +1,51 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BasicEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum_ExplicitInt
+{
+    Bit31 = BasicEnum_ExplicitInt.Bit31,
+    Bit30 = BasicEnum_ExplicitInt.Bit30,
+    Bit29 = BasicEnum_ExplicitInt.Bit29,
+    Bit28 = BasicEnum_ExplicitInt.Bit28,
+    Bit27 = BasicEnum_ExplicitInt.Bit27,
+    Bit26 = BasicEnum_ExplicitInt.Bit26,
+    Bit25 = BasicEnum_ExplicitInt.Bit25,
+    Bit24 = BasicEnum_ExplicitInt.Bit24,
+    Bit23 = BasicEnum_ExplicitInt.Bit23,
+    Bit22 = BasicEnum_ExplicitInt.Bit22,
+    Bit21 = BasicEnum_ExplicitInt.Bit21,
+    Bit20 = BasicEnum_ExplicitInt.Bit20,
+    Bit19 = BasicEnum_ExplicitInt.Bit19,
+    Bit18 = BasicEnum_ExplicitInt.Bit18,
+    Bit17 = BasicEnum_ExplicitInt.Bit17,
+    Bit16 = BasicEnum_ExplicitInt.Bit16,
+    Bit15 = BasicEnum_ExplicitInt.Bit15,
+    Bit14 = BasicEnum_ExplicitInt.Bit14,
+    Bit13 = BasicEnum_ExplicitInt.Bit13,
+    Bit12 = BasicEnum_ExplicitInt.Bit12,
+    Bit11 = BasicEnum_ExplicitInt.Bit11,
+    Bit10 = BasicEnum_ExplicitInt.Bit10,
+    Bit09 = BasicEnum_ExplicitInt.Bit09,
+    Bit08 = BasicEnum_ExplicitInt.Bit08,
+    Bit07 = BasicEnum_ExplicitInt.Bit07,
+    Bit06 = BasicEnum_ExplicitInt.Bit06,
+    Bit05 = BasicEnum_ExplicitInt.Bit05,
+    Bit04 = BasicEnum_ExplicitInt.Bit04,
+    Bit03 = BasicEnum_ExplicitInt.Bit03,
+    Bit02 = BasicEnum_ExplicitInt.Bit02,
+    Bit01 = BasicEnum_ExplicitInt.Bit01,
+    Bit00 = BasicEnum_ExplicitInt.Bit00,
+    All_0 = BasicEnum_ExplicitInt.All_0,
+    All_1 = BasicEnum_ExplicitInt.All_1,
+    Alternating_01 = BasicEnum_ExplicitInt.Alternating_01,
+    Alternating_10 = BasicEnum_ExplicitInt.Alternating_10,
+    EvenBytesHigh = BasicEnum_ExplicitInt.EvenBytesHigh,
+    OddBytesHigh = BasicEnum_ExplicitInt.OddBytesHigh
+}

+ 52 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt_NoFastIsDefined.cs

@@ -0,0 +1,52 @@
+// ReSharper disable EnumUnderlyingTypeIsInt
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BetterEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
+/// </summary>
+[GenerateEnumExtensionMethods (FastIsDefined = false)]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum_ExplicitInt_NoFastIsDefined : int
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 = 0b_01000000_00000000_00000000_00000000,
+    Bit29 = 0b_00100000_00000000_00000000_00000000,
+    Bit28 = 0b_00010000_00000000_00000000_00000000,
+    Bit27 = 0b_00001000_00000000_00000000_00000000,
+    Bit26 = 0b_00000100_00000000_00000000_00000000,
+    Bit25 = 0b_00000010_00000000_00000000_00000000,
+    Bit24 = 0b_00000001_00000000_00000000_00000000,
+    Bit23 = 0b_00000000_10000000_00000000_00000000,
+    Bit22 = 0b_00000000_01000000_00000000_00000000,
+    Bit21 = 0b_00000000_00100000_00000000_00000000,
+    Bit20 = 0b_00000000_00010000_00000000_00000000,
+    Bit19 = 0b_00000000_00001000_00000000_00000000,
+    Bit18 = 0b_00000000_00000100_00000000_00000000,
+    Bit17 = 0b_00000000_00000010_00000000_00000000,
+    Bit16 = 0b_00000000_00000001_00000000_00000000,
+    Bit15 = 0b_00000000_00000000_10000000_00000000,
+    Bit14 = 0b_00000000_00000000_01000000_00000000,
+    Bit13 = 0b_00000000_00000000_00100000_00000000,
+    Bit12 = 0b_00000000_00000000_00010000_00000000,
+    Bit11 = 0b_00000000_00000000_00001000_00000000,
+    Bit10 = 0b_00000000_00000000_00000100_00000000,
+    Bit09 = 0b_00000000_00000000_00000010_00000000,
+    Bit08 = 0b_00000000_00000000_00000001_00000000,
+    Bit07 = 0b_00000000_00000000_00000000_10000000,
+    Bit06 = 0b_00000000_00000000_00000000_01000000,
+    Bit05 = 0b_00000000_00000000_00000000_00100000,
+    Bit04 = 0b_00000000_00000000_00000000_00010000,
+    Bit03 = 0b_00000000_00000000_00000000_00001000,
+    Bit02 = 0b_00000000_00000000_00000000_00000100,
+    Bit01 = 0b_00000000_00000000_00000000_00000010,
+    Bit00 = 0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 51 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt.cs

@@ -0,0 +1,51 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BasicEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum_ExplicitUInt : uint
+{
+    Bit31 = 0b_10000000_00000000_00000000_00000000u,
+    Bit30 = 0b_01000000_00000000_00000000_00000000u,
+    Bit29 = 0b_00100000_00000000_00000000_00000000u,
+    Bit28 = 0b_00010000_00000000_00000000_00000000u,
+    Bit27 = 0b_00001000_00000000_00000000_00000000u,
+    Bit26 = 0b_00000100_00000000_00000000_00000000u,
+    Bit25 = 0b_00000010_00000000_00000000_00000000u,
+    Bit24 = 0b_00000001_00000000_00000000_00000000u,
+    Bit23 = 0b_00000000_10000000_00000000_00000000u,
+    Bit22 = 0b_00000000_01000000_00000000_00000000u,
+    Bit21 = 0b_00000000_00100000_00000000_00000000u,
+    Bit20 = 0b_00000000_00010000_00000000_00000000u,
+    Bit19 = 0b_00000000_00001000_00000000_00000000u,
+    Bit18 = 0b_00000000_00000100_00000000_00000000u,
+    Bit17 = 0b_00000000_00000010_00000000_00000000u,
+    Bit16 = 0b_00000000_00000001_00000000_00000000u,
+    Bit15 = 0b_00000000_00000000_10000000_00000000u,
+    Bit14 = 0b_00000000_00000000_01000000_00000000u,
+    Bit13 = 0b_00000000_00000000_00100000_00000000u,
+    Bit12 = 0b_00000000_00000000_00010000_00000000u,
+    Bit11 = 0b_00000000_00000000_00001000_00000000u,
+    Bit10 = 0b_00000000_00000000_00000100_00000000u,
+    Bit09 = 0b_00000000_00000000_00000010_00000000u,
+    Bit08 = 0b_00000000_00000000_00000001_00000000u,
+    Bit07 = 0b_00000000_00000000_00000000_10000000u,
+    Bit06 = 0b_00000000_00000000_00000000_01000000u,
+    Bit05 = 0b_00000000_00000000_00000000_00100000u,
+    Bit04 = 0b_00000000_00000000_00000000_00010000u,
+    Bit03 = 0b_00000000_00000000_00000000_00001000u,
+    Bit02 = 0b_00000000_00000000_00000000_00000100u,
+    Bit01 = 0b_00000000_00000000_00000000_00000010u,
+    Bit00 = 0b_00000000_00000000_00000000_00000001u,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 51 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt_NoFastIsDefined.cs

@@ -0,0 +1,51 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BetterEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
+/// </summary>
+[GenerateEnumExtensionMethods (FastIsDefined = false)]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum_ExplicitUInt_NoFastIsDefined : uint
+{
+    Bit31 = 0b_10000000_00000000_00000000_00000000u,
+    Bit30 = 0b_01000000_00000000_00000000_00000000u,
+    Bit29 = 0b_00100000_00000000_00000000_00000000u,
+    Bit28 = 0b_00010000_00000000_00000000_00000000u,
+    Bit27 = 0b_00001000_00000000_00000000_00000000u,
+    Bit26 = 0b_00000100_00000000_00000000_00000000u,
+    Bit25 = 0b_00000010_00000000_00000000_00000000u,
+    Bit24 = 0b_00000001_00000000_00000000_00000000u,
+    Bit23 = 0b_00000000_10000000_00000000_00000000u,
+    Bit22 = 0b_00000000_01000000_00000000_00000000u,
+    Bit21 = 0b_00000000_00100000_00000000_00000000u,
+    Bit20 = 0b_00000000_00010000_00000000_00000000u,
+    Bit19 = 0b_00000000_00001000_00000000_00000000u,
+    Bit18 = 0b_00000000_00000100_00000000_00000000u,
+    Bit17 = 0b_00000000_00000010_00000000_00000000u,
+    Bit16 = 0b_00000000_00000001_00000000_00000000u,
+    Bit15 = 0b_00000000_00000000_10000000_00000000u,
+    Bit14 = 0b_00000000_00000000_01000000_00000000u,
+    Bit13 = 0b_00000000_00000000_00100000_00000000u,
+    Bit12 = 0b_00000000_00000000_00010000_00000000u,
+    Bit11 = 0b_00000000_00000000_00001000_00000000u,
+    Bit10 = 0b_00000000_00000000_00000100_00000000u,
+    Bit09 = 0b_00000000_00000000_00000010_00000000u,
+    Bit08 = 0b_00000000_00000000_00000001_00000000u,
+    Bit07 = 0b_00000000_00000000_00000000_10000000u,
+    Bit06 = 0b_00000000_00000000_00000000_01000000u,
+    Bit05 = 0b_00000000_00000000_00000000_00100000u,
+    Bit04 = 0b_00000000_00000000_00000000_00010000u,
+    Bit03 = 0b_00000000_00000000_00000000_00001000u,
+    Bit02 = 0b_00000000_00000000_00000000_00000100u,
+    Bit01 = 0b_00000000_00000000_00000000_00000010u,
+    Bit00 = 0b_00000000_00000000_00000000_00000001u,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 51 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_NoFastIsDefined.cs

@@ -0,0 +1,51 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="BetterEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
+/// </summary>
+[GenerateEnumExtensionMethods (FastIsDefined = false)]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterEnum_NoFastIsDefined
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 =  0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 =  0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 =  0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 52 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum.cs

@@ -0,0 +1,52 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="FlagsEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[Flags]
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterFlagsEnum
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 = -0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 = -0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 = -0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 53 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitInt.cs

@@ -0,0 +1,53 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+/// <summary>
+///     Same as <see cref="FlagsEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[Flags]
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterFlagsEnum_ExplicitInt : int
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 = -0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 = -0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 = -0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 52 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitUInt.cs

@@ -0,0 +1,52 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Same as <see cref="FlagsEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
+/// </summary>
+[Flags]
+[GenerateEnumExtensionMethods]
+[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BetterFlagsEnum_ExplicitUInt : uint
+{
+    Bit31 = 0b_10000000_00000000_00000000_00000000u,
+    Bit30 = 0b_01000000_00000000_00000000_00000000u,
+    Bit29 = 0b_00100000_00000000_00000000_00000000u,
+    Bit28 = 0b_00010000_00000000_00000000_00000000u,
+    Bit27 = 0b_00001000_00000000_00000000_00000000u,
+    Bit26 = 0b_00000100_00000000_00000000_00000000u,
+    Bit25 = 0b_00000010_00000000_00000000_00000000u,
+    Bit24 = 0b_00000001_00000000_00000000_00000000u,
+    Bit23 = 0b_00000000_10000000_00000000_00000000u,
+    Bit22 = 0b_00000000_01000000_00000000_00000000u,
+    Bit21 = 0b_00000000_00100000_00000000_00000000u,
+    Bit20 = 0b_00000000_00010000_00000000_00000000u,
+    Bit19 = 0b_00000000_00001000_00000000_00000000u,
+    Bit18 = 0b_00000000_00000100_00000000_00000000u,
+    Bit17 = 0b_00000000_00000010_00000000_00000000u,
+    Bit16 = 0b_00000000_00000001_00000000_00000000u,
+    Bit15 = 0b_00000000_00000000_10000000_00000000u,
+    Bit14 = 0b_00000000_00000000_01000000_00000000u,
+    Bit13 = 0b_00000000_00000000_00100000_00000000u,
+    Bit12 = 0b_00000000_00000000_00010000_00000000u,
+    Bit11 = 0b_00000000_00000000_00001000_00000000u,
+    Bit10 = 0b_00000000_00000000_00000100_00000000u,
+    Bit09 = 0b_00000000_00000000_00000010_00000000u,
+    Bit08 = 0b_00000000_00000000_00000001_00000000u,
+    Bit07 = 0b_00000000_00000000_00000000_10000000u,
+    Bit06 = 0b_00000000_00000000_00000000_01000000u,
+    Bit05 = 0b_00000000_00000000_00000000_00100000u,
+    Bit04 = 0b_00000000_00000000_00000000_00010000u,
+    Bit03 = 0b_00000000_00000000_00000000_00001000u,
+    Bit02 = 0b_00000000_00000000_00000000_00000100u,
+    Bit01 = 0b_00000000_00000000_00000000_00000010u,
+    Bit00 = 0b_00000000_00000000_00000000_00000001u,
+    All_0  =  0,
+    All_1  = ~All_0,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = ~Alternating_01,
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+    OddBytesHigh = ~EvenBytesHigh,
+}

+ 48 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum.cs

@@ -0,0 +1,48 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Basic enum without explicitly-defined backing type and no attributes on the enum or any of its members.
+/// </summary>
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BasicEnum
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 =  0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 =  0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 =  0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = -1,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = unchecked((int)0b_10101010_10101010_10101010_10101010),
+    OddBytesHigh = unchecked((int)0b_11111111_00000000_11111111_00000000),
+    EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
+}

+ 50 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitInt.cs

@@ -0,0 +1,50 @@
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Basic enum with explicitly-defined backing type of int and no attributes on the enum or any of its members.
+/// </summary>
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BasicEnum_ExplicitInt : int
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 =  0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 =  0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 =  0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = -1,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101,
+    Alternating_10 = unchecked((int)0b_10101010_10101010_10101010_10101010),
+    OddBytesHigh = unchecked((int)0b_11111111_00000000_11111111_00000000),
+    EvenBytesHigh = unchecked((int)0b_00000000_11111111_00000000_11111111),
+}

+ 48 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitUint.cs

@@ -0,0 +1,48 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Basic enum with explicitly-defined backing type of uint and no attributes on the enum or any of its members.
+/// </summary>
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum BasicEnum_ExplicitUInt : uint
+{
+    Bit31 = 0b_10000000_00000000_00000000_00000000u,
+    Bit30 = 0b_01000000_00000000_00000000_00000000u,
+    Bit29 = 0b_00100000_00000000_00000000_00000000u,
+    Bit28 = 0b_00010000_00000000_00000000_00000000u,
+    Bit27 = 0b_00001000_00000000_00000000_00000000u,
+    Bit26 = 0b_00000100_00000000_00000000_00000000u,
+    Bit25 = 0b_00000010_00000000_00000000_00000000u,
+    Bit24 = 0b_00000001_00000000_00000000_00000000u,
+    Bit23 = 0b_00000000_10000000_00000000_00000000u,
+    Bit22 = 0b_00000000_01000000_00000000_00000000u,
+    Bit21 = 0b_00000000_00100000_00000000_00000000u,
+    Bit20 = 0b_00000000_00010000_00000000_00000000u,
+    Bit19 = 0b_00000000_00001000_00000000_00000000u,
+    Bit18 = 0b_00000000_00000100_00000000_00000000u,
+    Bit17 = 0b_00000000_00000010_00000000_00000000u,
+    Bit16 = 0b_00000000_00000001_00000000_00000000u,
+    Bit15 = 0b_00000000_00000000_10000000_00000000u,
+    Bit14 = 0b_00000000_00000000_01000000_00000000u,
+    Bit13 = 0b_00000000_00000000_00100000_00000000u,
+    Bit12 = 0b_00000000_00000000_00010000_00000000u,
+    Bit11 = 0b_00000000_00000000_00001000_00000000u,
+    Bit10 = 0b_00000000_00000000_00000100_00000000u,
+    Bit09 = 0b_00000000_00000000_00000010_00000000u,
+    Bit08 = 0b_00000000_00000000_00000001_00000000u,
+    Bit07 = 0b_00000000_00000000_00000000_10000000u,
+    Bit06 = 0b_00000000_00000000_00000000_01000000u,
+    Bit05 = 0b_00000000_00000000_00000000_00100000u,
+    Bit04 = 0b_00000000_00000000_00000000_00010000u,
+    Bit03 = 0b_00000000_00000000_00000000_00001000u,
+    Bit02 = 0b_00000000_00000000_00000000_00000100u,
+    Bit01 = 0b_00000000_00000000_00000000_00000010u,
+    Bit00 = 0b_00000000_00000000_00000000_00000001u,
+    All_0 = 0b_00000000_00000000_00000000_00000000u,
+    All_1 = 0b_11111111_11111111_11111111_11111111u,
+    Alternating_01 = 0b_01010101_01010101_01010101_01010101u,
+    Alternating_10 = 0b_10101010_10101010_10101010_10101010u,
+    OddBytesHigh   = 0b_11111111_00000000_11111111_00000000u,
+    EvenBytesHigh  = 0b_00000000_11111111_00000000_11111111u,
+}

+ 45 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum.cs

@@ -0,0 +1,45 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Flags enum without explicitly-defined backing type and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
+/// </summary>
+[Flags]
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum FlagsEnum
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 = -0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 = -0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 = -0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = -1
+}

+ 45 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitInt.cs

@@ -0,0 +1,45 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Flags enum with explicitly-defined backing type of int and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
+/// </summary>
+[Flags]
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum FlagsEnum_ExplicitInt : int
+{
+    Bit31 = -0b_10000000_00000000_00000000_00000000,
+    Bit30 =  0b_01000000_00000000_00000000_00000000,
+    Bit29 =  0b_00100000_00000000_00000000_00000000,
+    Bit28 =  0b_00010000_00000000_00000000_00000000,
+    Bit27 =  0b_00001000_00000000_00000000_00000000,
+    Bit26 =  0b_00000100_00000000_00000000_00000000,
+    Bit25 =  0b_00000010_00000000_00000000_00000000,
+    Bit24 =  0b_00000001_00000000_00000000_00000000,
+    Bit23 = -0b_00000000_10000000_00000000_00000000,
+    Bit22 =  0b_00000000_01000000_00000000_00000000,
+    Bit21 =  0b_00000000_00100000_00000000_00000000,
+    Bit20 =  0b_00000000_00010000_00000000_00000000,
+    Bit19 =  0b_00000000_00001000_00000000_00000000,
+    Bit18 =  0b_00000000_00000100_00000000_00000000,
+    Bit17 =  0b_00000000_00000010_00000000_00000000,
+    Bit16 =  0b_00000000_00000001_00000000_00000000,
+    Bit15 = -0b_00000000_00000000_10000000_00000000,
+    Bit14 =  0b_00000000_00000000_01000000_00000000,
+    Bit13 =  0b_00000000_00000000_00100000_00000000,
+    Bit12 =  0b_00000000_00000000_00010000_00000000,
+    Bit11 =  0b_00000000_00000000_00001000_00000000,
+    Bit10 =  0b_00000000_00000000_00000100_00000000,
+    Bit09 =  0b_00000000_00000000_00000010_00000000,
+    Bit08 =  0b_00000000_00000000_00000001_00000000,
+    Bit07 = -0b_00000000_00000000_00000000_10000000,
+    Bit06 =  0b_00000000_00000000_00000000_01000000,
+    Bit05 =  0b_00000000_00000000_00000000_00100000,
+    Bit04 =  0b_00000000_00000000_00000000_00010000,
+    Bit03 =  0b_00000000_00000000_00000000_00001000,
+    Bit02 =  0b_00000000_00000000_00000000_00000100,
+    Bit01 =  0b_00000000_00000000_00000000_00000010,
+    Bit00 =  0b_00000000_00000000_00000000_00000001,
+    All_0  =  0,
+    All_1  = -1
+}

+ 45 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitUInt.cs

@@ -0,0 +1,45 @@
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
+
+/// <summary>
+///     Flags enum with explicitly-defined backing type of uint and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
+/// </summary>
+[Flags]
+[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
+[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
+public enum FlagsEnum_ExplicitUInt : uint
+{
+    Bit31 = 0b_10000000_00000000_00000000_00000000u,
+    Bit30 = 0b_01000000_00000000_00000000_00000000u,
+    Bit29 = 0b_00100000_00000000_00000000_00000000u,
+    Bit28 = 0b_00010000_00000000_00000000_00000000u,
+    Bit27 = 0b_00001000_00000000_00000000_00000000u,
+    Bit26 = 0b_00000100_00000000_00000000_00000000u,
+    Bit25 = 0b_00000010_00000000_00000000_00000000u,
+    Bit24 = 0b_00000001_00000000_00000000_00000000u,
+    Bit23 = 0b_00000000_10000000_00000000_00000000u,
+    Bit22 = 0b_00000000_01000000_00000000_00000000u,
+    Bit21 = 0b_00000000_00100000_00000000_00000000u,
+    Bit20 = 0b_00000000_00010000_00000000_00000000u,
+    Bit19 = 0b_00000000_00001000_00000000_00000000u,
+    Bit18 = 0b_00000000_00000100_00000000_00000000u,
+    Bit17 = 0b_00000000_00000010_00000000_00000000u,
+    Bit16 = 0b_00000000_00000001_00000000_00000000u,
+    Bit15 = 0b_00000000_00000000_10000000_00000000u,
+    Bit14 = 0b_00000000_00000000_01000000_00000000u,
+    Bit13 = 0b_00000000_00000000_00100000_00000000u,
+    Bit12 = 0b_00000000_00000000_00010000_00000000u,
+    Bit11 = 0b_00000000_00000000_00001000_00000000u,
+    Bit10 = 0b_00000000_00000000_00000100_00000000u,
+    Bit09 = 0b_00000000_00000000_00000010_00000000u,
+    Bit08 = 0b_00000000_00000000_00000001_00000000u,
+    Bit07 = 0b_00000000_00000000_00000000_10000000u,
+    Bit06 = 0b_00000000_00000000_00000000_01000000u,
+    Bit05 = 0b_00000000_00000000_00000000_00100000u,
+    Bit04 = 0b_00000000_00000000_00000000_00010000u,
+    Bit03 = 0b_00000000_00000000_00000000_00001000u,
+    Bit02 = 0b_00000000_00000000_00000000_00000100u,
+    Bit01 = 0b_00000000_00000000_00000000_00000010u,
+    Bit00 = 0b_00000000_00000000_00000000_00000001u,
+    All_0 = 0b_00000000_00000000_00000000_00000000u,
+    All_1 = 0b_11111111_11111111_11111111_11111111u
+}

+ 306 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGeneratorTests.cs

@@ -0,0 +1,306 @@
+using System.Collections.Concurrent;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using NUnit.Framework.Interfaces;
+using NUnit.Framework.Internal;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+using Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
+// ReSharper disable InconsistentNaming
+
+namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions;
+
+[TestFixture]
+[Category ("Source Generators")]
+[TestOf (typeof (EnumExtensionMethodsIncrementalGenerator))]
+[Parallelizable (ParallelScope.Children)]
+[SuppressMessage ("ReSharper", "ExceptionNotDocumented")]
+public class EnumExtensionMethodsIncrementalGeneratorTests
+{
+    private static bool _isInitialized;
+
+    /// <summary>All enum types declared in the test assembly.</summary>
+    private static readonly ObservableCollection<Type> _allEnumTypes = [];
+
+    /// <summary>
+    ///     All enum types without a <see cref="GenerateEnumExtensionMethodsAttribute"/>, <see cref="_allEnumTypes"/>
+    /// </summary>
+    private static readonly HashSet<Type> _boringEnumTypes = [];
+
+    /// <summary>All extension classes generated for enums with our attribute.</summary>
+    private static readonly ObservableCollection<Type> _enumExtensionClasses = [];
+
+    private static readonly ConcurrentDictionary<Type, EnumData> _extendedEnumTypeMappings = [];
+    private static IEnumerable<Type> ExtendedEnumTypes => _extendedEnumTypeMappings.Keys;
+
+    private static readonly ReaderWriterLockSlim _initializationLock = new ();
+
+    private static IEnumerable<AssemblyExtendedEnumTypeAttribute> GetAssemblyExtendedEnumTypeAttributes () =>
+        Assembly.GetExecutingAssembly ()
+                .GetCustomAttributes<AssemblyExtendedEnumTypeAttribute> ();
+
+    private static IEnumerable<TestCaseData> Get_AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute_Cases ()
+    {
+        return GetAssemblyExtendedEnumTypeAttributes ()
+            .Select (
+                     static attr => new TestCaseData (attr)
+                     {
+                         TestName = $"{nameof (AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute)}({attr.EnumType.Name},{attr.ExtensionClass.Name})",
+                         HasExpectedResult = true,
+                         ExpectedResult = true
+                     });
+    }
+
+    [Test]
+    [Category ("Attributes")]
+    [TestCaseSource (nameof (Get_AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute_Cases))]
+    public bool AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute (AssemblyExtendedEnumTypeAttribute attr)
+    {
+        Assume.That (attr, Is.Not.Null);
+        Assume.That (attr.EnumType, Is.Not.Null);
+        Assume.That (attr.EnumType.IsEnum);
+
+        return attr.EnumType.IsDefined (typeof (GenerateEnumExtensionMethodsAttribute));
+    }
+
+    [Test]
+    [Category("Attributes")]
+    public void AssemblyExtendedEnumTypeAttribute_ExtensionClassHasExpectedReverseMappingAttribute ([ValueSource(nameof(GetAssemblyExtendedEnumTypeAttributes))]AssemblyExtendedEnumTypeAttribute attr)
+    {
+        Assume.That (attr, Is.Not.Null);
+        Assume.That (attr.ExtensionClass, Is.Not.Null);
+        Assume.That (attr.ExtensionClass.IsClass);
+        Assume.That (attr.ExtensionClass.IsSealed);
+
+        Assert.That (attr.ExtensionClass.IsDefined (typeof (ExtensionsForEnumTypeAttribute<>)));
+    }
+
+    [Test]
+    [Category("Attributes")]
+    public void ExtendedEnum_AssemblyHasMatchingAttribute ([ValueSource(nameof(GetExtendedEnum_EnumData))]EnumData enumData)
+    {
+        Assume.That (enumData, Is.Not.Null);
+        Assume.That (enumData.EnumType, Is.Not.Null);
+        Assume.That (enumData.EnumType.IsEnum);
+
+        Assert.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+    }
+
+    [Test]
+    public void BoringEnum_DoesNotHaveExtensions ([ValueSource (nameof (_boringEnumTypes))] Type enumType)
+    {
+        Assume.That (enumType.IsEnum);
+
+        Assert.That (enumType, Has.No.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+    }
+
+    [Test]
+    public void ExtendedEnum_FastIsDefinedFalse_DoesNotHaveFastIsDefined ([ValueSource (nameof (GetExtendedEnumTypes_FastIsDefinedFalse))] EnumData enumData)
+    {
+        Assume.That (enumData.EnumType.IsEnum);
+        Assume.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+        Assume.That (enumData.GeneratorAttribute, Is.Not.Null);
+        Assume.That (enumData.GeneratorAttribute, Is.EqualTo (enumData.EnumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> ()));
+        Assume.That (enumData.GeneratorAttribute, Has.Property ("FastIsDefined").False);
+        Assume.That (enumData.ExtensionClass, Is.Not.Null);
+
+        Assert.That (enumData.ExtensionClass!.GetMethod ("FastIsDefined"), Is.Null);
+    }
+
+    [Test]
+    public void ExtendedEnum_StaticExtensionClassExists ([ValueSource (nameof (ExtendedEnumTypes))] Type enumType)
+    {
+        Assume.That (enumType.IsEnum);
+        Assume.That (enumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+        Assume.That (enumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+    }
+
+    [Test]
+    public void ExtendedEnum_FastIsDefinedTrue_HasFastIsDefined ([ValueSource (nameof (GetExtendedEnumTypes_FastIsDefinedTrue))] EnumData enumData)
+    {
+        Assume.That (enumData.EnumType, Is.Not.Null);
+        Assume.That (enumData.EnumType.IsEnum);
+        Assume.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
+        Assume.That (enumData.ExtensionClass, Is.Not.Null);
+        TypeWrapper extensionClassTypeInfo = new(enumData.ExtensionClass!);
+        Assume.That (extensionClassTypeInfo.IsStaticClass);
+        Assume.That (enumData.GeneratorAttribute, Is.Not.Null);
+        Assume.That (enumData.GeneratorAttribute, Is.EqualTo (enumData.EnumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> ()));
+        Assume.That (enumData.GeneratorAttribute, Has.Property ("FastIsDefined").True);
+
+        MethodInfo? fastIsDefinedMethod = enumData.ExtensionClass!.GetMethod ("FastIsDefined");
+
+        Assert.That (fastIsDefinedMethod, Is.Not.Null);
+        Assert.That (fastIsDefinedMethod, Has.Attribute<ExtensionAttribute> ());
+        extensionClassTypeInfo.GetMethodsWithAttribute<ExtensionAttribute> (false);
+
+
+    }
+
+    private static IEnumerable<EnumData> GetExtendedEnum_EnumData ()
+    {
+        _initializationLock.EnterUpgradeableReadLock ();
+
+        try
+        {
+            if (!_isInitialized)
+            {
+                Initialize ();
+            }
+
+            return _extendedEnumTypeMappings.Values;
+        }
+        finally
+        {
+            _initializationLock.ExitUpgradeableReadLock ();
+        }
+    }
+
+    private static IEnumerable<EnumData> GetExtendedEnumTypes_FastIsDefinedFalse ()
+    {
+        _initializationLock.EnterUpgradeableReadLock ();
+
+        try
+        {
+            if (!_isInitialized)
+            {
+                Initialize ();
+            }
+
+            return _extendedEnumTypeMappings.Values.Where (static t => t.GeneratorAttribute?.FastIsDefined is false);
+        }
+        finally
+        {
+            _initializationLock.ExitUpgradeableReadLock ();
+        }
+    }
+
+    private static IEnumerable<EnumData> GetExtendedEnumTypes_FastIsDefinedTrue ()
+    {
+        _initializationLock.EnterUpgradeableReadLock ();
+
+        try
+        {
+            if (!_isInitialized)
+            {
+                Initialize ();
+            }
+
+            return _extendedEnumTypeMappings.Values.Where (static t => t.GeneratorAttribute?.FastIsDefined is true);
+        }
+        finally
+        {
+            _initializationLock.ExitUpgradeableReadLock ();
+        }
+    }
+
+    private static void Initialize ()
+    {
+        if (!_initializationLock.IsUpgradeableReadLockHeld || !_initializationLock.TryEnterWriteLock (5000))
+        {
+            return;
+        }
+
+        try
+        {
+            if (_isInitialized)
+            {
+                return;
+            }
+
+            _allEnumTypes.CollectionChanged += AllEnumTypes_CollectionChanged;
+            _enumExtensionClasses.CollectionChanged += EnumExtensionClasses_OnCollectionChanged;
+
+            Type [] allAssemblyTypes = Assembly
+                                       .GetExecutingAssembly ()
+                                       .GetTypes ();
+
+            foreach (Type type in allAssemblyTypes.Where (IsDefinedEnum))
+            {
+                _allEnumTypes.Add (type);
+            }
+
+            foreach (Type type in allAssemblyTypes.Where (HasExtensionForEnumTypeAttribute))
+            {
+                _enumExtensionClasses.Add (type);
+            }
+
+            _isInitialized = true;
+        }
+        finally
+        {
+            _initializationLock.ExitWriteLock ();
+        }
+
+        return;
+
+        static bool IsDefinedEnum (Type t) { return t is { IsEnum: true, IsGenericType: false, IsConstructedGenericType: false, IsTypeDefinition: true }; }
+
+        static void AllEnumTypes_CollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
+        {
+            if (e.Action is not NotifyCollectionChangedAction.Add and not NotifyCollectionChangedAction.Replace || e.NewItems is null)
+            {
+                return;
+            }
+
+            foreach (Type enumType in e.NewItems.OfType<Type> ())
+            {
+                if (enumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> () is not { } generatorAttribute)
+                {
+                    _boringEnumTypes.Add (enumType);
+
+                    continue;
+                }
+
+                _extendedEnumTypeMappings.AddOrUpdate (
+                                               enumType,
+                                               CreateNewEnumData,
+                                               UpdateGeneratorAttributeProperty,
+                                               generatorAttribute);
+            }
+        }
+
+        static EnumData CreateNewEnumData (Type tEnum, GenerateEnumExtensionMethodsAttribute attr) { return new (tEnum, attr); }
+
+        static EnumData UpdateGeneratorAttributeProperty (Type tEnum, EnumData data, GenerateEnumExtensionMethodsAttribute attr)
+        {
+            data.GeneratorAttribute ??= attr;
+
+            return data;
+        }
+
+        static void EnumExtensionClasses_OnCollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
+        {
+            if (e.Action != NotifyCollectionChangedAction.Add)
+            {
+                return;
+            }
+
+            foreach (Type extensionClassType in e.NewItems!.OfType<Type> ())
+            {
+                if (extensionClassType.GetCustomAttribute (typeof (ExtensionsForEnumTypeAttribute<>), false) is not IExtensionsForEnumTypeAttributes
+                        {
+                            EnumType.IsEnum: true
+                        } extensionForAttribute)
+                {
+                    continue;
+                }
+
+                _extendedEnumTypeMappings [extensionForAttribute.EnumType].ExtensionClass ??= extensionClassType;
+            }
+        }
+    }
+
+    private static bool HasExtensionForEnumTypeAttribute (Type t) => t.IsClass && t.IsDefined (typeof (ExtensionsForEnumTypeAttribute<>));
+
+    public sealed record EnumData (
+        Type EnumType,
+        GenerateEnumExtensionMethodsAttribute? GeneratorAttribute = null,
+        Type? ExtensionClass = null,
+        IExtensionsForEnumTypeAttributes? ExtensionForEnumTypeAttribute = null)
+    {
+        public Type? ExtensionClass { get; set; } = ExtensionClass;
+
+        public IExtensionsForEnumTypeAttributes? ExtensionForEnumTypeAttribute { get; set; } = ExtensionForEnumTypeAttribute;
+        public GenerateEnumExtensionMethodsAttribute? GeneratorAttribute { get; set; } = GeneratorAttribute;
+    }
+}

+ 3 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/GlobalSuppressions.cs

@@ -0,0 +1,3 @@
+[assembly: SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Scope = "module", Justification = "Naming is intentional.")]
+[assembly: SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Scope = "module", Justification = "Order is intentional.")]
+[assembly: SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Scope = "module", Justification = "Naming is intentional.")]

+ 111 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/IndentedTextWriterExtensionsTests.cs

@@ -0,0 +1,111 @@
+using System.CodeDom.Compiler;
+using System.Text;
+
+namespace Terminal.Gui.Analyzers.Internal.Tests;
+
+[TestFixture]
+[Category ("Extension Methods")]
+[TestOf (typeof (IndentedTextWriterExtensions))]
+[Parallelizable (ParallelScope.Children)]
+public class IndentedTextWriterExtensionsTests
+{
+    [Test]
+    public void Pop_Decrements ()
+    {
+        StringBuilder sb = new (0);
+        using var sw = new StringWriter (sb);
+        using var writer = new IndentedTextWriter (sw);
+        writer.Indent = 5;
+
+        Assume.That (writer.Indent, Is.EqualTo (5));
+
+        writer.Pop ();
+        Assert.That (writer.Indent, Is.EqualTo (4));
+    }
+
+    [Test]
+    public void Pop_WithClosing_WritesAndPops ([Values ("}", ")", "]")] string scopeClosing)
+    {
+        StringBuilder sb = new (256);
+        using var sw = new StringWriter (sb);
+        using var writer = new IndentedTextWriter (sw, "  ");
+        writer.Indent = 5;
+        writer.Flush ();
+        Assume.That (writer.Indent, Is.EqualTo (5));
+        Assume.That (sb.Length, Is.Zero);
+
+        // Need to write something first, or IndentedTextWriter won't emit the indentation for the first call.
+        // So we'll write an empty line.
+        writer.WriteLine ();
+
+        for (ushort indentCount = 5; indentCount > 0;)
+        {
+            writer.Pop (scopeClosing);
+            Assert.That (writer.Indent, Is.EqualTo (--indentCount));
+        }
+
+        writer.Flush ();
+        var result = sb.ToString ();
+
+        Assert.That (
+                     result,
+                     Is.EqualTo (
+                                 $"""
+                                  
+                                          {scopeClosing}
+                                        {scopeClosing}
+                                      {scopeClosing}
+                                    {scopeClosing}
+                                  {scopeClosing}
+
+                                  """));
+    }
+
+    [Test]
+    public void Push_Increments ()
+    {
+        StringBuilder sb = new (32);
+        using var sw = new StringWriter (sb);
+        using var writer = new IndentedTextWriter (sw, "  ");
+
+        for (int indentCount = 0; indentCount < 5; indentCount++)
+        {
+            writer.Push ();
+            Assert.That (writer.Indent, Is.EqualTo (indentCount + 1));
+        }
+    }
+
+    [Test]
+    public void Push_WithOpening_WritesAndPushes ([Values ('{', '(', '[')] char scopeOpening)
+    {
+        StringBuilder sb = new (256);
+        using var sw = new StringWriter (sb);
+        using var writer = new IndentedTextWriter (sw, "  ");
+
+        for (ushort indentCount = 0; indentCount < 5;)
+        {
+            writer.Push ("Opening UninterestingEnum", scopeOpening);
+            Assert.That (writer.Indent, Is.EqualTo (++indentCount));
+        }
+
+        writer.Flush ();
+        var result = sb.ToString ();
+
+        Assert.That (
+                     result,
+                     Is.EqualTo (
+                                 $"""
+                                  Opening UninterestingEnum
+                                  {scopeOpening}
+                                    Opening UninterestingEnum
+                                    {scopeOpening}
+                                      Opening UninterestingEnum
+                                      {scopeOpening}
+                                        Opening UninterestingEnum
+                                        {scopeOpening}
+                                          Opening UninterestingEnum
+                                          {scopeOpening}
+
+                                  """));
+    }
+}

+ 48 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj

@@ -0,0 +1,48 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <LangVersion>12</LangVersion>
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <DebugType>portable</DebugType>
+    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+    <PackageReference Include="NUnit" Version="4.1.0" />
+    <PackageReference Include="NUnit.Analyzers" Version="4.2.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
+      <PrivateAssets>all</PrivateAssets>
+      <OutputItemType>Analyzer</OutputItemType>
+      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="NUnit.Framework" />
+    <Using Include="Terminal.Gui" />
+    <Using Include="Terminal.Gui.Analyzers" />
+    <Using Include="Terminal.Gui.Analyzers.Internal" />
+    <Using Include="System.Diagnostics.CodeAnalysis" />
+  </ItemGroup>
+
+</Project>

+ 3 - 0
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj.DotSettings

@@ -0,0 +1,3 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generators_005Cenumextensions_005Cenumdefinitions_005Cwithgenerator/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generators_005Cenumextensions_005Cenumdefinitions_005Cwithoutgenerator/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

+ 20 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/AccessibilityExtensions.cs

@@ -0,0 +1,20 @@
+using Microsoft.CodeAnalysis;
+
+namespace Terminal.Gui.Analyzers.Internal;
+
+internal static class AccessibilityExtensions
+{
+    internal static string ToCSharpString (this Accessibility value)
+    {
+        return value switch
+        {
+            Accessibility.Public => "public",
+            Accessibility.Internal => "internal",
+            Accessibility.Private => "private",
+            Accessibility.Protected => "protected",
+            Accessibility.ProtectedAndInternal => "private protected",
+            Accessibility.ProtectedOrInternal => "protected internal",
+            _ => string.Empty
+        };
+    }
+}

+ 8 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Shipped.md

@@ -0,0 +1,8 @@
+## Release 1.0
+
+### New Rules
+
+Rule ID | Category | Severity | Notes
+--------|----------|----------|--------------------
+TG0001  |   Usage  |  Error   | TG0001_GlobalNamespaceNotSupported
+TG0002  |   Usage  |  Error   | TG0002_UnderlyingTypeNotSupported

+ 4 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Unshipped.md

@@ -0,0 +1,4 @@
+### New Rules
+
+Rule ID | Category | Severity | Notes
+--------|----------|----------|--------------------

+ 117 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Analyzers/GenerateEnumExtensionMethodsAttributeAnalyzer.cs

@@ -0,0 +1,117 @@
+#define JETBRAINS_ANNOTATIONS
+using System.Collections.Immutable;
+using System.Linq;
+using JetBrains.Annotations;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+using Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
+
+namespace Terminal.Gui.Analyzers.Internal.Analyzers;
+
+/// <summary>
+///     Design-time analyzer that checks for proper use of <see cref="GenerateEnumExtensionMethodsAttribute"/>.
+/// </summary>
+[DiagnosticAnalyzer (LanguageNames.CSharp)]
+[UsedImplicitly]
+internal sealed class GenerateEnumExtensionMethodsAttributeAnalyzer : DiagnosticAnalyzer
+{
+    // ReSharper disable once InconsistentNaming
+    private static readonly DiagnosticDescriptor TG0001_GlobalNamespaceNotSupported = new (
+                                                                                           // ReSharper restore InconsistentNaming
+                                                                                           "TG0001",
+                                                                                           $"{nameof (GenerateEnumExtensionMethodsAttribute)} not supported on global enums",
+                                                                                           "{0} is in the global namespace, which is not supported by the source generator ({1}) used by {2}. Move the enum to a namespace or remove the attribute.",
+                                                                                           "Usage",
+                                                                                           DiagnosticSeverity.Error,
+                                                                                           true,
+                                                                                           null,
+                                                                                           null,
+                                                                                           WellKnownDiagnosticTags.NotConfigurable,
+                                                                                           WellKnownDiagnosticTags.Compiler);
+
+    // ReSharper disable once InconsistentNaming
+    private static readonly DiagnosticDescriptor TG0002_UnderlyingTypeNotSupported = new (
+                                                                                          "TG0002",
+                                                                                          $"{nameof (GenerateEnumExtensionMethodsAttribute)} not supported for this enum type",
+                                                                                          "{0} has an underlying type of {1}, which is not supported by the source generator ({2}) used by {3}. Only enums backed by int or uint are supported.",
+                                                                                          "Usage",
+                                                                                          DiagnosticSeverity.Error,
+                                                                                          true,
+                                                                                          null,
+                                                                                          null,
+                                                                                          WellKnownDiagnosticTags.NotConfigurable,
+                                                                                          WellKnownDiagnosticTags.Compiler);
+
+    /// <inheritdoc/>
+    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
+        [
+            TG0001_GlobalNamespaceNotSupported,
+            TG0002_UnderlyingTypeNotSupported
+        ];
+
+    /// <inheritdoc/>
+    public override void Initialize (AnalysisContext context)
+    {
+        context.ConfigureGeneratedCodeAnalysis (GeneratedCodeAnalysisFlags.None);
+        context.EnableConcurrentExecution ();
+
+        context.RegisterSyntaxNodeAction (CheckAttributeLocations, SyntaxKind.EnumDeclaration);
+
+        return;
+
+        static void CheckAttributeLocations (SyntaxNodeAnalysisContext analysisContext)
+        {
+            ISymbol? symbol = analysisContext.SemanticModel.GetDeclaredSymbol (analysisContext.Node) as INamedTypeSymbol;
+
+            if (symbol is not INamedTypeSymbol { EnumUnderlyingType: { } } enumSymbol)
+            {
+                // Somehow not even an enum declaration.
+                // Skip it.
+                return;
+            }
+
+            // Check attributes for those we care about and react accordingly.
+            foreach (AttributeData attributeData in enumSymbol.GetAttributes ())
+            {
+                if (attributeData.AttributeClass?.Name != nameof (GenerateEnumExtensionMethodsAttribute))
+                {
+                    // Just skip - not an interesting attribute.
+                    continue;
+                }
+
+                // Check enum underlying type for supported types (int and uint, currently)
+                // Report TG0002 if unsupported underlying type.
+                if (enumSymbol.EnumUnderlyingType is not { SpecialType: SpecialType.System_Int32 or SpecialType.System_UInt32 })
+                {
+                    analysisContext.ReportDiagnostic (
+                                                      Diagnostic.Create (
+                                                                         TG0002_UnderlyingTypeNotSupported,
+                                                                         enumSymbol.Locations.FirstOrDefault (),
+                                                                         enumSymbol.Name,
+                                                                         enumSymbol.EnumUnderlyingType.Name,
+                                                                         nameof (EnumExtensionMethodsIncrementalGenerator),
+                                                                         nameof (GenerateEnumExtensionMethodsAttribute)
+                                                                        )
+                                                     );
+                }
+
+                // Check enum namespace (only non-global supported, currently)
+                // Report TG0001 if in the global namespace.
+                if (enumSymbol.ContainingSymbol is not INamespaceSymbol { IsGlobalNamespace: false })
+                {
+                    analysisContext.ReportDiagnostic (
+                                                      Diagnostic.Create (
+                                                                         TG0001_GlobalNamespaceNotSupported,
+                                                                         enumSymbol.Locations.FirstOrDefault (),
+                                                                         enumSymbol.Name,
+                                                                         nameof (EnumExtensionMethodsIncrementalGenerator),
+                                                                         nameof (GenerateEnumExtensionMethodsAttribute)
+                                                                        )
+                                                     );
+                }
+            }
+        }
+    }
+}

+ 3 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/ApiCompatExcludedAttributes.txt

@@ -0,0 +1,3 @@
+N:System.Runtime.CompilerServices
+N:System.Diagnostics.CodeAnalysis
+N:System.Numerics

+ 27 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs

@@ -0,0 +1,27 @@
+// ReSharper disable ClassNeverInstantiated.Global
+// ReSharper disable once RedundantNullableDirective
+#nullable enable
+
+namespace Terminal.Gui.Analyzers.Internal.Attributes;
+
+/// <summary>Assembly attribute declaring a known pairing of an <see langword="enum" /> type to an extension class.</summary>
+/// <remarks>This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported.</remarks>
+[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]
+internal sealed class AssemblyExtendedEnumTypeAttribute : System.Attribute
+{
+    /// <summary>Creates a new instance of <see cref="AssemblyExtendedEnumTypeAttribute" /> from the provided parameters.</summary>
+    /// <param name="enumType">The <see cref="System.Type" /> of an <see langword="enum" /> decorated with a <see cref="GenerateEnumExtensionMethodsAttribute" />.</param>
+    /// <param name="extensionClass">The <see cref="System.Type" /> of the <see langword="class" /> decorated with an <see cref="ExtensionsForEnumTypeAttribute{TEnum}" /> referring to the same type as <paramref name="enumType" />.</param>
+    public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass)
+    {
+        EnumType = enumType;
+        ExtensionClass = extensionClass;
+    }
+    ///<summary>An <see langword="enum" /> type that has been extended by Terminal.Gui source generators.</summary>
+    public System.Type EnumType { get; init; }
+    ///<summary>A class containing extension methods for <see cref="EnumType"/>.</summary>
+    public System.Type ExtensionClass { get; init; }
+
+    /// <inheritdoc />
+    public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}";
+}

+ 37 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/ExtensionsForEnumTypeAttribute.cs

@@ -0,0 +1,37 @@
+// ReSharper disable RedundantNameQualifier
+// ReSharper disable RedundantNullableDirective
+// ReSharper disable UnusedType.Global
+#pragma warning disable IDE0001, IDE0240
+#nullable enable
+
+namespace Terminal.Gui.Analyzers.Internal.Attributes;
+
+/// <summary>
+///     Attribute written by the source generator for <see langword="enum" /> extension classes, for easier analysis and reflection.
+/// </summary>
+/// <remarks>
+///     Properties are just convenient shortcuts to properties of <typeparamref name="TEnum"/>.
+/// </remarks>
+[System.AttributeUsage (System.AttributeTargets.Class | System.AttributeTargets.Interface)]
+internal sealed class ExtensionsForEnumTypeAttribute<TEnum>: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, System.Enum
+{
+    /// <summary>
+    ///     The namespace-qualified name of <typeparamref name="TEnum"/>.
+    /// </summary>
+    public string EnumFullName => EnumType.FullName!;
+
+    /// <summary>
+    ///     The unqualified name of <typeparamref name="TEnum"/>.
+    /// </summary>
+    public string EnumName => EnumType.Name;
+
+    /// <summary>
+    ///     The namespace containing <typeparamref name="TEnum"/>.
+    /// </summary>
+    public string EnumNamespace => EnumType.Namespace!;
+
+    /// <summary>
+    ///     The <see cref="System.Type"/> given by <see langword="typeof"/>(<typeparamref name="TEnum"/>).
+    /// </summary>
+    public System.Type EnumType => typeof (TEnum);
+}

+ 110 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumExtensionMethodsAttribute.cs

@@ -0,0 +1,110 @@
+// ReSharper disable RedundantNullableDirective
+// ReSharper disable RedundantUsingDirective
+// ReSharper disable ClassNeverInstantiated.Global
+
+#nullable enable
+using System;
+using Attribute = System.Attribute;
+using AttributeUsageAttribute = System.AttributeUsageAttribute;
+using AttributeTargets = System.AttributeTargets;
+
+namespace Terminal.Gui.Analyzers.Internal.Attributes;
+
+/// <summary>
+///     Used to enable source generation of a common set of extension methods for enum types.
+/// </summary>
+[AttributeUsage (AttributeTargets.Enum)]
+internal sealed class GenerateEnumExtensionMethodsAttribute : Attribute
+{
+    /// <summary>
+    ///     The name of the generated static class.
+    /// </summary>
+    /// <remarks>
+    ///     If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".<br/>
+    ///     No other validation is performed, so illegal values will simply result in compiler errors.
+    ///     <para>
+    ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+    ///     </para>
+    /// </remarks>
+    public string? ClassName { get; set; }
+
+    /// <summary>
+    ///     The namespace in which to place the generated static class containing the extension methods.
+    /// </summary>
+    /// <remarks>
+    ///     If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.<br/>
+    ///     No other validation is performed, so illegal values will simply result in compiler errors.
+    ///     <para>
+    ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+    ///     </para>
+    /// </remarks>
+    public string? ClassNamespace { get; set; }
+
+    /// <summary>
+    ///     Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in
+    ///     <see cref="Enum.HasFlag"/> method.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Default: false
+    ///     </para>
+    ///     <para>
+    ///         If the enum is not decorated with <see cref="FlagsAttribute"/>, this option has no effect.
+    ///     </para>
+    ///     <para>
+    ///         If multiple members have the same value, the first member with that value will be used and subsequent members
+    ///         with the same value will be skipped.
+    ///     </para>
+    ///     <para>
+    ///         Overloads taking the enum type itself as well as the underlying type of the enum will be generated, enabling
+    ///         avoidance of implicit or explicit cast overhead.
+    ///     </para>
+    ///     <para>
+    ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+    ///     </para>
+    /// </remarks>
+    public bool FastHasFlags { get; set; }
+
+    /// <summary>
+    ///     Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in
+    ///     <see cref="Enum.IsDefined"/> method,
+    ///     using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Default: true
+    ///     </para>
+    ///     <para>
+    ///         If multiple members have the same value, the first member with that value will be used and subsequent members
+    ///         with the same value will be skipped.
+    ///     </para>
+    ///     <para>
+    ///         As with <see cref="Enum.IsDefined"/> the source generator only considers explicitly-named members.<br/>
+    ///         Generation of values which represent valid bitwise combinations of members of enums decorated with
+    ///         <see cref="FlagsAttribute"/> is not affected by this property.
+    ///     </para>
+    /// </remarks>
+    public bool FastIsDefined { get; init; } = true;
+
+    /// <summary>
+    ///     Gets a <see langword="bool"/> value indicating if this <see cref="GenerateEnumExtensionMethodsAttribute"/> instance
+    ///     contains default values only. See <see href="#remarks">remarks</see> of this method or documentation on properties of this type for details.
+    /// </summary>
+    /// <returns>
+    ///     A <see langword="bool"/> value indicating if all property values are default for this
+    ///     <see cref="GenerateEnumExtensionMethodsAttribute"/> instance.
+    /// </returns>
+    /// <remarks>
+    ///     Default values that will result in a <see langword="true"/> return value are:<br/>
+    ///     <see cref="FastIsDefined"/> &amp;&amp; !<see cref="FastHasFlags"/> &amp;&amp; <see cref="ClassName"/>
+    ///     <see langword="is"/> <see langword="null"/> &amp;&amp; <see cref="ClassNamespace"/> <see langword="is"/>
+    ///     <see langword="null"/>
+    /// </remarks>
+    public override bool IsDefaultAttribute ()
+    {
+        return FastIsDefined
+               && !FastHasFlags
+               && ClassName is null
+               && ClassNamespace is null;
+    }
+}

+ 14 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/IExtensionsForEnumTypeAttribute.cs

@@ -0,0 +1,14 @@
+// ReSharper disable All
+
+using System;
+
+namespace Terminal.Gui.Analyzers.Internal.Attributes;
+
+/// <summary>
+///     Interface to simplify general enumeration of constructed generic types for
+///     <see cref="ExtensionsForEnumTypeAttribute{TEnum}"/>
+/// </summary>
+internal interface IExtensionsForEnumTypeAttributes
+{
+    Type EnumType { get; }
+}

+ 11 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IEqualityOperators.cs

@@ -0,0 +1,11 @@
+// ReSharper disable once CheckNamespace
+namespace System.Numerics;
+/// <summary>
+/// Included for compatibility with .net7+, but has no members.
+/// Thus it cannot be explicitly used in generator code.
+/// Use it for static analysis only.
+/// </summary>
+/// <typeparam name="T">The left operand type.</typeparam>
+/// <typeparam name="T1">The right operand type.</typeparam>
+/// <typeparam name="T2">The return type.</typeparam>
+internal interface IEqualityOperators<T, T1, T2>;

+ 6 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IntrinsicAttribute.cs

@@ -0,0 +1,6 @@
+namespace System.Runtime.CompilerServices;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
+public sealed class IntrinsicAttribute : Attribute
+{
+}

+ 43 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NumericExtensions.cs

@@ -0,0 +1,43 @@
+// ReSharper disable once CheckNamespace
+namespace Terminal.Gui.Analyzers.Internal.Compatibility;
+
+/// <summary>
+///     Extension methods for <see langword="int"/> and <see langword="uint"/> types.
+/// </summary>
+/// <remarks>
+///     This is mostly just for backward compatibility with netstandard2.0.
+/// </remarks>
+public static class NumericExtensions
+{
+    /// <summary>
+    ///     Gets the population count (number of bits set to 1) of this 32-bit value.
+    /// </summary>
+    /// <param name="value">The value to get the population count of.</param>
+    /// <remarks>
+    ///     The algorithm is the well-known SWAR (SIMD Within A Register) method for population count.<br/>
+    ///     Included for hardware- and runtime- agnostic support for the equivalent of the x86 popcnt instruction, since
+    ///     System.Numerics.Intrinsics isn't available in netstandard2.0.<br/>
+    ///     It performs the operation simultaneously on 4 bytes at a time, rather than the naive method of testing all 32 bits
+    ///     individually.<br/>
+    ///     Most compilers can recognize this and turn it into a single platform-specific instruction, when available.
+    /// </remarks>
+    /// <returns>
+    ///     An unsigned 32-bit integer value containing the population count of <paramref name="value"/>.
+    /// </returns>
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    public static uint GetPopCount (this uint value)
+    {
+        unchecked
+        {
+            value -= (value >> 1) & 0x55555555;
+            value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
+            value = (value + (value >> 4)) & 0x0F0F0F0F;
+
+            return (value * 0x01010101) >> 24;
+        }
+    }
+
+    /// <inheritdoc cref="GetPopCount(uint)"/>
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    public static uint GetPopCount (this int value) { return GetPopCount (Unsafe.As<int, uint> (ref value)); }
+}

+ 204 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs

@@ -0,0 +1,204 @@
+// ReSharper disable MemberCanBePrivate.Global
+
+using System;
+using System.CodeDom.Compiler;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
+namespace Terminal.Gui.Analyzers.Internal.Constants;
+
+/// <summary>String constants for frequently-used boilerplate.</summary>
+/// <remarks>These are for performance, instead of using Roslyn to build it all during execution of analyzers.</remarks>
+internal static class Strings
+{
+    internal const string AnalyzersAttributesNamespace = $"{InternalAnalyzersNamespace}.Attributes";
+
+    internal const string AssemblyExtendedEnumTypeAttributeFullName = $"{AnalyzersAttributesNamespace}.{nameof (AssemblyExtendedEnumTypeAttribute)}";
+
+    internal const string DefaultTypeNameSuffix = "Extensions";
+
+    internal const string FallbackClassNamespace = $"{TerminalGuiRootNamespace}";
+
+    internal const string InternalAnalyzersNamespace = $"{AnalyzersRootNamespace}.Internal";
+
+    internal const string TerminalGuiRootNamespace = "Terminal.Gui";
+
+    private const string AnalyzersRootNamespace = $"{TerminalGuiRootNamespace}.Analyzers";
+    private const string NetStandard20CompatibilityNamespace = $"{InternalAnalyzersNamespace}.Compatibility";
+
+    /// <summary>
+    ///     Names of dotnet namespaces and types. Included as compile-time constants to avoid unnecessary work for the Roslyn
+    ///     source generators.
+    /// </summary>
+    /// <remarks>Implemented as nested static types because XmlDoc doesn't work on namespaces.</remarks>
+    internal static class DotnetNames
+    {
+        /// <summary>Fully-qualified attribute type names. Specific applications (uses) are in <see cref="Applications"/>.</summary>
+        internal static class Attributes
+        {
+            /// <inheritdoc cref="CompilerGeneratedAttribute"/>
+            internal const string CompilerGenerated = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (CompilerGeneratedAttribute)}";
+
+            /// <inheritdoc cref="DebuggerNonUserCodeAttribute"/>
+            internal const string DebuggerNonUserCode = $"{Namespaces.System_Diagnostics}.{nameof (DebuggerNonUserCodeAttribute)}";
+
+            /// <inheritdoc cref="ExcludeFromCodeCoverageAttribute"/>
+            internal const string ExcludeFromCodeCoverage = $"{Namespaces.System_Diagnostics_CodeAnalysis}.{nameof (ExcludeFromCodeCoverageAttribute)}";
+
+            internal const string Flags = $"{Namespaces.SystemNs}.{nameof (FlagsAttribute)}";
+
+            internal const string GeneratedCode = $"{Namespaces.System_CodeDom_Compiler}.{nameof (GeneratedCodeAttribute)}";
+
+            /// <inheritdoc cref="MethodImplOptions.AggressiveInlining"/>
+            /// <remarks>Use of this attribute should be carefully evaluated.</remarks>
+            internal const string MethodImpl = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (MethodImplAttribute)}";
+
+            /// <summary>Attributes formatted for use in code, including square brackets.</summary>
+            internal static class Applications
+            {
+                // ReSharper disable MemberHidesStaticFromOuterClass
+                internal const string Flags = $"[{Attributes.Flags}]";
+
+                /// <inheritdoc cref="System.CodeDom.Compiler.GeneratedCodeAttribute"/>
+                internal const string GeneratedCode = $"""[{Attributes.GeneratedCode}("{InternalAnalyzersNamespace}","1.0")]""";
+
+                /// <inheritdoc cref="MethodImplOptions.AggressiveInlining"/>
+                /// <remarks>Use of this attribute should be carefully evaluated.</remarks>
+                internal const string AggressiveInlining = $"[{MethodImpl}({Types.MethodImplOptions}.{nameof (MethodImplOptions.AggressiveInlining)})]";
+
+                /// <inheritdoc cref="DebuggerNonUserCodeAttribute"/>
+                internal const string DebuggerNonUserCode = $"[{Attributes.DebuggerNonUserCode}]";
+
+                /// <inheritdoc cref="CompilerGeneratedAttribute"/>
+                internal const string CompilerGenerated = $"[{Attributes.CompilerGenerated}]";
+
+                /// <inheritdoc cref="ExcludeFromCodeCoverageAttribute"/>
+                internal const string ExcludeFromCodeCoverage = $"[{Attributes.ExcludeFromCodeCoverage}]";
+
+                // ReSharper restore MemberHidesStaticFromOuterClass
+            }
+        }
+
+        /// <summary>Names of dotnet namespaces.</summary>
+        internal static class Namespaces
+        {
+            internal const string SystemNs = nameof (System);
+            // ReSharper disable InconsistentNaming
+            internal const string System_CodeDom = $"{SystemNs}.{nameof (System.CodeDom)}";
+            internal const string System_CodeDom_Compiler = $"{System_CodeDom}.{nameof (System.CodeDom.Compiler)}";
+            internal const string System_ComponentModel = $"{SystemNs}.{nameof (System.ComponentModel)}";
+            internal const string System_Diagnostics = $"{SystemNs}.{nameof (System.Diagnostics)}";
+            internal const string System_Diagnostics_CodeAnalysis = $"{System_Diagnostics}.{nameof (System.Diagnostics.CodeAnalysis)}";
+            internal const string System_Numerics = $"{SystemNs}.{nameof (System.Numerics)}";
+            internal const string System_Runtime = $"{SystemNs}.{nameof (System.Runtime)}";
+            internal const string System_Runtime_CompilerServices = $"{System_Runtime}.{nameof (System.Runtime.CompilerServices)}";
+            // ReSharper restore InconsistentNaming
+        }
+
+        internal static class Types
+        {
+            internal const string Attribute = $"{Namespaces.SystemNs}.{nameof (System.Attribute)}";
+            internal const string AttributeTargets = $"{Namespaces.SystemNs}.{nameof (System.AttributeTargets)}";
+            internal const string AttributeUsageAttribute = $"{Namespaces.SystemNs}.{nameof (System.AttributeUsageAttribute)}";
+
+            internal const string MethodImplOptions =
+                $"{Namespaces.System_Runtime_CompilerServices}.{nameof (System.Runtime.CompilerServices.MethodImplOptions)}";
+        }
+    }
+
+    internal static class Templates
+    {
+        internal const string AutoGeneratedCommentBlock = $"""
+                                                           //------------------------------------------------------------------------------
+                                                           // <auto-generated>
+                                                           //   This file and the code it contains was generated by a source generator in
+                                                           //   the {InternalAnalyzersNamespace} library.
+                                                           //
+                                                           //   Modifications to this file are not supported and will be lost when
+                                                           //   source generation is triggered, either implicitly or explicitly.
+                                                           // </auto-generated>
+                                                           //------------------------------------------------------------------------------
+                                                           """;
+
+        /// <summary>
+        ///     A set of explicit type aliases to work around Terminal.Gui having name collisions with types like
+        ///     <see cref="System.Attribute"/>.
+        /// </summary>
+        internal const string DotnetExplicitTypeAliasUsingDirectives = $"""
+                                                                        using Attribute = {DotnetNames.Types.Attribute};
+                                                                        using AttributeUsageAttribute = {DotnetNames.Types.AttributeUsageAttribute};
+                                                                        using GeneratedCode = {DotnetNames.Attributes.GeneratedCode};
+                                                                        """;
+
+        /// <summary>Using directives for common namespaces in generated code.</summary>
+        internal const string DotnetNamespaceUsingDirectives = $"""
+                                                                using {DotnetNames.Namespaces.SystemNs};
+                                                                using {DotnetNames.Namespaces.System_CodeDom};
+                                                                using {DotnetNames.Namespaces.System_CodeDom_Compiler};
+                                                                using {DotnetNames.Namespaces.System_ComponentModel};
+                                                                using {DotnetNames.Namespaces.System_Numerics};
+                                                                using {DotnetNames.Namespaces.System_Runtime};
+                                                                using {DotnetNames.Namespaces.System_Runtime_CompilerServices};
+                                                                """;
+
+        /// <summary>
+        ///     A set of empty namespaces that MAY be referenced in generated code, especially in using statements,
+        ///     which are always included to avoid additional complexity due to conditional compilation.
+        /// </summary>
+        internal const string DummyNamespaceDeclarations = $$"""
+                                                             // These are dummy declarations to avoid complexity with conditional compilation.
+                                                             #pragma warning disable IDE0079 // Remove unnecessary suppression
+                                                             #pragma warning disable RCS1259 // Remove empty syntax
+                                                             namespace {{TerminalGuiRootNamespace}} { }
+                                                             namespace {{AnalyzersRootNamespace}} { }
+                                                             namespace {{InternalAnalyzersNamespace}} { }
+                                                             namespace {{NetStandard20CompatibilityNamespace}} { }
+                                                             namespace {{AnalyzersAttributesNamespace}} { }
+                                                             #pragma warning restore RCS1259 // Remove empty syntax
+                                                             #pragma warning restore IDE0079 // Remove unnecessary suppression
+                                                             """;
+
+        internal const string StandardHeader = $"""
+                                                {AutoGeneratedCommentBlock}
+                                                // ReSharper disable RedundantUsingDirective
+                                                // ReSharper disable once RedundantNullableDirective
+                                                {NullableContextDirective}
+
+                                                {StandardUsingDirectivesText}
+                                                """;
+
+        /// <summary>
+        ///     Standard set of using directives for generated extension method class files.
+        ///     Not all are always needed, but all are included so we don't have to worry about it.
+        /// </summary>
+        internal const string StandardUsingDirectivesText = $"""
+                                                             {DotnetNamespaceUsingDirectives}
+                                                             {DotnetExplicitTypeAliasUsingDirectives}
+                                                             using {TerminalGuiRootNamespace};
+                                                             using {AnalyzersRootNamespace};
+                                                             using {InternalAnalyzersNamespace};
+                                                             using {AnalyzersAttributesNamespace};
+                                                             using {NetStandard20CompatibilityNamespace};
+                                                             """;
+
+        internal const string AttributesForGeneratedInterfaces = $"""
+                                                                  {DotnetNames.Attributes.Applications.GeneratedCode}
+                                                                  {DotnetNames.Attributes.Applications.CompilerGenerated}
+                                                                  """;
+
+        internal const string AttributesForGeneratedTypes = $"""
+                                                             {DotnetNames.Attributes.Applications.GeneratedCode}
+                                                             {DotnetNames.Attributes.Applications.CompilerGenerated}
+                                                             {DotnetNames.Attributes.Applications.DebuggerNonUserCode}
+                                                             {DotnetNames.Attributes.Applications.ExcludeFromCodeCoverage}
+                                                             """;
+
+        /// <summary>
+        ///     Preprocessor directive to enable nullability context for generated code.<br/>
+        ///     This should always be emitted, as it applies only to generated code.<br/>
+        ///     As such, generated code MUST be properly annotated.
+        /// </summary>
+        internal const string NullableContextDirective = "#nullable enable";
+    }
+}

+ 235 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs

@@ -0,0 +1,235 @@
+using System;
+using System.CodeDom.Compiler;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Text;
+using Microsoft.CodeAnalysis.Text;
+using Terminal.Gui.Analyzers.Internal.Constants;
+
+namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
+
+/// <summary>
+///     The class responsible for turning an <see cref="EnumExtensionMethodsGenerationInfo"/>
+///     into actual C# code.
+/// </summary>
+/// <remarks>Try to use this type as infrequently as possible.</remarks>
+/// <param name="metadata">
+///     A reference to an <see cref="IGeneratedTypeMetadata{TSelf}"/> which will be used
+///     to generate the extension class code. The object will not be validated,
+///     so it is critical that it be correct and remain unchanged while in use
+///     by an instance of this class. Behavior if those rules are not followed
+///     is undefined.
+/// </param>
+[SuppressMessage ("CodeQuality", "IDE0079", Justification = "Suppressions here are intentional and the warnings they disable are just noise.")]
+internal sealed class CodeWriter (in EnumExtensionMethodsGenerationInfo metadata) : IStandardCSharpCodeGenerator<EnumExtensionMethodsGenerationInfo>
+{
+    // Using the null suppression operator here because this will always be
+    // initialized to non-null before a reference to it is returned.
+    private SourceText _sourceText = null!;
+
+    /// <inheritdoc/>
+    public EnumExtensionMethodsGenerationInfo Metadata
+    {
+        [MethodImpl (MethodImplOptions.AggressiveInlining)]
+        [return: NotNull]
+        get;
+        [param: DisallowNull]
+        set;
+    } = metadata;
+
+    /// <inheritdoc/>
+    public ref readonly SourceText GenerateSourceText (Encoding? encoding = null)
+    {
+        encoding ??= Encoding.UTF8;
+        _sourceText = SourceText.From (GetFullSourceText (), encoding);
+
+        return ref _sourceText;
+    }
+
+    /// <summary>
+    ///     Gets the using directive for the namespace containing the enum,
+    ///     if different from the extension class namespace, or an empty string, if they are the same.
+    /// </summary>
+    private string EnumNamespaceUsingDirective => Metadata.TargetTypeNamespace != Metadata.GeneratedTypeNamespace
+
+                                                      // ReSharper disable once HeapView.ObjectAllocation
+                                                      ? $"using {Metadata.TargetTypeNamespace};"
+                                                      : string.Empty;
+
+    private string EnumTypeKeyword => Metadata.EnumBackingTypeCode switch
+                                      {
+                                          TypeCode.Int32 => "int",
+                                          TypeCode.UInt32 => "uint",
+                                          _ => string.Empty
+                                      };
+
+    /// <summary>Gets the class declaration line.</summary>
+    private string ExtensionClassDeclarationLine => $"public static partial class {Metadata.GeneratedTypeName}";
+
+    // ReSharper disable once HeapView.ObjectAllocation
+    /// <summary>Gets the XmlDoc for the extension class declaration.</summary>
+    private string ExtensionClassDeclarationXmlDoc =>
+        $"/// <summary>Extension methods for the <see cref=\"{Metadata.TargetTypeFullName}\"/> <see langword=\"enum\" /> type.</summary>";
+
+    // ReSharper disable once HeapView.ObjectAllocation
+    /// <summary>Gets the extension class file-scoped namespace directive.</summary>
+    private string ExtensionClassNamespaceDirective => $"namespace {Metadata.GeneratedTypeNamespace};";
+
+    /// <summary>
+    ///     An attribute to decorate the extension class with for easy mapping back to the target enum type, for reflection and
+    ///     analysis.
+    /// </summary>
+    private string ExtensionsForTypeAttributeLine => $"[ExtensionsForEnumType<{Metadata.TargetTypeFullName}>]";
+
+    /// <summary>
+    ///     Creates the code for the FastHasFlags method.
+    /// </summary>
+    /// <remarks>
+    ///     Since the generator already only writes code for enums backed by <see langword="int"/> and <see langword="uint"/>,
+    ///     this method is safe, as we'll always be using a DWORD.
+    /// </remarks>
+    /// <param name="w">An instance of an <see cref="IndentedTextWriter"/> to write to.</param>
+    private void GetFastHasFlagsMethods (IndentedTextWriter w)
+    {
+        // The version taking the same enum type as the check value.
+        w.WriteLine (
+                     $"/// <summary>Determines if the specified flags are set in the current value of this <see cref=\"{Metadata.TargetTypeFullName}\" />.</summary>");
+        w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
+
+        w.WriteLine (
+                     $"/// <returns>True, if all flags present in <paramref name=\"checkFlags\" /> are also present in the current value of the <see cref=\"{Metadata.TargetTypeFullName}\" />.<br />Otherwise false.</returns>");
+        w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
+
+        w.Push (
+                $"{Metadata.Accessibility.ToCSharpString ()} static bool FastHasFlags (this {Metadata.TargetTypeFullName} e, {Metadata.TargetTypeFullName} checkFlags)");
+        w.WriteLine ($"ref uint enumCurrentValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref e);");
+        w.WriteLine ($"ref uint checkFlagsValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref checkFlags);");
+        w.WriteLine ("return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef;");
+        w.Pop ();
+
+        // The version taking the underlying type of the enum as the check value.
+        w.WriteLine (
+                     $"/// <summary>Determines if the specified mask bits are set in the current value of this <see cref=\"{Metadata.TargetTypeFullName}\" />.</summary>");
+
+        w.WriteLine (
+                     $"/// <param name=\"e\">The <see cref=\"{Metadata.TargetTypeFullName}\" /> value to check against the <paramref name=\"mask\" /> value.</param>");
+        w.WriteLine ("/// <param name=\"mask\">A mask to apply to the current value.</param>");
+
+        w.WriteLine (
+                     $"/// <returns>True, if all bits set to 1 in the mask are also set to 1 in the current value of the <see cref=\"{Metadata.TargetTypeFullName}\" />.<br />Otherwise false.</returns>");
+        w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
+        w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
+
+        w.Push (
+                $"{Metadata.Accessibility.ToCSharpString ()} static bool FastHasFlags (this {Metadata.TargetTypeFullName} e, {EnumTypeKeyword} mask)");
+        w.WriteLine ($"ref {EnumTypeKeyword} enumCurrentValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},{EnumTypeKeyword}> (ref e);");
+        w.WriteLine ("return (enumCurrentValueRef & mask) == mask;");
+        w.Pop ();
+    }
+
+    /// <summary>
+    ///     Creates the code for the FastIsDefined method.
+    /// </summary>
+    [SuppressMessage ("ReSharper", "SwitchStatementHandlesSomeKnownEnumValuesWithDefault", Justification = "Only need to handle int and uint.")]
+    [SuppressMessage ("ReSharper", "SwitchStatementMissingSomeEnumCasesNoDefault", Justification = "Only need to handle int and uint.")]
+    private void GetFastIsDefinedMethod (IndentedTextWriter w)
+    {
+        w.WriteLine (
+                     $"/// <summary>Determines if the specified <see langword=\"{EnumTypeKeyword}\" /> value is explicitly defined as a named value of the <see cref=\"{Metadata.TargetTypeFullName}\" /> <see langword=\"enum\" /> type.</summary>");
+
+        w.WriteLine (
+                     "/// <remarks>Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are not explicitly named will return false.</remarks>");
+
+        w.Push (
+                $"{Metadata.Accessibility.ToCSharpString ()} static bool FastIsDefined (this {Metadata.TargetTypeFullName} e, {EnumTypeKeyword} value)");
+        w.Push ("return value switch");
+
+        switch (Metadata.EnumBackingTypeCode)
+        {
+            case TypeCode.Int32:
+                foreach (int definedValue in Metadata._intMembers)
+                {
+                    w.WriteLine ($"{definedValue:D} => true,");
+                }
+
+                break;
+            case TypeCode.UInt32:
+                foreach (uint definedValue in Metadata._uIntMembers)
+                {
+                    w.WriteLine ($"{definedValue:D} => true,");
+                }
+
+                break;
+        }
+
+        w.WriteLine ("_ => false");
+
+        w.Pop ("};");
+        w.Pop ();
+    }
+
+    private string GetFullSourceText ()
+    {
+        StringBuilder sb = new (
+                                $"""
+                                 {Strings.Templates.StandardHeader}
+
+                                 [assembly: {Strings.AssemblyExtendedEnumTypeAttributeFullName} (typeof({Metadata.TargetTypeFullName}), typeof({Metadata.GeneratedTypeFullName}))]
+
+                                 {EnumNamespaceUsingDirective}
+                                 {ExtensionClassNamespaceDirective}
+                                 {ExtensionClassDeclarationXmlDoc}
+                                 {Strings.Templates.AttributesForGeneratedTypes}
+                                 {ExtensionsForTypeAttributeLine}
+                                 {ExtensionClassDeclarationLine}
+                                 
+                                 """,
+                                4096);
+
+        using IndentedTextWriter w = new (new StringWriter (sb));
+        w.Push ();
+
+        GetNamedValuesToInt32Method (w);
+        GetNamedValuesToUInt32Method (w);
+
+        if (Metadata.GenerateFastIsDefined)
+        {
+            GetFastIsDefinedMethod (w);
+        }
+
+        if (Metadata.GenerateFastHasFlags)
+        {
+            GetFastHasFlagsMethods (w);
+        }
+
+        w.Pop ();
+
+        w.Flush ();
+
+        return sb.ToString ();
+    }
+
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    private void GetNamedValuesToInt32Method (IndentedTextWriter w)
+    {
+        w.WriteLine (
+                     $"/// <summary>Directly converts this <see cref=\"{Metadata.TargetTypeFullName}\" /> value to an <see langword=\"int\" /> value with the same binary representation.</summary>");
+        w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
+        w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
+        w.Push ($"{Metadata.Accessibility.ToCSharpString ()} static int AsInt32 (this {Metadata.TargetTypeFullName} e)");
+        w.WriteLine ($"return Unsafe.As<{Metadata.TargetTypeFullName},int> (ref e);");
+        w.Pop ();
+    }
+
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    private void GetNamedValuesToUInt32Method (IndentedTextWriter w)
+    {
+        w.WriteLine (
+                     $"/// <summary>Directly converts this <see cref=\"{Metadata.TargetTypeFullName}\" /> value to a <see langword=\"uint\" /> value with the same binary representation.</summary>");
+        w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
+        w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
+        w.Push ($"{Metadata.Accessibility.ToCSharpString ()} static uint AsUInt32 (this {Metadata.TargetTypeFullName} e)");
+        w.WriteLine ($"return Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref e);");
+        w.Pop ();
+    }
+}

+ 443 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs

@@ -0,0 +1,443 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Threading;
+using JetBrains.Annotations;
+using Microsoft.CodeAnalysis;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+using Terminal.Gui.Analyzers.Internal.Constants;
+
+namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
+
+/// <summary>
+///     Type containing the information necessary to generate code according to the declared attribute values,
+///     as well as the actual code to create the corresponding source code text, to be used in the
+///     source generator pipeline.
+/// </summary>
+/// <remarks>
+///     Minimal validation is performed by this type.<br/>
+///     Errors in analyzed source code will result in generation failure or broken output.<br/>
+///     This type is not intended for use outside of Terminal.Gui library development.
+/// </remarks>
+internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetadata<EnumExtensionMethodsGenerationInfo>,
+                                                            IEqualityOperators<EnumExtensionMethodsGenerationInfo, EnumExtensionMethodsGenerationInfo, bool>
+{
+    private const int ExplicitFastHasFlagsMask  = 0b_0100;
+    private const int ExplicitFastIsDefinedMask = 0b_1000;
+    private const int ExplicitNameMask          = 0b_0010;
+    private const int ExplicitNamespaceMask     = 0b_0001;
+    private const string GeneratorAttributeFullyQualifiedName = $"{GeneratorAttributeNamespace}.{GeneratorAttributeName}";
+    private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
+    private const string GeneratorAttributeNamespace = Strings.AnalyzersAttributesNamespace;
+
+    /// <summary>
+    ///     Type containing the information necessary to generate code according to the declared attribute values,
+    ///     as well as the actual code to create the corresponding source code text, to be used in the
+    ///     source generator pipeline.
+    /// </summary>
+    /// <param name="enumNamespace">The fully-qualified namespace of the enum type, without assembly name.</param>
+    /// <param name="enumTypeName">
+    ///     The name of the enum type, as would be given by <see langword="nameof"/> on the enum's type
+    ///     declaration.
+    /// </param>
+    /// <param name="typeNamespace">
+    ///     The fully-qualified namespace in which to place the generated code, without assembly name. If omitted or explicitly
+    ///     null, uses the value provided in <paramref name="enumNamespace"/>.
+    /// </param>
+    /// <param name="typeName">
+    ///     The name of the generated class. If omitted or explicitly null, appends "Extensions" to the value of
+    ///     <paramref name="enumTypeName"/>.
+    /// </param>
+    /// <param name="enumBackingTypeCode">The backing type of the enum. Defaults to <see cref="int"/>.</param>
+    /// <param name="generateFastHasFlags">
+    ///     Whether to generate a fast HasFlag alternative. (Default: true) Ignored if the enum does not also have
+    ///     <see cref="FlagsAttribute"/>.
+    /// </param>
+    /// <param name="generateFastIsDefined">Whether to generate a fast IsDefined alternative. (Default: true)</param>
+    /// <remarks>
+    ///     Minimal validation is performed by this type.<br/>
+    ///     Errors in analyzed source code will result in generation failure or broken output.<br/>
+    ///     This type is not intended for use outside of Terminal.Gui library development.
+    /// </remarks>
+    public EnumExtensionMethodsGenerationInfo (
+        string enumNamespace,
+        string enumTypeName,
+        string? typeNamespace = null,
+        string? typeName = null,
+        TypeCode enumBackingTypeCode = TypeCode.Int32,
+        bool generateFastHasFlags = true,
+        bool generateFastIsDefined = true
+    ) : this (enumNamespace, enumTypeName, enumBackingTypeCode)
+    {
+        GeneratedTypeNamespace = typeNamespace ?? enumNamespace;
+        GeneratedTypeName = typeName ?? string.Concat (enumTypeName, Strings.DefaultTypeNameSuffix);
+        GenerateFastHasFlags = generateFastHasFlags;
+        GenerateFastIsDefined = generateFastIsDefined;
+    }
+
+    public EnumExtensionMethodsGenerationInfo (string enumNamespace, string enumTypeName, TypeCode enumBackingType)
+    {
+        // Interning these since they're rather unlikely to change.
+        string enumInternedNamespace = string.Intern (enumNamespace);
+        string enumInternedName = string.Intern (enumTypeName);
+        TargetTypeNamespace = enumInternedNamespace;
+        TargetTypeName = enumInternedName;
+        EnumBackingTypeCode = enumBackingType;
+    }
+
+    [AccessedThroughProperty (nameof (EnumBackingTypeCode))]
+    private readonly TypeCode _enumBackingTypeCode;
+
+    [AccessedThroughProperty (nameof (GeneratedTypeName))]
+    private string? _generatedTypeName;
+
+    [AccessedThroughProperty (nameof (GeneratedTypeNamespace))]
+    private string? _generatedTypeNamespace;
+
+    private BitVector32 _discoveredProperties = new (0);
+
+    /// <summary>The name of the extension class.</summary>
+    public string? GeneratedTypeName
+    {
+        get => _generatedTypeName ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
+        set => _generatedTypeName = value ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
+    }
+
+    /// <summary>The namespace for the extension class.</summary>
+    /// <remarks>
+    ///     Value is not validated by the set accessor.<br/>
+    ///     Get accessor will never return null and is thus marked [NotNull] for static analysis, even though the property is
+    ///     declared as a nullable <see langword="string?"/>.<br/>If the backing field for this property is null, the get
+    ///     accessor will return <see cref="TargetTypeNamespace"/> instead.
+    /// </remarks>
+    public string? GeneratedTypeNamespace
+    {
+        get => _generatedTypeNamespace ?? TargetTypeNamespace;
+        set => _generatedTypeNamespace = value ?? TargetTypeNamespace;
+    }
+
+    /// <inheritdoc/>
+    public string TargetTypeFullName => string.Concat (TargetTypeNamespace, ".", TargetTypeName);
+
+    /// <inheritdoc/>
+    public Accessibility Accessibility
+    {
+        get;
+        [UsedImplicitly]
+        internal set;
+    } = Accessibility.Public;
+
+    /// <inheritdoc/>
+    public TypeKind TypeKind => TypeKind.Class;
+
+    /// <inheritdoc/>
+    public bool IsRecord => false;
+
+    /// <inheritdoc/>
+    public bool IsClass => true;
+
+    /// <inheritdoc/>
+    public bool IsStruct => false;
+
+    /// <inheritdoc/>
+    public bool IsByRefLike => false;
+
+    /// <inheritdoc/>
+    public bool IsSealed => false;
+
+    /// <inheritdoc/>
+    public bool IsAbstract => false;
+
+    /// <inheritdoc/>
+    public bool IsEnum => false;
+
+    /// <inheritdoc/>
+    public bool IsStatic => true;
+
+    /// <inheritdoc/>
+    public bool IncludeInterface => false;
+
+    public string GeneratedTypeFullName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}";
+
+    /// <summary>Whether to generate the extension class as partial (Default: true)</summary>
+    public bool IsPartial => true;
+
+    /// <summary>The fully-qualified namespace of the source enum type.</summary>
+    public string TargetTypeNamespace
+    {
+        get;
+        [UsedImplicitly]
+        set;
+    }
+
+    /// <summary>The UNQUALIFIED name of the source enum type.</summary>
+    public string TargetTypeName
+    {
+        get;
+        [UsedImplicitly]
+        set;
+    }
+
+    /// <summary>
+    ///     The backing type for the enum.
+    /// </summary>
+    /// <remarks>For simplicity and formality, only System.Int32 and System.UInt32 are supported at this time.</remarks>
+    public TypeCode EnumBackingTypeCode
+    {
+        get => _enumBackingTypeCode;
+        init
+        {
+            if (value is not TypeCode.Int32 and not TypeCode.UInt32)
+            {
+                throw new NotSupportedException ("Only System.Int32 and System.UInt32 are supported at this time.");
+            }
+
+            _enumBackingTypeCode = value;
+        }
+    }
+
+    /// <summary>
+    ///     Whether a fast alternative to the built-in Enum.HasFlag method will be generated (Default: false)
+    /// </summary>
+    public bool GenerateFastHasFlags { [UsedImplicitly] get; set; }
+
+    /// <summary>Whether a switch-based IsDefined replacement will be generated (Default: true)</summary>
+    public bool GenerateFastIsDefined { [UsedImplicitly]get; set; } = true;
+
+    internal ImmutableHashSet<int>? _intMembers;
+    internal ImmutableHashSet<uint>? _uIntMembers;
+
+    /// <summary>
+    ///     Fully-qualified name of the extension class
+    /// </summary>
+    internal string FullyQualifiedClassName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}";
+
+    /// <summary>
+    ///     Whether a Flags was found on the enum type.
+    /// </summary>
+    internal bool HasFlagsAttribute {[UsedImplicitly] get; set; }
+
+    private static readonly SymbolDisplayFormat FullyQualifiedSymbolDisplayFormatWithoutGlobal =
+        SymbolDisplayFormat.FullyQualifiedFormat
+                           .WithGlobalNamespaceStyle (
+                                                      SymbolDisplayGlobalNamespaceStyle.Omitted);
+
+
+    internal bool TryConfigure (INamedTypeSymbol enumSymbol, CancellationToken cancellationToken)
+    {
+        using var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
+        cts.Token.ThrowIfCancellationRequested ();
+
+        ImmutableArray<AttributeData> attributes = enumSymbol.GetAttributes ();
+
+        // This is theoretically impossible, but guarding just in case and canceling if it does happen.
+        if (attributes.Length == 0)
+        {
+            cts.Cancel (true);
+
+            return false;
+        }
+
+        // Check all attributes provided for anything interesting.
+        // Attributes can be in any order, so just check them all and adjust at the end if necessary.
+        // Note that we do not perform as strict validation on actual usage of the attribute, at this stage,
+        // because the analyzer should have already thrown errors for invalid uses like global namespace
+        // or unsupported enum underlying types.
+        foreach (AttributeData attr in attributes)
+        {
+            cts.Token.ThrowIfCancellationRequested ();
+            string? attributeFullyQualifiedName = attr.AttributeClass?.ToDisplayString (FullyQualifiedSymbolDisplayFormatWithoutGlobal);
+
+            // Skip if null or not possibly an attribute we care about
+            if (attributeFullyQualifiedName is null or not { Length: >= 5 })
+            {
+                continue;
+            }
+
+            switch (attributeFullyQualifiedName)
+            {
+                // For Flags enums
+                case Strings.DotnetNames.Attributes.Flags:
+                {
+                    HasFlagsAttribute = true;
+                }
+
+                    continue;
+
+                // For the attribute that started this whole thing
+                case GeneratorAttributeFullyQualifiedName:
+
+                {
+                    // If we can't successfully complete this method,
+                    // something is wrong enough that we may as well just stop now.
+                    if (!TryConfigure (attr, cts.Token))
+                    {
+                        if (cts.Token.CanBeCanceled)
+                        {
+                            cts.Cancel ();
+                        }
+
+                        return false;
+                    }
+                }
+
+                    continue;
+            }
+        }
+
+        // Now get the members, if we know we'll need them.
+        if (GenerateFastIsDefined || GenerateFastHasFlags)
+        {
+            if (EnumBackingTypeCode == TypeCode.Int32)
+            {
+                PopulateIntMembersHashSet (enumSymbol);
+            }
+            else if (EnumBackingTypeCode == TypeCode.UInt32)
+            {
+                PopulateUIntMembersHashSet (enumSymbol);
+            }
+        }
+
+        return true;
+    }
+
+    private void PopulateIntMembersHashSet (INamedTypeSymbol enumSymbol)
+    {
+        ImmutableArray<ISymbol> enumMembers = enumSymbol.GetMembers ();
+        IEnumerable<IFieldSymbol> fieldSymbols = enumMembers.OfType<IFieldSymbol> ();
+        _intMembers = fieldSymbols.Select (static m => m.HasConstantValue ? (int)m.ConstantValue : 0).ToImmutableHashSet ();
+    }
+    private void PopulateUIntMembersHashSet (INamedTypeSymbol enumSymbol)
+    {
+        _uIntMembers = enumSymbol.GetMembers ().OfType<IFieldSymbol> ().Select (static m => (uint)m.ConstantValue).ToImmutableHashSet ();
+    }
+
+    private bool HasExplicitFastHasFlags
+    {
+        [UsedImplicitly]get => _discoveredProperties [ExplicitFastHasFlagsMask];
+        set => _discoveredProperties [ExplicitFastHasFlagsMask] = value;
+    }
+
+    private bool HasExplicitFastIsDefined
+    {
+        [UsedImplicitly]get => _discoveredProperties [ExplicitFastIsDefinedMask];
+        set => _discoveredProperties [ExplicitFastIsDefinedMask] = value;
+    }
+
+    private bool HasExplicitTypeName
+    {
+        get => _discoveredProperties [ExplicitNameMask];
+        set => _discoveredProperties [ExplicitNameMask] = value;
+    }
+
+    private bool HasExplicitTypeNamespace
+    {
+        get => _discoveredProperties [ExplicitNamespaceMask];
+        set => _discoveredProperties [ExplicitNamespaceMask] = value;
+    }
+
+    [MemberNotNullWhen (true, nameof (_generatedTypeName), nameof (_generatedTypeNamespace))]
+    private bool TryConfigure (AttributeData attr, CancellationToken cancellationToken)
+    {
+        using var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
+        cts.Token.ThrowIfCancellationRequested ();
+
+        if (attr is not { NamedArguments.Length: > 0 })
+        {
+            // Just a naked attribute, so configure with appropriate defaults.
+            GeneratedTypeNamespace = TargetTypeNamespace;
+            GeneratedTypeName = string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
+
+            return true;
+        }
+
+        cts.Token.ThrowIfCancellationRequested ();
+
+        foreach (KeyValuePair<string, TypedConstant> kvp in attr.NamedArguments)
+        {
+            string? propName = kvp.Key;
+            TypedConstant propValue = kvp.Value;
+
+            cts.Token.ThrowIfCancellationRequested ();
+
+            // For every property name and value pair, set associated metadata
+            // property, if understood.
+            switch (propName, propValue)
+            {
+                // Null or empty string doesn't make sense, so skip if it happens.
+                case (null, _):
+                case ("", _):
+                    continue;
+
+                // ClassName is specified, not explicitly null, and at least 1 character long.
+                case (AttributeProperties.TypeNamePropertyName, { IsNull: false, Value: string { Length: > 1 } classNameProvidedValue }):
+                    if (string.IsNullOrWhiteSpace (classNameProvidedValue))
+                    {
+                        return false;
+                    }
+
+                    GeneratedTypeName = classNameProvidedValue;
+                    HasExplicitTypeName = true;
+
+                    continue;
+
+                // Class namespace is specified, not explicitly null, and at least 1 character long.
+                case (AttributeProperties.TypeNamespacePropertyName, { IsNull: false, Value: string { Length: > 1 } classNamespaceProvidedValue }):
+
+                    if (string.IsNullOrWhiteSpace (classNamespaceProvidedValue))
+                    {
+                        return false;
+                    }
+
+                    GeneratedTypeNamespace = classNamespaceProvidedValue;
+                    HasExplicitTypeNamespace = true;
+
+                    continue;
+
+                // FastHasFlags is specified
+                case (AttributeProperties.FastHasFlagsPropertyName, { IsNull: false } fastHasFlagsConstant):
+                    GenerateFastHasFlags = fastHasFlagsConstant.Value is true;
+                    HasExplicitFastHasFlags = true;
+
+                    continue;
+
+                // FastIsDefined is specified
+                case (AttributeProperties.FastIsDefinedPropertyName, { IsNull: false } fastIsDefinedConstant):
+                    GenerateFastIsDefined = fastIsDefinedConstant.Value is true;
+                    HasExplicitFastIsDefined = true;
+
+                    continue;
+            }
+        }
+
+        // The rest is simple enough it's not really worth worrying about cancellation, so don't bother from here on...
+
+        // Configure anything that wasn't specified that doesn't have an implicitly safe default
+        if (!HasExplicitTypeName || _generatedTypeName is null)
+        {
+            _generatedTypeName = string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
+        }
+
+        if (!HasExplicitTypeNamespace || _generatedTypeNamespace is null)
+        {
+            _generatedTypeNamespace = TargetTypeNamespace;
+        }
+
+        if (!HasFlagsAttribute)
+        {
+            GenerateFastHasFlags = false;
+        }
+
+        return true;
+    }
+
+    private static class AttributeProperties
+    {
+        internal const string FastHasFlagsPropertyName = nameof (GenerateEnumExtensionMethodsAttribute.FastHasFlags);
+        internal const string FastIsDefinedPropertyName = nameof (GenerateEnumExtensionMethodsAttribute.FastIsDefined);
+        internal const string TypeNamePropertyName = nameof (GenerateEnumExtensionMethodsAttribute.ClassName);
+        internal const string TypeNamespacePropertyName = nameof (GenerateEnumExtensionMethodsAttribute.ClassNamespace);
+    }
+}

+ 452 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs

@@ -0,0 +1,452 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+using Terminal.Gui.Analyzers.Internal.Attributes;
+using Terminal.Gui.Analyzers.Internal.Constants;
+
+namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
+
+/// <summary>
+///     Incremental code generator for enums decorated with <see cref="GenerateEnumExtensionMethodsAttribute"/>.
+/// </summary>
+[SuppressMessage ("CodeQuality", "IDE0079", Justification = "Suppressions here are intentional and the warnings they disable are just noise.")]
+[Generator (LanguageNames.CSharp)]
+public sealed class EnumExtensionMethodsIncrementalGenerator : IIncrementalGenerator
+{
+    private const string ExtensionsForEnumTypeAttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{ExtensionsForEnumTypeAttributeName}";
+    private const string ExtensionsForEnumTypeAttributeName = "ExtensionsForEnumTypeAttribute";
+    private const string GeneratorAttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{GeneratorAttributeName}";
+    private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
+
+    /// <summary>Fully-qualified symbol name format without the "global::" prefix.</summary>
+    private static readonly SymbolDisplayFormat _fullyQualifiedSymbolDisplayFormatWithoutGlobal =
+        SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle (SymbolDisplayGlobalNamespaceStyle.Omitted);
+
+    /// <inheritdoc/>
+    /// <remarks>
+    ///     <para>
+    ///         Basically, this method is called once by the compiler, and is responsible for wiring up
+    ///         everything important about how source generation works.
+    ///     </para>
+    ///     <para>
+    ///         See in-line comments for specifics of what's going on.
+    ///     </para>
+    ///     <para>
+    ///         Note that <paramref name="context"/> is everything in the compilation,
+    ///         except for code generated by this generator or generators which have not yet executed.<br/>
+    ///         The methods registered to perform generation get called on-demand by the host (the IDE,
+    ///         compiler, etc), sometimes as often as every single keystroke.
+    ///     </para>
+    /// </remarks>
+    public void Initialize (IncrementalGeneratorInitializationContext context)
+    {
+        // Write out namespaces that may be used later. Harmless to declare them now and will avoid
+        // additional processing and potential omissions later on.
+        context.RegisterPostInitializationOutput (GenerateDummyNamespaces);
+
+        // This executes the delegate given to it immediately after Roslyn gets all set up.
+        // 
+        // As written, this will result in the GenerateEnumExtensionMethodsAttribute code
+        // being added to the environment, so that it can be used without having to actually
+        // be declared explicitly in the target project.
+        // This is important, as it guarantees the type will exist and also guarantees it is
+        // defined exactly as the generator expects it to be defined.
+        context.RegisterPostInitializationOutput (GenerateAttributeSources);
+
+        // Next up, we define our pipeline.
+        // To do so, we create one or more IncrementalValuesProvider<T> objects, each of which
+        // defines on stage of analysis or generation as needed.
+        //
+        // Critically, these must be as fast and efficient as reasonably possible because,
+        // once the pipeline is registered, this stuff can get called A LOT.
+        //
+        // Note that declaring these doesn't really do much of anything unless they are given to the
+        // RegisterSourceOutput method at the end of this method.
+        //
+        // The delegates are not actually evaluated right here. That is triggered by changes being
+        // made to the source code.
+
+        // This provider grabs attributes that pass our filter and then creates lightweight
+        // metadata objects to be used in the final code generation step.
+        // It also preemptively removes any nulls from the collection before handing things off
+        // to the code generation logic.
+        IncrementalValuesProvider<EnumExtensionMethodsGenerationInfo?> enumGenerationInfos =
+            context
+                .SyntaxProvider
+
+                // This method is a highly-optimized (and highly-recommended) filter on the incoming
+                // code elements that only bothers to present code that is annotated with the specified
+                // attribute, by its fully-qualified name, as a string, which is the first parameter.
+                //
+                // Two delegates are passed to it, in the second and third parameters.
+                //
+                // The second parameter is a filter predicate taking each SyntaxNode that passes the
+                // name filter above, and then refines that result.
+                //
+                // It is critical that the filter predicate be as simple and fast as possible, as it
+                // will be called a ton, triggered by keystrokes or anything else that modifies code
+                // in or even related to (in either direction) the pre-filtered code.
+                // It should collect metadata only and not actually generate any code.
+                // It must return a boolean indicating whether the supplied SyntaxNode should be
+                // given to the transform delegate at all.
+                // 
+                // The third parameter is the "transform" delegate.
+                // That one only runs when code is changed that passed both the attribute name filter
+                // and the filter predicate in the second parameter.
+                // It will be called for everything that passes both of those, so it can still happen
+                // a lot, but should at least be pretty close.
+                // In our case, it should be 100% accurate, since we're using OUR attribute, which can
+                // only be applied to enum types in the first place.
+                //
+                // That delegate is responsible for creating some sort of lightweight data structure
+                // which can later be used to generate the actual source code for output.
+                //
+                // THIS DELEGATE DOES NOT GENERATE CODE!
+                // However, it does need to return instances of the metadata class in use that are either
+                // null or complete enough to generate meaningful code from, later on.
+                //
+                // We then filter out any that were null with the .Where call at the end, so that we don't
+                // know or care about them when it's time to generate code.
+                //
+                // While the syntax of that .Where call is the same as LINQ, that is actually a
+                // highly-optimized implementation specifically for this use.
+                .ForAttributeWithMetadataName (
+                                               GeneratorAttributeFullyQualifiedName,
+                                               IsPotentiallyInterestingDeclaration,
+                                               GatherMetadataForCodeGeneration
+                                              )
+                .WithTrackingName ("CollectEnumMetadata")
+                .Where (static eInfo => eInfo is { });
+
+        // Finally, we wire up any IncrementalValuesProvider<T> instances above to the appropriate
+        // delegate that takes the SourceProductionContext that is current at run-time and an instance of
+        // our metadata type and takes appropriate action.
+        // Typically that means generating code from that metadata and adding it to the compilation via
+        // the received context object.
+        //
+        // As with everything else , the delegate will be invoked once for each item that passed
+        // all of the filters above, so we get to write that method from the perspective of a single
+        // enum type declaration.
+
+        context.RegisterSourceOutput (enumGenerationInfos, GenerateSourceFromGenerationInfo);
+    }
+
+    private static EnumExtensionMethodsGenerationInfo? GatherMetadataForCodeGeneration (
+        GeneratorAttributeSyntaxContext context,
+        CancellationToken cancellationToken
+    )
+    {
+        var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
+        cancellationToken.ThrowIfCancellationRequested ();
+
+        // If it's not an enum symbol, we don't care.
+        // EnumUnderlyingType is null for non-enums, so this validates it's an enum declaration.
+        if (context.TargetSymbol is not INamedTypeSymbol { EnumUnderlyingType: { } } namedSymbol)
+        {
+            return null;
+        }
+
+        INamespaceSymbol? enumNamespaceSymbol = namedSymbol.ContainingNamespace;
+
+        if (enumNamespaceSymbol is null or { IsGlobalNamespace: true })
+        {
+            // Explicitly choosing not to support enums in the global namespace.
+            // The corresponding analyzer will report this.
+            return null;
+        }
+
+        string enumName = namedSymbol.Name;
+
+        string enumNamespace = enumNamespaceSymbol.ToDisplayString (_fullyQualifiedSymbolDisplayFormatWithoutGlobal);
+
+        TypeCode enumTypeCode = namedSymbol.EnumUnderlyingType.Name switch
+                                {
+                                    "UInt32" => TypeCode.UInt32,
+                                    "Int32" => TypeCode.Int32,
+                                    _ => TypeCode.Empty
+                                };
+
+        EnumExtensionMethodsGenerationInfo info = new (
+                                                       enumNamespace,
+                                                       enumName,
+                                                       enumTypeCode
+                                                      );
+
+        if (!info.TryConfigure (namedSymbol, cts.Token))
+        {
+            cts.Cancel ();
+            cts.Token.ThrowIfCancellationRequested ();
+        }
+
+        return info;
+    }
+
+
+    private static void GenerateAttributeSources (IncrementalGeneratorPostInitializationContext postInitializationContext)
+    {
+        postInitializationContext
+            .AddSource (
+                        $"{nameof (IExtensionsForEnumTypeAttributes)}.g.cs",
+                        SourceText.From (
+                                         $$"""
+                                           // ReSharper disable All
+                                           {{Strings.Templates.AutoGeneratedCommentBlock}}
+                                           using System;
+
+                                           namespace {{Strings.AnalyzersAttributesNamespace}};
+
+                                           /// <summary>
+                                           ///     Interface to simplify general enumeration of constructed generic types for
+                                           ///     <see cref="ExtensionsForEnumTypeAttribute{TEnum}"/>
+                                           /// </summary>
+                                           {{Strings.Templates.AttributesForGeneratedInterfaces}}
+                                           public interface IExtensionsForEnumTypeAttributes
+                                           {
+                                               System.Type EnumType { get; }
+                                           }
+
+                                           """,
+                                         Encoding.UTF8));
+
+        postInitializationContext
+            .AddSource (
+                        $"{nameof (AssemblyExtendedEnumTypeAttribute)}.g.cs",
+                        SourceText.From (
+                                         $$"""
+                                           // ReSharper disable All
+                                           #nullable enable
+                                           {{Strings.Templates.AutoGeneratedCommentBlock}}
+
+                                           namespace {{Strings.AnalyzersAttributesNamespace}};
+
+                                           /// <summary>Assembly attribute declaring a known pairing of an <see langword="enum" /> type to an extension class.</summary>
+                                           /// <remarks>This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported.</remarks>
+                                           {{Strings.Templates.AttributesForGeneratedTypes}}
+                                           [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true)]
+                                           public sealed class {{nameof(AssemblyExtendedEnumTypeAttribute)}} : System.Attribute
+                                           {
+                                               /// <summary>Creates a new instance of <see cref="AssemblyExtendedEnumTypeAttribute" /> from the provided parameters.</summary>
+                                               /// <param name="enumType">The <see cref="System.Type" /> of an <see langword="enum" /> decorated with a <see cref="GenerateEnumExtensionMethodsAttribute" />.</param>
+                                               /// <param name="extensionClass">The <see cref="System.Type" /> of the <see langword="class" /> decorated with an <see cref="ExtensionsForEnumTypeAttribute{TEnum}" /> referring to the same type as <paramref name="enumType" />.</param>
+                                               public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass)
+                                               {
+                                                   EnumType = enumType;
+                                                   ExtensionClass = extensionClass;
+                                               }
+                                               /// <summary>An <see langword="enum" /> type that has been extended by Terminal.Gui source generators.</summary>
+                                               public System.Type EnumType { get; init; }
+                                               /// <summary>A class containing extension methods for <see cref="EnumType"/>.</summary>
+                                               public System.Type ExtensionClass { get; init; }
+                                               /// <inheritdoc />
+                                               public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}";
+                                           }
+
+                                           """,
+                                         Encoding.UTF8));
+
+        postInitializationContext
+            .AddSource (
+                        $"{GeneratorAttributeFullyQualifiedName}.g.cs",
+                        SourceText.From (
+                                         $$"""
+                                           {{Strings.Templates.StandardHeader}}
+                                           
+                                           namespace {{Strings.AnalyzersAttributesNamespace}};
+
+                                           /// <summary>
+                                           ///     Used to enable source generation of a common set of extension methods for enum types.
+                                           /// </summary>
+                                           {{Strings.Templates.AttributesForGeneratedTypes}}
+                                           [{{Strings.DotnetNames.Types.AttributeUsageAttribute}} ({{Strings.DotnetNames.Types.AttributeTargets}}.Enum)]
+                                           public sealed class {{GeneratorAttributeName}} : {{Strings.DotnetNames.Types.Attribute}}
+                                           {
+                                               /// <summary>
+                                               ///     The name of the generated static class.
+                                               /// </summary>
+                                               /// <remarks>
+                                               ///     If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".<br/>
+                                               ///     No other validation is performed, so illegal values will simply result in compiler errors.
+                                               ///     <para>
+                                               ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+                                               ///     </para>
+                                               /// </remarks>
+                                               public string? ClassName { get; set; }
+                                           
+                                               /// <summary>
+                                               ///     The namespace in which to place the generated static class containing the extension methods.
+                                               /// </summary>
+                                               /// <remarks>
+                                               ///     If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.<br/>
+                                               ///     No other validation is performed, so illegal values will simply result in compiler errors.
+                                               ///     <para>
+                                               ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+                                               ///     </para>
+                                               /// </remarks>
+                                               public string? ClassNamespace { get; set; }
+                                           
+                                               /// <summary>
+                                               ///     Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in
+                                               ///     <see cref="Enum.HasFlag"/> method.
+                                               /// </summary>
+                                               /// <remarks>
+                                               ///     <para>
+                                               ///         Default: false
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         If the enum is not decorated with <see cref="Flags"/>, this option has no effect.
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         If multiple members have the same value, the first member with that value will be used and subsequent members
+                                               ///         with the same value will be skipped.
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         Overloads taking the enum type itself as well as the underlying type of the enum will be generated, enabling
+                                               ///         avoidance of implicit or explicit cast overhead.
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
+                                               ///     </para>
+                                               /// </remarks>
+                                               public bool FastHasFlags { get; set; }
+                                           
+                                               /// <summary>
+                                               ///     Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in
+                                               ///     <see cref="Enum.IsDefined"/> method,
+                                               ///     using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members.
+                                               /// </summary>
+                                               /// <remarks>
+                                               ///     <para>
+                                               ///         Default: true
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         If multiple members have the same value, the first member with that value will be used and subsequent members
+                                               ///         with the same value will be skipped.
+                                               ///     </para>
+                                               ///     <para>
+                                               ///         As with <see cref="Enum.IsDefined"/> the source generator only considers explicitly-named members.<br/>
+                                               ///         Generation of values which represent valid bitwise combinations of members of enums decorated with
+                                               ///         <see cref="Flags"/> is not affected by this property.
+                                               ///     </para>
+                                               /// </remarks>
+                                               public bool FastIsDefined { get; init; } = true;
+                                           
+                                               /// <summary>
+                                               ///     Gets a <see langword="bool"/> value indicating if this <see cref="GenerateEnumExtensionMethodsAttribute"/> instance
+                                               ///     contains default values only. See <see href="#remarks">remarks</see> of this method or documentation on properties of this type for details.
+                                               /// </summary>
+                                               /// <returns>
+                                               ///     A <see langword="bool"/> value indicating if all property values are default for this
+                                               ///     <see cref="GenerateEnumExtensionMethodsAttribute"/> instance.
+                                               /// </returns>
+                                               /// <remarks>
+                                               ///     Default values that will result in a <see langword="true"/> return value are:<br/>
+                                               ///     <see cref="FastIsDefined"/> &amp;&amp; !<see cref="FastHasFlags"/> &amp;&amp; <see cref="ClassName"/>
+                                               ///     <see langword="is"/> <see langword="null"/> &amp;&amp; <see cref="ClassNamespace"/> <see langword="is"/>
+                                               ///     <see langword="null"/>
+                                               /// </remarks>
+                                               public override bool IsDefaultAttribute ()
+                                               {
+                                                   return FastIsDefined
+                                                          && !FastHasFlags
+                                                          && ClassName is null
+                                                          && ClassNamespace is null;
+                                               }
+                                           }
+                                           
+                                           """,
+                                         Encoding.UTF8));
+
+        postInitializationContext
+            .AddSource (
+                        $"{ExtensionsForEnumTypeAttributeFullyQualifiedName}.g.cs",
+                        SourceText.From (
+                                         $$"""
+                                           // ReSharper disable RedundantNameQualifier
+                                           // ReSharper disable RedundantNullableDirective
+                                           // ReSharper disable UnusedType.Global
+                                           {{Strings.Templates.AutoGeneratedCommentBlock}}
+                                           #nullable enable
+
+                                           namespace {{Strings.AnalyzersAttributesNamespace}};
+
+                                           /// <summary>
+                                           ///     Attribute written by the source generator for enum extension classes, for easier analysis and reflection.
+                                           /// </summary>
+                                           /// <remarks>
+                                           ///     Properties are just convenient shortcuts to properties of <typeparamref name="TEnum"/>.
+                                           /// </remarks>
+                                           {{Strings.Templates.AttributesForGeneratedTypes}}
+                                           [System.AttributeUsageAttribute (System.AttributeTargets.Class | System.AttributeTargets.Interface)]
+                                           public sealed class {{ExtensionsForEnumTypeAttributeName}}<TEnum>: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, Enum
+                                           {
+                                               /// <summary>
+                                               ///     The namespace-qualified name of <typeparamref name="TEnum"/>.
+                                               /// </summary>
+                                               public string EnumFullName => EnumType.FullName!;
+                                           
+                                               /// <summary>
+                                               ///     The unqualified name of <typeparamref name="TEnum"/>.
+                                               /// </summary>
+                                               public string EnumName => EnumType.Name;
+                                           
+                                               /// <summary>
+                                               ///     The namespace containing <typeparamref name="TEnum"/>.
+                                               /// </summary>
+                                               public string EnumNamespace => EnumType.Namespace!;
+                                           
+                                               /// <summary>
+                                               ///     The <see cref="Type"/> given by <see langword="typeof"/>(<typeparamref name="TEnum"/>).
+                                               /// </summary>
+                                               public Type EnumType => typeof (TEnum);
+                                           }
+                                           
+                                           """,
+                                         Encoding.UTF8));
+    }
+
+    [SuppressMessage ("Roslynator", "RCS1267", Justification = "Intentionally used so that Spans are used.")]
+    private static void GenerateDummyNamespaces (IncrementalGeneratorPostInitializationContext postInitializeContext)
+    {
+        postInitializeContext.AddSource (
+                                         string.Concat (Strings.InternalAnalyzersNamespace, "Namespaces.g.cs"),
+                                         SourceText.From (Strings.Templates.DummyNamespaceDeclarations, Encoding.UTF8));
+    }
+
+    private static void GenerateSourceFromGenerationInfo (SourceProductionContext context, EnumExtensionMethodsGenerationInfo? enumInfo)
+    {
+        // Just in case we still made it this far with a null...
+        if (enumInfo is not { })
+        {
+            return;
+        }
+
+        CodeWriter writer = new (enumInfo);
+
+        context.AddSource ($"{enumInfo.FullyQualifiedClassName}.g.cs", writer.GenerateSourceText ());
+    }
+
+    /// <summary>
+    ///     Returns true if <paramref name="syntaxNode"/> is an EnumDeclarationSyntax
+    ///     whose parent is a NamespaceDeclarationSyntax, FileScopedNamespaceDeclarationSyntax, or a
+    ///     (Class|Struct)DeclarationSyntax.<br/>
+    ///     Additional filtering is performed in later stages.
+    /// </summary>
+    private static bool IsPotentiallyInterestingDeclaration (SyntaxNode syntaxNode, CancellationToken cancellationToken)
+    {
+        cancellationToken.ThrowIfCancellationRequested ();
+
+        return syntaxNode is
+               {
+                   RawKind: 8858, //(int)SyntaxKind.EnumDeclaration,
+                   Parent.RawKind: 8845 //(int)SyntaxKind.FileScopedNamespaceDeclaration
+                                   or 8842 //(int)SyntaxKind.NamespaceDeclaration
+                                   or 8855 //(int)SyntaxKind.ClassDeclaration
+                                   or 8856 //(int)SyntaxKind.StructDeclaration
+                                   or 9068 //(int)SyntaxKind.RecordStructDeclaration
+                                   or 9063 //(int)SyntaxKind.RecordDeclaration
+               };
+    }
+}

+ 3 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/GlobalSuppressions.cs

@@ -0,0 +1,3 @@
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage ("Naming", "CA1708:Names should differ by more than case", Scope = "module", Justification = "That's coming from an external generator.")]

+ 38 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/IGeneratedTypeMetadata.cs

@@ -0,0 +1,38 @@
+using JetBrains.Annotations;
+using Microsoft.CodeAnalysis;
+
+namespace Terminal.Gui.Analyzers.Internal;
+
+/// <summary>
+/// Interface for all generators to use for their metadata classes.
+/// </summary>
+/// <typeparam name="TSelf">The type implementing this interface.</typeparam>
+internal interface IGeneratedTypeMetadata<out TSelf> where TSelf : IGeneratedTypeMetadata<TSelf>
+{
+    [UsedImplicitly]
+    string GeneratedTypeNamespace { get; }
+    [UsedImplicitly]
+    string? GeneratedTypeName { get; }
+    [UsedImplicitly]
+    string GeneratedTypeFullName { get; }
+    [UsedImplicitly]
+    string TargetTypeNamespace { get; }
+    [UsedImplicitly]
+    string TargetTypeName { get; }
+    string TargetTypeFullName { get; }
+    [UsedImplicitly]
+    Accessibility Accessibility { get; }
+    TypeKind TypeKind { get; }
+    bool IsRecord { get; }
+    bool IsClass { get; }
+    bool IsStruct { get; }
+    [UsedImplicitly]
+    bool IsPartial { get; }
+    bool IsByRefLike { get; }
+    bool IsSealed { get; }
+    bool IsAbstract { get; }
+    bool IsEnum { get; }
+    bool IsStatic { get; }
+    [UsedImplicitly]
+    bool IncludeInterface { get; }
+}

+ 28 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/IStandardCSharpCodeGenerator.cs

@@ -0,0 +1,28 @@
+using System.Text;
+using JetBrains.Annotations;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Terminal.Gui.Analyzers.Internal;
+
+internal interface IStandardCSharpCodeGenerator<T> where T : IGeneratedTypeMetadata<T>
+{
+    /// <summary>
+    ///     Generates and returns the full source text corresponding to <see cref="Metadata"/>,
+    ///     in the requested <paramref name="encoding"/> or <see cref="Encoding.UTF8"/> if not provided.
+    /// </summary>
+    /// <param name="encoding">
+    ///     The <see cref="Encoding"/> of the generated source text or <see cref="Encoding.UTF8"/> if not
+    ///     provided.
+    /// </param>
+    /// <returns></returns>
+    [UsedImplicitly]
+    [SkipLocalsInit]
+    ref readonly SourceText GenerateSourceText (Encoding? encoding = null);
+
+    /// <summary>
+    ///     A type implementing <see cref="IGeneratedTypeMetadata{T}"/> which
+    ///     will be used for source generation.
+    /// </summary>
+    [UsedImplicitly]
+    T Metadata { get; set; }
+}

+ 71 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/IndentedTextWriterExtensions.cs

@@ -0,0 +1,71 @@
+using System.CodeDom.Compiler;
+
+namespace Terminal.Gui.Analyzers.Internal;
+
+/// <summary>
+///     Just a simple set of extension methods to increment and decrement the indentation
+///     level of an <see cref="IndentedTextWriter"/> via push and pop terms, and to avoid having
+///     explicit values all over the place.
+/// </summary>
+public static class IndentedTextWriterExtensions
+{
+    /// <summary>
+    ///     Decrements <see cref="IndentedTextWriter.Indent"/> by 1, but only if it is greater than 0.
+    /// </summary>
+    /// <returns>
+    ///     The resulting indentation level of the <see cref="IndentedTextWriter"/>.
+    /// </returns>
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    public static int Pop (this IndentedTextWriter w, string endScopeDelimiter = "}")
+    {
+        if (w.Indent > 0)
+        {
+            w.Indent--;
+            w.WriteLine (endScopeDelimiter);
+        }
+        return w.Indent;
+    }
+
+    /// <summary>
+    ///     Decrements <see cref="IndentedTextWriter.Indent"/> by 1 and then writes a closing curly brace.
+    /// </summary>
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    public static void PopCurly (this IndentedTextWriter w, bool withSemicolon = false)
+    {
+        w.Indent--;
+
+        if (withSemicolon)
+        {
+            w.WriteLine ("};");
+        }
+        else
+        {
+            w.WriteLine ('}');
+        }
+    }
+
+    /// <summary>
+    ///     Increments <see cref="IndentedTextWriter.Indent"/> by 1, with optional parameters to customize the scope push.
+    /// </summary>
+    /// <param name="w">An instance of an <see cref="IndentedTextWriter"/>.</param>
+    /// <param name="declaration">
+    ///     The first line to be written before indenting and before the optional <paramref name="scopeDelimiter"/> line or
+    ///     null if not needed.
+    /// </param>
+    /// <param name="scopeDelimiter">
+    ///     An opening delimiter to write. Written before the indentation and after <paramref name="declaration"/> (if provided). Default is an opening curly brace.
+    /// </param>
+    /// <remarks>Calling with no parameters will write an opening curly brace and a line break at the current indentation and then increment.</remarks>
+    [MethodImpl (MethodImplOptions.AggressiveInlining)]
+    public static void Push (this IndentedTextWriter w, string? declaration = null, char scopeDelimiter = '{')
+    {
+        if (declaration is { Length: > 0 })
+        {
+            w.WriteLine (declaration);
+        }
+
+        w.WriteLine (scopeDelimiter);
+
+        w.Indent++;
+    }
+}

+ 8 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Properties/launchSettings.json

@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "InternalAnalyzers Debug": {
+      "commandName": "DebugRoslynComponent",
+      "targetProject": "..\\Terminal.Gui.Analyzers.Internal.Debugging\\Terminal.Gui.Analyzers.Internal.Debugging.csproj"
+    }
+  }
+}

+ 63 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj

@@ -0,0 +1,63 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <!-- 
+        Do not remove netstandard2.0 from the TargetFramework.
+        Visual Studio requires that Analyzers/Generators target netstandard2.0 to work properly.
+        Also do not change this to TargetFrameworks without fully understanding the behavior change that implies.
+        -->
+        <TargetFramework>netstandard2.0</TargetFramework>
+    </PropertyGroup>
+
+    <PropertyGroup>
+        <OutputType>Library</OutputType>
+        <LangVersion>12</LangVersion>
+        <RootNamespace>Terminal.Gui.Analyzers.Internal</RootNamespace>
+        <ImplicitUsings>disable</ImplicitUsings>
+        <InvariantGlobalization>true</InvariantGlobalization>
+        <EnableNETAnalyzers>true</EnableNETAnalyzers>
+        <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+        <CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode>
+        <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
+        <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
+        <GenerateDocumentationFile>True</GenerateDocumentationFile>
+        <IsRoslynComponent>true</IsRoslynComponent>
+        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <ApiCompatExcludeAttributesFile Include="ApiCompatExcludedAttributes.txt" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <Compile Remove="Compatibility/*.cs" />
+    </ItemGroup>
+
+    <PropertyGroup>
+        <!-- Disabling some useless warnings caused by the netstandard2.0 target -->
+        <NoWarn>$(NoWarn);nullable;CA1067</NoWarn>
+    </PropertyGroup>
+    <ItemGroup>                           
+        <Compile Include="Compatibility/IEqualityOperators.cs" />             
+        <Compile Include="Compatibility/NumericExtensions.cs" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <AdditionalFiles Include="AnalyzerReleases.Unshipped.md" />
+        <AdditionalFiles Include="AnalyzerReleases.Shipped.md" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <PackageReference Include="Meziantou.Polyfill" Version="1.0.38" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.9.2" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
+        <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.Analyzers" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.CSharp" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" PrivateAssets="all" />
+        <PackageReference Include="System.Runtime.Extensions" Version="4.3.1" PrivateAssets="all" />
+        <PackageReference Include="System.Runtime.Numerics" Version="4.3.0" PrivateAssets="all" />
+    </ItemGroup>
+</Project>

+ 4 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj.DotSettings

@@ -0,0 +1,4 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String>
+	<s:String x:Key="/Default/CodeInspection/Highlighting/UsageCheckingInspectionLevel/@EntryValue">InternalsOnly</s:String>
+	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=compatibility/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>

+ 19 - 13
CONTRIBUTING.md

@@ -33,7 +33,7 @@ You now have your own fork and a local repo that references it as `origin`. Your
 
 ### Starting to Make a Change
 
-Ensure your local `develop` branch is up-to-date with `upstream` (`github.com/gui-cs/Terminal.Gui`):
+Ensure your local `develop` (for v1) or `v2_develop` (for v2) branch is up-to-date with `upstream` (`github.com/gui-cs/Terminal.Gui`):
 ```powershell
 cd ./Terminal.Gui
 git checkout develop
@@ -45,12 +45,12 @@ Create a new local branch:
 git checkout -b my_new_branch
 ```
 
-#### Making Changes
+### Making Changes
 Follow all the guidelines below.
 
-* Coding Style
-* Unit Tests
-* Sample Code
+* [Coding Style](#TerminalGui-Coding-Style)
+* [Unit Tests](#Unit-Tests)
+* [Sample Code](#Sample-Code)
 * API Documentation
 * etc...
 
@@ -92,7 +92,13 @@ Follow the template instructions found on Github.
 
 ## Terminal.Gui Coding Style
 
-**Terminal.Gui** follows the [Mono Coding Guidelines](https://www.mono-project.com/community/contributing/coding-guidelines/). [`/.editorconfig`](https://github.com/gui-cs/Terminal.Gui/blob/b0a43ba338adf5ec069066e5a7dff8fea39b41db/.editorconfig) enforces this style in Visual Studio. Use `Ctrl-K-D` in Visual Studio to have it reformat code.
+**Terminal.Gui** uses a derivative of the [Microsoft C# Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions), with any deviations from those (somewhat older) conventions codified in the .editorconfig for the solution, as well as even more specific definitions in team-shared dotsettings files, used by ReSharper and Rider.\
+Before you commit code, please run the formatting rules on **only the code file(s) you have modified**, in one of the following ways, in order of most preferred to least preferred:
+
+ 1. `Ctrl-E-C` if using ReSharper or Rider
+ 2. Running the free [CleanupCode](https://www.jetbrains.com/help/resharper/CleanupCode.html) tool from JetBrains (this applies the same formatting rules as if you had used ReSharper or Rider, but is free for all users, if you don't have a license for those products)
+     - Run at the command line, from the solution root directory, as: `cleanupcode.exe relative/path/to/your/file.cs`
+ 3. If you are unable to use either of those options, the last resort is to use `Ctrl-K-D` in Visual Studio (with default C# developer key bindings), to apply the subset of the formatting rules that Visual Studio can apply.
 
 ## User Experience Tenets
 
@@ -118,13 +124,13 @@ Follow the template instructions found on Github.
 
 ### Include API Documentation
 
-Great care has been provided thus far in ensuring **Terminal.Gui** has great [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.html). Contributors have the responsibility of continuously improving the API Documentation.
+Great care has been provided thus far in ensuring **Terminal.Gui** has great [API Documentation](https://gui-cs.github.io/Terminal.Gui). Contributors have the responsibility of continuously improving the API Documentation.
 
 - All public APIs must have clear, concise, and complete documentation in the form of [XML Documentation](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/).
 - Keep the `<summary></summary>` terse.
 - Use `<see cref=""/>` liberally to cross-link topics.
 - Use `<remarks></remarks>` to add more context and explanation.
-- For complex topics, provide conceptual documentation in the `docfx/articles` folder as a `.md` file. It will automatically get picked up and be added to [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/articles/index.html).
+- For complex topics, provide conceptual documentation in the `docfx/articles` folder as a `.md` file. It will automatically get picked up and be added to [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/docs/index.html).
 - Use proper English and good grammar.
 
 ### Defining Events
@@ -148,15 +154,15 @@ The [Microsoft .NET Framework Design Guidelines](https://docs.microsoft.com/en-u
 > ✔️ DO name event argument classes with the "EventArgs" suffix.
 
 1. We follow the naming guidelines provided in https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members?redirectedfrom=MSDN
-2. We use the `event Action<T>` idiom.
+2. We use the `event EventHandler<T>` idiom.
 3. For public APIs, the class that can raise the event will implement:
    - A `virtual` event raising function, named as `OnEventToRaise`. Typical implementations will simply do a `EventToRaise?.Invoke(this, eventArgs)`.
-   - An `event` as in `public event Action<EventArgs> EventToRaise`
-   - Consumers of the event can do `theobject.EventToRaise += (args) => {};`
+   - An `event` as in `public event EventHandler<EventArgs> EventToRaise`
+   - Consumers of the event can do `theobject.EventToRaise += (sender, args) => {};`
    - Sub-classes of the class implementing `EventToRaise` can override `OnEventToRaise` as needed.
 4. Where possible, a subclass of `EventArgs` should be provided and the old and new state should be included. By doing this, event handler methods do not have to query the sender for state.
 
-See also: https://www.codeproject.com/Articles/20550/C-Event-Implementation-Fundamentals-Best-Practices
+See also: https://www.codeproject.com../docs/20550/C-Event-Implementation-Fundamentals-Best-Practices
 
 ### Defining new `View` classes
 
@@ -167,7 +173,7 @@ See also: https://www.codeproject.com/Articles/20550/C-Event-Implementation-Fund
 ## Breaking Changes to User Behavior or the Public API
 
 - Tag all pull requests that cause breaking changes to user behavior or the public API with the [breaking-change](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Abreaking-change) tag. This will help project maintainers track and document these.
-- Add a `<remark></remark>` to the XML Documentation to the code describing the breaking change. These will get picked up in the [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.html).
+- Add a `<remark></remark>` to the XML Documentation to the code describing the breaking change. These will get picked up in the [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.html).
 
 ## Unit Tests
 

+ 19 - 0
CommunityToolkitExample/CommunityToolkitExample.csproj

@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
+  </ItemGroup>
+
+</Project>

+ 8 - 0
CommunityToolkitExample/LoginActions.cs

@@ -0,0 +1,8 @@
+namespace CommunityToolkitExample;
+
+internal enum LoginActions
+{
+    Clear,
+    Validation,
+    LoginProgress
+}

+ 62 - 0
CommunityToolkitExample/LoginView.Designer.cs

@@ -0,0 +1,62 @@
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginView : Window
+{
+    private Label titleLabel;
+    private Label usernameLengthLabel;
+    private TextField usernameInput;
+    private Label passwordLengthLabel;
+    private TextField passwordInput;
+    private Label validationLabel;
+    private Button loginButton;
+    private Button clearButton;
+    private Label loginProgressLabel;
+
+    private void InitializeComponent ()
+    {
+        titleLabel = new Label ();
+        titleLabel.Text = "Login Form";
+        Add (titleLabel);
+        usernameLengthLabel = new Label ();
+        usernameLengthLabel.X = Pos.Left (titleLabel);
+        usernameLengthLabel.Y = Pos.Top (titleLabel) + 1;
+        Add (usernameLengthLabel);
+        usernameInput = new TextField ();
+        usernameInput.X = Pos.Right (usernameLengthLabel) + 1;
+        usernameInput.Y = Pos.Top (usernameLengthLabel);
+        usernameInput.Width = 40;
+        Add (usernameInput);
+        passwordLengthLabel = new Label ();
+        passwordLengthLabel.X = Pos.Left (usernameLengthLabel);
+        passwordLengthLabel.Y = Pos.Top (usernameLengthLabel) + 1;
+        Add (passwordLengthLabel);
+        passwordInput = new TextField ();
+        passwordInput.X = Pos.Right (passwordLengthLabel) + 1;
+        passwordInput.Y = Pos.Top (passwordLengthLabel);
+        passwordInput.Width = 40;
+        passwordInput.Secret = true;
+        Add (passwordInput);
+        validationLabel = new Label ();
+        validationLabel.X = Pos.Left (passwordInput);
+        validationLabel.Y = Pos.Top (passwordInput) + 1;
+        Add (validationLabel);
+        loginButton = new Button ();
+        loginButton.X = Pos.Left (validationLabel);
+        loginButton.Y = Pos.Top (validationLabel) + 1;
+        loginButton.Text = "_Login";
+        Add (loginButton);
+        clearButton = new Button ();
+        clearButton.X = Pos.Left (loginButton);
+        clearButton.Y = Pos.Top (loginButton) + 1;
+        clearButton.Text = "_Clear";
+        Add (clearButton);
+        loginProgressLabel = new Label ();
+        loginProgressLabel.X = Pos.Left (clearButton);
+        loginProgressLabel.Y = Pos.Top (clearButton) + 1;
+        loginProgressLabel.Width = 40;
+        loginProgressLabel.Height = 1;
+        Add (loginProgressLabel);
+    }
+}

+ 72 - 0
CommunityToolkitExample/LoginView.cs

@@ -0,0 +1,72 @@
+using CommunityToolkit.Mvvm.Messaging;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginView : IRecipient<Message<LoginActions>>
+{
+    public LoginView (LoginViewModel viewModel)
+    {
+        WeakReferenceMessenger.Default.Register (this);
+        Title = $"Community Toolkit MVVM Example - {Application.QuitKey} to Exit";
+        ViewModel = viewModel;
+        InitializeComponent ();
+        usernameInput.TextChanged += (_, _) =>
+                                     {
+                                         ViewModel.Username = usernameInput.Text;
+                                     };
+        passwordInput.TextChanged += (_, _) =>
+                                     {
+                                         ViewModel.Password = passwordInput.Text;
+                                     };
+        loginButton.Accept += (_, _) =>
+                              {
+                                  if (!ViewModel.CanLogin) { return; }
+                                  ViewModel.LoginCommand.Execute (null);
+                              };
+
+        clearButton.Accept += (_, _) =>
+                              {
+                                  ViewModel.ClearCommand.Execute (null);
+                              };
+
+        Initialized += (_, _) => { ViewModel.Initialized (); };
+    }
+
+    public LoginViewModel ViewModel { get; set; }
+
+    public void Receive (Message<LoginActions> message)
+    {
+        switch (message.Value)
+        {
+            case LoginActions.Clear:
+                {
+                    loginProgressLabel.Text = ViewModel.LoginProgressMessage;
+                    validationLabel.Text = ViewModel.ValidationMessage;
+                    validationLabel.ColorScheme = ViewModel.ValidationColorScheme;
+                    break;
+                }
+            case LoginActions.LoginProgress:
+                {
+                    loginProgressLabel.Text = ViewModel.LoginProgressMessage;
+                    break;
+                }
+            case LoginActions.Validation:
+                {
+                    validationLabel.Text = ViewModel.ValidationMessage;
+                    validationLabel.ColorScheme = ViewModel.ValidationColorScheme;
+                    break;
+                }
+        }
+        SetText();
+        Application.Refresh ();
+    }
+
+    private void SetText ()
+    {
+        usernameInput.Text = ViewModel.Username;
+        usernameLengthLabel.Text = ViewModel.UsernameLengthMessage;
+        passwordInput.Text = ViewModel.Password;
+        passwordLengthLabel.Text = ViewModel.PasswordLengthMessage;
+    }
+}

+ 128 - 0
CommunityToolkitExample/LoginViewModel.cs

@@ -0,0 +1,128 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginViewModel : ObservableObject
+{
+    private const string DEFAULT_LOGIN_PROGRESS_MESSAGE = "Press 'Login' to log in.";
+    private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password.";
+    private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in...";
+    private const string VALID_LOGIN_MESSAGE = "The input is valid!";
+    
+    [ObservableProperty]
+    private bool _canLogin;
+
+    [ObservableProperty]
+    private string _loginProgressMessage;
+
+    private string _password;
+
+    [ObservableProperty]
+    private string _passwordLengthMessage;
+
+    private string _username;
+
+    [ObservableProperty]
+    private string _usernameLengthMessage;
+    
+    [ObservableProperty]
+    private ColorScheme? _validationColorScheme;
+
+    [ObservableProperty]
+    private string _validationMessage;
+    public LoginViewModel ()
+    {
+        _loginProgressMessage = string.Empty;
+        _password = string.Empty;
+        _passwordLengthMessage = string.Empty;
+        _username = string.Empty;
+        _usernameLengthMessage = string.Empty;
+        _validationMessage = string.Empty;
+
+        Username = string.Empty;
+        Password = string.Empty;
+
+        ClearCommand = new (Clear);
+        LoginCommand = new (Execute);
+
+        Clear ();
+
+        return;
+
+        async void Execute () { await Login (); }
+    }
+
+    public RelayCommand ClearCommand { get; }
+
+    public RelayCommand LoginCommand { get; }
+
+    public string Password
+    {
+        get => _password;
+        set
+        {
+            SetProperty (ref _password, value);
+            PasswordLengthMessage = $"_Password ({_password.Length} characters):";
+            ValidateLogin ();
+        }
+    }
+
+    public string Username
+    {
+        get => _username;
+        set
+        {
+            SetProperty (ref _username, value);
+            UsernameLengthMessage = $"_Username ({_username.Length} characters):";
+            ValidateLogin ();
+        }
+    }
+
+    public void Initialized ()
+    {
+        Clear ();
+    }
+
+    private void Clear ()
+    {
+        Username = string.Empty;
+        Password = string.Empty;
+        SendMessage (LoginActions.Clear, DEFAULT_LOGIN_PROGRESS_MESSAGE);
+    }
+
+    private async Task Login ()
+    {
+        SendMessage (LoginActions.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
+        await Task.Delay (TimeSpan.FromSeconds (1));
+        Clear ();
+    }
+
+    private void SendMessage (LoginActions loginAction, string message = "")
+    {
+        switch (loginAction)
+        {
+             case LoginActions.Clear:
+                LoginProgressMessage = message;
+                ValidationMessage = INVALID_LOGIN_MESSAGE;
+                ValidationColorScheme = Colors.ColorSchemes ["Error"];
+                break;
+            case LoginActions.LoginProgress:
+                LoginProgressMessage = message;
+                break;
+            case LoginActions.Validation:
+                ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
+                ValidationColorScheme = CanLogin ? Colors.ColorSchemes ["Base"] : Colors.ColorSchemes ["Error"];
+                break;
+        }
+        WeakReferenceMessenger.Default.Send (new Message<LoginActions> { Value = loginAction });
+    }
+
+    private void ValidateLogin ()
+    {
+        CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
+        SendMessage (LoginActions.Validation);
+    }
+}

+ 6 - 0
CommunityToolkitExample/Message.cs

@@ -0,0 +1,6 @@
+namespace CommunityToolkitExample;
+
+internal class Message<T>
+{
+    public T? Value { get; set; }
+}

+ 26 - 0
CommunityToolkitExample/Program.cs

@@ -0,0 +1,26 @@
+using Microsoft.Extensions.DependencyInjection;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+public static class Program
+{
+    public static IServiceProvider? Services { get; private set; }
+
+    private static void Main (string [] args)
+    {
+        Services = ConfigureServices ();
+        Application.Init ();
+        Application.Run (Services.GetRequiredService<LoginView> ());
+        Application.Top.Dispose();
+        Application.Shutdown ();
+    }
+
+    private static IServiceProvider ConfigureServices ()
+    {
+        var services = new ServiceCollection ();
+        services.AddTransient<LoginView> ();
+        services.AddTransient<LoginViewModel> ();
+        return services.BuildServiceProvider ();
+    }
+}

+ 154 - 0
CommunityToolkitExample/README.md

@@ -0,0 +1,154 @@
+# CommunityToolkit.MVVM Example
+
+This small demo gives an example of using the `CommunityToolkit.MVVM` framework's `ObservableObject`, `ObservableProperty`, and `IRecipient<T>` in conjunction with `Microsoft.Extensions.DependencyInjection`. 
+
+Right away we use IoC to load our views and view models.
+
+``` csharp
+// As a public property for access further in the application if needed. 
+public static IServiceProvider Services { get; private set; }
+...
+// In Main
+Services = ConfigureServices ();
+...
+private static IServiceProvider ConfigureServices ()
+{
+    var services = new ServiceCollection ();
+    services.AddTransient<LoginView> ();
+    services.AddTransient<LoginViewModel> ();
+    return services.BuildServiceProvider ();
+}
+```
+
+Now, we start the app and get our main view.
+
+``` csharp
+Application.Run (Services.GetRequiredService<LoginView> ());
+```
+
+Our view implements `IRecipient<T>` to demonstrate the use of the `WeakReferenceMessenger`. The binding of the view events is then created.
+
+``` csharp
+internal partial class LoginView : IRecipient<Message<LoginAction>>
+{
+    public LoginView (LoginViewModel viewModel)
+    {
+        // Initialize our Receive method
+        WeakReferenceMessenger.Default.Register (this);
+        ...
+        ViewModel = viewModel;
+        ...
+        passwordInput.TextChanged += (_, _) =>
+                                     {
+                                         ViewModel.Password = passwordInput.Text;
+                                         SetText ();
+                                     };
+        loginButton.Accept += (_, _) =>
+                              {
+                                  if (!ViewModel.CanLogin) { return; }
+                                  ViewModel.LoginCommand.Execute (null);
+                              };
+        ...
+        // Let the view model know the view is intialized.
+        Initialized += (_, _) => { ViewModel.Initialized (); };
+    }
+    ...
+}
+```
+
+Momentarily slipping over to the view model, all bindable properties use some form of `ObservableProperty` with the class deriving from `ObservableObject`. Commands are of the `RelayCommand` type. The use of `ObservableProperty` generates the code for handling `INotifyPropertyChanged` and `INotifyPropertyChanging`.
+
+``` csharp
+internal partial class LoginViewModel : ObservableObject
+{
+    ...
+    [ObservableProperty]
+    private bool _canLogin;
+
+    private string _password;
+    ...
+    public LoginViewModel ()
+    {
+        ...
+        Password = string.Empty;
+        ...   
+        LoginCommand = new (Execute);
+
+        Clear ();
+
+        return;
+
+        async void Execute () { await Login (); }
+    }
+    ...
+    public RelayCommand LoginCommand { get; }
+
+    public string Password
+    {
+        get => _password;
+        set
+        {
+            SetProperty (ref _password, value);
+            PasswordLengthMessage = $"_Password ({_password.Length} characters):";
+            ValidateLogin ();
+        }
+    }
+```
+
+The use of `WeakReferenceMessenger` provides one method of signaling the view from the view model. It's just one way to handle cross-thread messaging in this framework.
+
+``` csharp
+...
+private async Task Login ()
+{
+    SendMessage (LoginAction.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
+    await Task.Delay (TimeSpan.FromSeconds (1));
+    Clear ();
+}
+
+private void SendMessage (LoginAction loginAction, string message = "")
+{
+    switch (loginAction)
+    {
+        case LoginAction.LoginProgress:
+            LoginProgressMessage = message;
+            break;
+        case LoginAction.Validation:
+            ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
+            ValidationColorScheme = CanLogin ? Colors.ColorSchemes ["Base"] : Colors.ColorSchemes ["Error"];
+            break;
+    }
+    WeakReferenceMessenger.Default.Send (new Message<LoginAction> { Value = loginAction });
+}
+
+private void ValidateLogin ()
+{
+    CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
+    SendMessage (LoginAction.Validation);
+}
+...
+```
+
+And the view's `Receive` function which provides an `Application.Refresh()` call to update the UI immediately.
+
+``` csharp
+public void Receive (Message<LoginAction> message)
+{
+    switch (message.Value)
+    {
+        case LoginAction.LoginProgress:
+            {
+                loginProgressLabel.Text = ViewModel.LoginProgressMessage;
+                break;
+            }
+        case LoginAction.Validation:
+            {
+                validationLabel.Text = ViewModel.ValidationMessage;
+                validationLabel.ColorScheme = ViewModel.ValidationColorScheme;
+                break;
+            }
+    }
+    SetText();
+    Application.Refresh ();
+}
+```

+ 6 - 0
Directory.Build.props

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

+ 5 - 0
Directory.Build.targets

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

+ 69 - 59
Example/Example.cs

@@ -3,70 +3,80 @@
 
 // A simple Terminal.Gui example in C# - using C# 9.0 Top-level statements
 
+using System;
 using Terminal.Gui;
 
-Application.Run<ExampleWindow> ();
+var app = Application.Run<ExampleWindow> ();
 
-System.Console.WriteLine ($"Username: {((ExampleWindow)Application.Top).usernameText.Text}");
+Console.WriteLine ($"Username: {app.UserNameText.Text}");
+
+app.Dispose ();
 
 // Before the application exits, reset Terminal.Gui for clean shutdown
 Application.Shutdown ();
 
 // Defines a top-level window with border and title
-public class ExampleWindow : Window {
-	public TextField usernameText;
-	
-	public ExampleWindow ()
-	{
-		Title = $"Example App ({Application.QuitKey} to quit)";
-
-		// Create input components and labels
-		var usernameLabel = new Label () { 
-			Text = "Username:" 
-		};
-
-		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.Clicked += (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");
-			}
-		};
-
-		// Add the views to the Window
-		Add (usernameLabel, usernameText, passwordLabel, passwordText, btnLogin);
-	}
-}
+public class ExampleWindow : Window
+{
+    public TextField UserNameText;
+
+    public ExampleWindow ()
+    {
+        Title = $"Example App ({Application.QuitKey} to quit)";
+
+        // Create input components and labels
+        var usernameLabel = new Label { Text = "Username:" };
+
+        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");
+                                    Application.RequestStop ();
+                                }
+                                else
+                                {
+                                    MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
+                                }
+                            };
+
+        // Add the views to the Window
+        Add (usernameLabel, UserNameText, passwordLabel, passwordText, btnLogin);
+    }
+}

+ 1 - 1
Example/Example.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- Do not modify these. -->

+ 74 - 33
GitVersion.yml

@@ -1,21 +1,14 @@
 mode: ContinuousDeployment
 tag-prefix: '[vV]'
-continuous-delivery-fallback-tag: 'pre'
+continuous-delivery-fallback-tag: pre
 branches:
-  # v1_develop:
-  #   mode: ContinuousDeployment
-  #   tag: pre
-  #   regex: ^v1_develop?[/-]
-  #   is-release-branch: false
-  #   source-branches:
-  #   - v1
-  # v1:
-  #   tag: rc
-  #   increment: Patch
-  #   regex: ^v2?[/-]
-  #   is-release-branch: false
-  #   source-branches: []
-  #   is-mainline: true
+  develop:
+    mode: ContinuousDeployment
+    tag: pre
+    regex: develop
+    source-branches:
+    - main
+    pre-release-weight: 100
 
   v2_develop:
     mode: ContinuousDeployment
@@ -23,28 +16,76 @@ branches:
     regex: ^v2_develop?[/-]
     is-release-branch: true
     tracks-release-branches: true
-    is-source-branch-for: ['v2']
+    #is-source-branch-for: ['v2']
     source-branches: []
-  v2:
-    mode: ContinuousDeployment
-    is-release-branch: false
-    tag: alpha
-    increment: Patch
-    regex: ^v2?[/-]
-    source-branches: ['v2_develop']
 
-  # feature:
-  #   tag: useBranchName
-  #   regex: ^features?[/-]
-  #   source-branches:
-  #   - v1
-  #   - v1_develop
-  #   - v2
-  #   - v2_develop
- 
+  main:
+    tag: rc
+    increment: Patch
+    source-branches:
+    - develop
+    - main
+  feature:
+    tag: useBranchName
+    regex: ^features?[/-]
+    source-branches:
+    - develop
+    - main
   pull-request:
     tag: PullRequest.{BranchName}
     increment: Inherit
 ignore:
   sha: []
-merge-message-formats: {}
+
+
+# next-version: 2.0.0
+# mode: ContinuousDeployment
+# tag-prefix: '[vV]'
+# continuous-delivery-fallback-tag: 'pre'
+# branches:
+#   # v1_develop:
+#   #   mode: ContinuousDeployment
+#   #   tag: pre
+#   #   regex: ^v1_develop?[/-]
+#   #   is-release-branch: false
+#   #   source-branches:
+#   #   - v1
+#   # v1:
+#   #   tag: rc
+#   #   increment: Patch
+#   #   regex: ^v2?[/-]
+#   #   is-release-branch: false
+#   #   source-branches: []
+#   #   is-mainline: true
+
+#   v2_develop:
+#     mode: ContinuousDeployment
+#     tag: pre
+#     regex: ^v2_develop?[/-]
+#     is-release-branch: true
+#     tracks-release-branches: true
+#     is-source-branch-for: ['v2']
+#     source-branches: []
+#   v2:
+#     mode: ContinuousDeployment
+#     is-release-branch: false
+#     tag: alpha
+#     increment: Patch
+#     regex: ^v2?[/-]
+#     source-branches: ['v2_develop']
+
+#   # feature:
+#   #   tag: useBranchName
+#   #   regex: ^features?[/-]
+#   #   source-branches:
+#   #   - v1
+#   #   - v1_develop
+#   #   - v2
+#   #   - v2_develop
+ 
+#   pull-request:
+#     tag: PullRequest.{BranchName}
+#     increment: Inherit
+# ignore:
+#   sha: []
+# merge-message-formats: {}

+ 12 - 0
NoSamples.slnf

@@ -0,0 +1,12 @@
+{
+  "solution": {
+    "path": "Terminal.sln",
+    "projects": [
+      "Analyzers\\Terminal.Gui.Analyzers.Internal.Tests\\Terminal.Gui.Analyzers.Internal.Tests.csproj",
+      "Analyzers\\Terminal.Gui.Analyzers.Internal\\Terminal.Gui.Analyzers.Internal.csproj",
+      "Terminal.Gui\\Terminal.Gui.csproj",
+      "UICatalog\\UICatalog.csproj",
+      "UnitTests\\UnitTests.csproj"
+    ]
+  }
+}

+ 11 - 130
README.md

@@ -9,7 +9,7 @@
 
 ***The current, stable, release of Terminal.Gui is [v1.x](https://www.nuget.org/packages/Terminal.Gui). It is stable, rich, and broadly used. The team is now focused on designing and building a significant upgrade we're referring to as `v2`. Therefore:***
  * *`v1` is now in maintenance mode, meaning we will accept PRs for v1.x (the `develop` branch) only for issues impacting existing functionality.*
- * *All new development happens on the `v2_develop` branch. See the V2 discussion [here](https://github.com/gui-cs/Terminal.Gui/discussions/1940).*
+ * *All new development happens on the `v2_develop` branch. See the V2 discussion [here](https://github.com/gui-cs/Terminal.GuiV2Docs/discussions/1940).*
  * *Developers are encouraged to continue building on [v1.x](https://www.nuget.org/packages/Terminal.Gui) until we announce `v2` is stable.*
 
 **Terminal.Gui**: A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix.
@@ -31,147 +31,28 @@ dotnet run
 
 ## Documentation 
 
-* [Documentation Home](https://gui-cs.github.io/Terminal.Gui/index.html)
-* [Terminal.Gui Overview](https://gui-cs.github.io/Terminal.Gui/articles/overview.html)
-* [List of Views/Controls](https://gui-cs.github.io/Terminal.Gui/articles/views.html)
-* [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/articles/index.html)
-* [API Documentation](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.html)
-
-_The Documentation matches the most recent Nuget release from the `main` branch ([![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui))_
-
-## Features
-
-* **Cross Platform** - Windows, Mac, and Linux. Terminal drivers for Curses, [Windows Console](https://github.com/gui-cs/Terminal.Gui/issues/27), and the .NET Console mean apps will work well on both color and monochrome terminals. 
-* **Keyboard and Mouse Input** - Both keyboard and mouse input are supported, including support for drag & drop.
-* **[Flexible Layout](https://gui-cs.github.io/Terminal.Gui/articles/overview.html#layout)** - Supports both *Absolute layout* and an innovative *Computed Layout* system. *Computed Layout* makes it easy to lay out controls relative to each other and enables dynamic terminal UIs.
-* **Clipboard support** - Cut, Copy, and Paste of text provided through the [`Clipboard`](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.Clipboard.html) class.
-* **[Arbitrary Views](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.View.html)** - All visible UI elements are subclasses of the `View` class, and these in turn can contain an arbitrary number of sub-views.
-* **Advanced App Features** - The [Mainloop](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui/Terminal.Gui.MainLoop.html) supports processing events, idle handlers, timers, and monitoring file
-descriptors. Most classes are safe for threading.
-* **Reactive Extensions** - Use [reactive extensions](https://github.com/dotnet/reactive) and benefit from increased code readability, and the ability to apply the MVVM pattern and [ReactiveUI](https://www.reactiveui.net/) data bindings. See the [source code](https://github.com/gui-cs/Terminal.Gui/tree/master/ReactiveExample) of a sample app in order to learn how to achieve this.
+* [Getting Started](https://gui-cs.github.io/Terminal.GuiV2Docs/docs/getting-started.html)
+* [What's new in v2](https://gui-cs.github.io/Terminal.GuiV2Docs/docs/newinv2.html)
+* [API Documentation](https://gui-cs.github.io/Terminal.GuiV2Docs/api/Terminal.Gui.html)
+* [Documentation Home](https://gui-cs.github.io/Terminal.GuiV2Docs)
 
 ## Showcase & Examples
 
-* **[UI Catalog](https://github.com/gui-cs/Terminal.Gui/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.Gui/tree/master/Example)** - Run `dotnet run` in the `Example` directory to run the C# Example.
-* **[F# Example](https://github.com/gui-cs/Terminal.Gui/tree/master/FSharpExample)** - An example showing how to build a Terminal.Gui app using F#.
-* **[Reactive Example](https://github.com/gui-cs/Terminal.Gui/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](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.
 * **[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#.
 * **[PoshDotnetDumpAnalyzeViewer](https://github.com/En3Tho/PoshDotnetDumpAnalyzeViewer)** - dotnet-dump UI module for PowerShell.
 * **[TerminalGuiDesigner](https://github.com/tznind/TerminalGuiDesigner)** - Cross platform view designer for building Terminal.Gui applications.
 
-See the [`Terminal.Gui/` README](https://github.com/gui-cs/Terminal.Gui/tree/master/Terminal.Gui) for an overview of how the library is structured. The [Conceptual Documentation](https://gui-cs.github.io/Terminal.Gui/articles/index.html) provides insight into core concepts.
-
-## Sample Usage in C#
-
-The following example shows a basic Terminal.Gui application in C#:
-
-```csharp
-// A simple Terminal.Gui example in C# - using C# 9.0 Top-level statements
-
-using Terminal.Gui;
-
-Application.Run<ExampleWindow> ();
-
-System.Console.WriteLine ($"Username: {((ExampleWindow)Application.Top).usernameText.Text}");
-
-// Before the application exits, reset Terminal.Gui for clean shutdown
-Application.Shutdown ();
-
-// Defines a top-level window with border and title
-public class ExampleWindow : Window {
-	public TextField usernameText;
-	
-	public ExampleWindow ()
-	{
-		Title = "Example App (Ctrl+Q to quit)";
-
-		// Create input components and labels
-		var usernameLabel = new Label () { 
-			Text = "Username:" 
-		};
-
-		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.Clicked += () => {
-			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");
-			}
-		};
-
-		// Add the views to the Window
-		Add (usernameLabel, usernameText, passwordLabel, passwordText, btnLogin);
-	}
-}
-```
-
-When run the application looks as follows:
-
-![Simple Usage app](./docfx/images/Example.png)
-
-_Sample application running_
-
-## Installing
-
-Use NuGet to install the `Terminal.Gui` NuGet package: https://www.nuget.org/packages/Terminal.Gui
-
-### Installation in .NET Core Projects
-
-To install Terminal.Gui into a .NET Core project, use the `dotnet` CLI tool with this command.
-
-```
-dotnet add package Terminal.Gui
-```
-
-Or, you can use the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates).
-
-## Building the Library and Running the Examples
-
-* Windows, Mac, and Linux - Build and run using the .NET SDK command line tools (`dotnet build` in the root directory). Run `UICatalog` with `dotnet run --project UICatalog`.
-* Windows - Open `Terminal.sln` with Visual Studio 2022.
-
-See [CONTRIBUTING.md](CONTRIBUTING.md) for instructions for downloading and forking the source.
-
 ## Contributing
 
-See [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.Gui/blob/master/CONTRIBUTING.md).
+See [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.GuiV2Docs/blob/master/CONTRIBUTING.md).
 
-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%3Adesign).
+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).
 
 ## History
 

+ 200 - 180
ReactiveExample/LoginView.cs

@@ -1,185 +1,205 @@
 using System.Reactive.Disposables;
 using System.Reactive.Linq;
-using System.Text;
+using ReactiveMarbles.ObservableEvents;
 using ReactiveUI;
 using Terminal.Gui;
-using ReactiveMarbles.ObservableEvents;
 
-namespace ReactiveExample {
-	public class LoginView : Window, IViewFor<LoginViewModel> {
-		readonly CompositeDisposable _disposable = new CompositeDisposable();
-		
-		public LoginView (LoginViewModel viewModel) : base() {
-			Title = "Reactive Extensions Example";
-			ViewModel = viewModel;
-			var usernameLengthLabel = UsernameLengthLabel (TitleLabel ());
-			var usernameInput = UsernameInput (usernameLengthLabel);
-			var passwordLengthLabel = PasswordLengthLabel (usernameInput);
-			var passwordInput = PasswordInput (passwordLengthLabel);
-			var validationLabel = ValidationLabel (passwordInput);
-			var loginButton = LoginButton (validationLabel);
-			var clearButton = ClearButton (loginButton);
-			LoginProgressLabel (clearButton);
-		}
-		
-		public LoginViewModel ViewModel { get; set; }
-
-		protected override void Dispose (bool disposing) {
-			_disposable.Dispose ();
-			base.Dispose (disposing);
-		}
-
-		Label TitleLabel () {
-			var label = new Label("Login Form");
-			Add (label);
-			return label;
-		}
-
-		TextField UsernameInput (View previous) {
-			var usernameInput = new TextField (ViewModel.Username) {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyValue (x => x.Username)
-				.BindTo (usernameInput, x => x.Text)
-				.DisposeWith (_disposable);
-			usernameInput
-				.Events ()
-				.TextChanged
-				.Select (old => usernameInput.Text)
-				.DistinctUntilChanged ()
-				.BindTo (ViewModel, x => x.Username)
-				.DisposeWith (_disposable);
-			Add (usernameInput);
-			return usernameInput;
-		}
-
-		Label UsernameLengthLabel (View previous) {
-			var usernameLengthLabel = new Label {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyValue (x => x.UsernameLength)
-				.Select (length => $"Username ({length} characters)")
-				.BindTo (usernameLengthLabel, x => x.Text)
-				.DisposeWith (_disposable);
-			Add (usernameLengthLabel);
-			return usernameLengthLabel;
-		}
-
-		TextField PasswordInput (View previous) {
-			var passwordInput = new TextField (ViewModel.Password) {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyValue (x => x.Password)
-				.BindTo (passwordInput, x => x.Text)
-				.DisposeWith (_disposable);
-			passwordInput
-				.Events ()
-				.TextChanged
-				.Select (old => passwordInput.Text)
-				.DistinctUntilChanged ()
-				.BindTo (ViewModel, x => x.Password)
-				.DisposeWith (_disposable);
-			Add (passwordInput);
-			return passwordInput;
-		}
-
-		Label PasswordLengthLabel (View previous) {
-			var passwordLengthLabel = new Label {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyValue (x => x.PasswordLength)
-				.Select (length => $"Password ({length} characters)")
-				.BindTo (passwordLengthLabel, x => x.Text)
-				.DisposeWith (_disposable);
-			Add (passwordLengthLabel);
-			return passwordLengthLabel;
-		}
-
-		Label ValidationLabel (View previous) {
-			var error = "Please, enter user name and password.";
-			var success = "The input is valid!";
-			var validationLabel = new Label(error) {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyValue (x => x.IsValid)	
-				.Select (valid => valid ? success : error)
-				.BindTo (validationLabel, x => x.Text)
-				.DisposeWith (_disposable);
-			ViewModel
-				.WhenAnyValue (x => x.IsValid)	
-				.Select (valid => valid ? Colors.Base : Colors.Error)
-				.BindTo (validationLabel, x => x.ColorScheme)
-				.DisposeWith (_disposable);
-			Add (validationLabel);
-			return validationLabel;
-		}
-
-		Label LoginProgressLabel (View previous) {
-			var progress = "Logging in...";
-			var idle = "Press 'Login' to log in.";
-			var loginProgressLabel = new Label(idle) {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			ViewModel
-				.WhenAnyObservable (x => x.Login.IsExecuting)
-				.Select (executing => executing ? progress : idle)
-				.ObserveOn (RxApp.MainThreadScheduler)
-				.BindTo (loginProgressLabel, x => x.Text)
-				.DisposeWith (_disposable);
-			Add (loginProgressLabel);
-			return loginProgressLabel;
-		}
-
-		Button LoginButton (View previous) {
-			var loginButton = new Button ("Login") {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			loginButton
-				.Events ()
-				.Clicked
-				.InvokeCommand (ViewModel, x => x.Login)
-				.DisposeWith (_disposable);
-			Add (loginButton);
-			return loginButton;
-		}
-
-		Button ClearButton (View previous) {
-			var clearButton = new Button("Clear") {
-				X = Pos.Left(previous),
-				Y = Pos.Top(previous) + 1,
-				Width = 40
-			};
-			clearButton
-				.Events ()
-				.Clicked
-				.InvokeCommand (ViewModel, x => x.Clear)
-				.DisposeWith (_disposable);
-			Add (clearButton);
-			return clearButton;
-		}
-		
-		object IViewFor.ViewModel {
-			get => ViewModel;
-			set => ViewModel = (LoginViewModel) value;
-		}
-	}
-}
+namespace ReactiveExample;
+
+public class LoginView : Window, IViewFor<LoginViewModel>
+{
+    private readonly CompositeDisposable _disposable = new ();
+
+    public LoginView (LoginViewModel viewModel)
+    {
+        Title = $"Reactive Extensions Example - {Application.QuitKey} to Exit";
+        ViewModel = viewModel;
+        Label usernameLengthLabel = UsernameLengthLabel (TitleLabel ());
+        TextField usernameInput = UsernameInput (usernameLengthLabel);
+        Label passwordLengthLabel = PasswordLengthLabel (usernameLengthLabel);
+        TextField passwordInput = PasswordInput (passwordLengthLabel);
+        Label validationLabel = ValidationLabel (passwordInput);
+        Button loginButton = LoginButton (validationLabel);
+        Button clearButton = ClearButton (loginButton);
+        LoginProgressLabel (clearButton);
+    }
+
+    public LoginViewModel ViewModel { get; set; }
+
+    object IViewFor.ViewModel
+    {
+        get => ViewModel;
+        set => ViewModel = (LoginViewModel)value;
+    }
+
+    protected override void Dispose (bool disposing)
+    {
+        _disposable.Dispose ();
+        base.Dispose (disposing);
+    }
+
+    private Button ClearButton (View previous)
+    {
+        var clearButton = new Button
+        {
+            X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Text = "_Clear"
+        };
+
+        clearButton
+            .Events ()
+            .Accept
+            .InvokeCommand (ViewModel, x => x.Clear)
+            .DisposeWith (_disposable);
+        Add (clearButton);
+
+        return clearButton;
+    }
+
+    private Button LoginButton (View previous)
+    {
+        var loginButton = new Button
+        {
+            X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Text = "_Login"
+        };
+
+        loginButton
+            .Events ()
+            .Accept
+            .InvokeCommand (ViewModel, x => x.Login)
+            .DisposeWith (_disposable);
+        Add (loginButton);
+
+        return loginButton;
+    }
+
+    private Label LoginProgressLabel (View previous)
+    {
+        var progress = "Logging in...";
+        var idle = "Press 'Login' to log in.";
+
+        var loginProgressLabel = new Label
+        {
+            X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Width = 40, Height = 1, Text = idle
+        };
+
+        ViewModel
+            .WhenAnyObservable (x => x.Login.IsExecuting)
+            .Select (executing => executing ? progress : idle)
+            .ObserveOn (RxApp.MainThreadScheduler)
+            .BindTo (loginProgressLabel, x => x.Text)
+            .DisposeWith (_disposable);
+        Add (loginProgressLabel);
+
+        return loginProgressLabel;
+    }
+
+    private TextField PasswordInput (View previous)
+    {
+        var passwordInput = new TextField
+        {
+            X = Pos.Right (previous) + 1, Y = Pos.Top (previous), Width = 40, Text = ViewModel.Password
+        };
+
+        ViewModel
+            .WhenAnyValue (x => x.Password)
+            .BindTo (passwordInput, x => x.Text)
+            .DisposeWith (_disposable);
+
+        passwordInput
+            .Events ()
+            .TextChanged
+            .Select (old => passwordInput.Text)
+            .DistinctUntilChanged ()
+            .BindTo (ViewModel, x => x.Password)
+            .DisposeWith (_disposable);
+        Add (passwordInput);
+
+        return passwordInput;
+    }
+
+    private Label PasswordLengthLabel (View previous)
+    {
+        var passwordLengthLabel = new Label { X = Pos.Left (previous), Y = Pos.Top (previous) + 1, };
+
+        ViewModel
+            .WhenAnyValue (x => x.PasswordLength)
+            .Select (length => $"_Password ({length} characters):")
+            .BindTo (passwordLengthLabel, x => x.Text)
+            .DisposeWith (_disposable);
+        Add (passwordLengthLabel);
+
+        return passwordLengthLabel;
+    }
+
+    private Label TitleLabel ()
+    {
+        var label = new Label { Text = "Login Form" };
+        Add (label);
+
+        return label;
+    }
+
+    private TextField UsernameInput (View previous)
+    {
+        var usernameInput = new TextField
+        {
+            X = Pos.Right (previous) + 1, Y = Pos.Top (previous), Width = 40, Text = ViewModel.Username
+        };
+
+        ViewModel
+            .WhenAnyValue (x => x.Username)
+            .BindTo (usernameInput, x => x.Text)
+            .DisposeWith (_disposable);
+
+        usernameInput
+            .Events ()
+            .TextChanged
+            .Select (old => usernameInput.Text)
+            .DistinctUntilChanged ()
+            .BindTo (ViewModel, x => x.Username)
+            .DisposeWith (_disposable);
+        Add (usernameInput);
+
+        return usernameInput;
+    }
+
+    private Label UsernameLengthLabel (View previous)
+    {
+        var usernameLengthLabel = new Label { X = Pos.Left (previous), Y = Pos.Top (previous) + 1 };
+
+        ViewModel
+            .WhenAnyValue (x => x.UsernameLength)
+            .Select (length => $"_Username ({length} characters):")
+            .BindTo (usernameLengthLabel, x => x.Text)
+            .DisposeWith (_disposable);
+        Add (usernameLengthLabel);
+
+        return usernameLengthLabel;
+    }
+
+    private Label ValidationLabel (View previous)
+    {
+        var error = "Please enter a valid user name and password.";
+        var success = "The input is valid!";
+
+        var validationLabel = new Label
+        {
+           X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Text = error
+        };
+
+        ViewModel
+            .WhenAnyValue (x => x.IsValid)
+            .Select (valid => valid ? success : error)
+            .BindTo (validationLabel, x => x.Text)
+            .DisposeWith (_disposable);
+
+        ViewModel
+            .WhenAnyValue (x => x.IsValid)
+            .Select (valid => valid ? Colors.ColorSchemes ["Base"] : Colors.ColorSchemes ["Error"])
+            .BindTo (validationLabel, x => x.ColorScheme)
+            .DisposeWith (_disposable);
+        Add (validationLabel);
+
+        return validationLabel;
+    }
+}

+ 81 - 70
ReactiveExample/LoginViewModel.cs

@@ -1,78 +1,89 @@
 using System;
+using System.ComponentModel;
 using System.Reactive;
 using System.Reactive.Linq;
 using System.Runtime.Serialization;
 using System.Threading.Tasks;
-using System.Text;
 using ReactiveUI;
 using ReactiveUI.Fody.Helpers;
 
-namespace ReactiveExample {
-	//
-	// This view model can be easily shared across different UI frameworks.
-	// For example, if you have a WPF or XF app with view models written
-	// this way, you can easily port your app to Terminal.Gui by implementing
-	// the views with Terminal.Gui classes and ReactiveUI bindings.
-	//
-	// We mark the view model with the [DataContract] attributes and this
-	// allows you to save the view model class to the disk, and then to read
-	// the view model from the disk, making your app state persistent.
-	// See also: https://www.reactiveui.net/docs/handbook/data-persistence/
-	//
-	[DataContract]
-	public class LoginViewModel : ReactiveObject {
-		readonly ObservableAsPropertyHelper<int> _usernameLength;
-		readonly ObservableAsPropertyHelper<int> _passwordLength;
-		readonly ObservableAsPropertyHelper<bool> _isValid;
-		
-		public LoginViewModel () {
-			var canLogin = this.WhenAnyValue (
-				x => x.Username, 
-				x => x.Password,
-				(username, password) =>
-					!string.IsNullOrEmpty (username) &&
-					!string.IsNullOrEmpty (password));
-			
-			_isValid = canLogin.ToProperty (this, x => x.IsValid);
-			Login = ReactiveCommand.CreateFromTask (
-				() => Task.Delay (TimeSpan.FromSeconds (1)),
-				canLogin);
-			
-			_usernameLength = this
-				.WhenAnyValue (x => x.Username)
-				.Select (name => name.Length)
-				.ToProperty (this, x => x.UsernameLength);
-			_passwordLength = this
-				.WhenAnyValue (x => x.Password)
-				.Select (password => password.Length)
-				.ToProperty (this, x => x.PasswordLength);
-			
-			Clear = ReactiveCommand.Create (() => { });
-			Clear.Subscribe (unit => {
-				Username = string.Empty;
-				Password = string.Empty;
-			});
-		}
-		
-		[Reactive, DataMember]
-		public string Username { get; set; } = string.Empty;
-		
-		[Reactive, DataMember]
-		public string Password { get; set; } = string.Empty;
-		
-		[IgnoreDataMember]
-		public int UsernameLength => _usernameLength.Value;
-		
-		[IgnoreDataMember]
-		public int PasswordLength => _passwordLength.Value;
-
-		[IgnoreDataMember]
-		public ReactiveCommand<Unit, Unit> Login { get; }
-		
-		[IgnoreDataMember]
-		public ReactiveCommand<Unit, Unit> Clear { get; }
-		
-		[IgnoreDataMember]
-		public bool IsValid => _isValid.Value;
-	}
-}
+namespace ReactiveExample;
+
+//
+// This view model can be easily shared across different UI frameworks.
+// For example, if you have a WPF or XF app with view models written
+// this way, you can easily port your app to Terminal.Gui by implementing
+// the views with Terminal.Gui classes and ReactiveUI bindings.
+//
+// We mark the view model with the [DataContract] attributes and this
+// allows you to save the view model class to the disk, and then to read
+// the view model from the disk, making your app state persistent.
+// See also: https://www.reactiveui.net../docs/handbook/data-persistence/
+//
+[DataContract]
+public class LoginViewModel : ReactiveObject
+{
+    private readonly ObservableAsPropertyHelper<bool> _isValid;
+    private readonly ObservableAsPropertyHelper<int> _passwordLength;
+    private readonly ObservableAsPropertyHelper<int> _usernameLength;
+
+    public LoginViewModel ()
+    {
+        IObservable<bool> canLogin = this.WhenAnyValue (
+                                                        x => x.Username,
+                                                        x => x.Password,
+                                                        (username, password) =>
+                                                            !string.IsNullOrEmpty (username) && !string.IsNullOrEmpty (password)
+                                                       );
+
+        _isValid = canLogin.ToProperty (this, x => x.IsValid);
+
+        Login = ReactiveCommand.CreateFromTask<CancelEventArgs> (
+                                                                 e => Task.Delay (TimeSpan.FromSeconds (1)),
+                                                                 canLogin
+                                                                );
+
+        _usernameLength = this
+                          .WhenAnyValue (x => x.Username)
+                          .Select (name => name.Length)
+                          .ToProperty (this, x => x.UsernameLength);
+
+        _passwordLength = this
+                          .WhenAnyValue (x => x.Password)
+                          .Select (password => password.Length)
+                          .ToProperty (this, x => x.PasswordLength);
+
+        Clear = ReactiveCommand.Create<CancelEventArgs> (e => { });
+
+        Clear.Subscribe (
+                         unit =>
+                         {
+                             Username = string.Empty;
+                             Password = string.Empty;
+                         }
+                        );
+    }
+
+    [IgnoreDataMember]
+    public ReactiveCommand<CancelEventArgs, Unit> Clear { get; }
+
+    [IgnoreDataMember]
+    public bool IsValid => _isValid.Value;
+
+    [IgnoreDataMember]
+    public ReactiveCommand<CancelEventArgs, Unit> Login { get; }
+
+    [Reactive]
+    [DataMember]
+    public string Password { get; set; } = string.Empty;
+
+    [IgnoreDataMember]
+    public int PasswordLength => _passwordLength.Value;
+
+    [Reactive]
+    [DataMember]
+    public string Username { get; set; } = string.Empty;
+
+    [IgnoreDataMember]
+    public int UsernameLength => _usernameLength.Value;
+}

+ 14 - 11
ReactiveExample/Program.cs

@@ -2,14 +2,17 @@
 using ReactiveUI;
 using Terminal.Gui;
 
-namespace ReactiveExample {
-	public static class Program {
-		static void Main (string [] args) {
-			Application.Init ();
-			RxApp.MainThreadScheduler = TerminalScheduler.Default;
-			RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
-			Application.Run (new LoginView (new LoginViewModel ()));
-			Application.Shutdown ();
-		}
-	}
-}
+namespace ReactiveExample;
+
+public static class Program
+{
+    private static void Main (string [] args)
+    {
+        Application.Init ();
+        RxApp.MainThreadScheduler = TerminalScheduler.Default;
+        RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
+        Application.Run (new LoginView (new LoginViewModel ()));
+        Application.Top.Dispose();
+        Application.Shutdown ();
+    }
+}

+ 1 - 1
ReactiveExample/README.md

@@ -17,7 +17,7 @@ From now on, you can use `.ObserveOn(RxApp.MainThreadScheduler)` to return to th
 
 ### Data Bindings
 
-If you wish to implement `OneWay` data binding, then use the `WhenAnyValue` [ReactiveUI extension method](https://www.reactiveui.net/docs/handbook/when-any/) that listens to `INotifyPropertyChanged` events of the specified property, and converts that events into `IObservable<TProperty>`:
+If you wish to implement `OneWay` data binding, then use the `WhenAnyValue` [ReactiveUI extension method](https://www.reactiveui.net../docs/handbook/when-any/) that listens to `INotifyPropertyChanged` events of the specified property, and converts that events into `IObservable<TProperty>`:
 
 ```cs
 // 'usernameInput' is 'TextField' 

+ 4 - 4
ReactiveExample/ReactiveExample.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 2.0 for all projects. -->
     <!-- Do not modify these. -->
@@ -11,9 +11,9 @@
     <InformationalVersion>2.0</InformationalVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="ReactiveUI.Fody" Version="19.2.1" />
-    <PackageReference Include="ReactiveUI" Version="19.2.1" />
-    <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.2.3" PrivateAssets="all" />
+    <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
+    <PackageReference Include="ReactiveUI" Version="20.0.1" />
+    <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.3.1" PrivateAssets="all" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />

+ 55 - 36
ReactiveExample/TerminalScheduler.cs

@@ -3,39 +3,58 @@ using System.Reactive.Concurrency;
 using System.Reactive.Disposables;
 using Terminal.Gui;
 
-namespace ReactiveExample {
-	public class TerminalScheduler : LocalScheduler {
-		public static readonly TerminalScheduler Default = new TerminalScheduler();
-		TerminalScheduler () { }
-
-		public override IDisposable Schedule<TState> (
-			TState state, TimeSpan dueTime,
-			Func<IScheduler, TState, IDisposable> action) {
-			
-			IDisposable PostOnMainLoop() {
-				var composite = new CompositeDisposable(2);
-				var cancellation = new CancellationDisposable();
-				Application.MainLoop.Invoke (() => {
-					if (!cancellation.Token.IsCancellationRequested)
-						composite.Add(action(this, state));
-				});
-				composite.Add(cancellation);
-				return composite;
-			}
-
-			IDisposable PostOnMainLoopAsTimeout () {
-				var composite = new CompositeDisposable (2);
-				var timeout = Application.MainLoop.AddTimeout (dueTime, args => {
-					composite.Add(action (this, state));
-					return false;
-				});
-				composite.Add (Disposable.Create (() => Application.MainLoop.RemoveTimeout (timeout)));
-				return composite;
-			}
-
-			return dueTime == TimeSpan.Zero 
-				? PostOnMainLoop ()
-				: PostOnMainLoopAsTimeout ();
-		}
-	}
-}
+namespace ReactiveExample;
+
+public class TerminalScheduler : LocalScheduler
+{
+    public static readonly TerminalScheduler Default = new ();
+    private TerminalScheduler () { }
+
+    public override IDisposable Schedule<TState> (
+        TState state,
+        TimeSpan dueTime,
+        Func<IScheduler, TState, IDisposable> action
+    )
+    {
+        IDisposable PostOnMainLoop ()
+        {
+            var composite = new CompositeDisposable (2);
+            var cancellation = new CancellationDisposable ();
+
+            Application.Invoke (
+                                () =>
+                                {
+                                    if (!cancellation.Token.IsCancellationRequested)
+                                    {
+                                        composite.Add (action (this, state));
+                                    }
+                                }
+                               );
+            composite.Add (cancellation);
+
+            return composite;
+        }
+
+        IDisposable PostOnMainLoopAsTimeout ()
+        {
+            var composite = new CompositeDisposable (2);
+
+            object timeout = Application.AddTimeout (
+                                                     dueTime,
+                                                     () =>
+                                                     {
+                                                         composite.Add (action (this, state));
+
+                                                         return false;
+                                                     }
+                                                    );
+            composite.Add (Disposable.Create (() => Application.RemoveTimeout (timeout)));
+
+            return composite;
+        }
+
+        return dueTime == TimeSpan.Zero
+                   ? PostOnMainLoop ()
+                   : PostOnMainLoopAsTimeout ();
+    }
+}

+ 11 - 0
Release.slnf

@@ -0,0 +1,11 @@
+{
+  "solution": {
+    "path": "Terminal.sln",
+    "projects": [
+      "Analyzers\\Terminal.Gui.Analyzers.Internal\\Terminal.Gui.Analyzers.Internal.csproj",
+      "Terminal.Gui\\Terminal.Gui.csproj",
+      "UICatalog\\UICatalog.csproj",
+      "UnitTests\\UnitTests.csproj"
+    ]
+  }
+}

+ 16 - 0
Scripts/COPYRIGHT

@@ -0,0 +1,16 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// The MIT License (MIT)
+// Copyright © 2024 Brandon Thetford (@dodexahedron)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

+ 46 - 0
Scripts/README.md

@@ -0,0 +1,46 @@
+## Development and Design-Time PowerShell Modules
+This directory contains PowerShell modules for use when working with Terminal.sln
+
+### Purpose
+These modules will be modifed and extended as time goes on, whenever someone decides to add something to make life easier.
+
+### Requirements
+These modules are designed for **PowerShell Core, version 7.4 or higher**, on any platform, and must be run directly within a pwsh process.\
+If you want to use them from within another application, such as PowerShell hosted inside VSCode, you must first run `pwsh` in that terminal.
+
+As the primary development environment for Terminal.Gui is Visual Studio 2022+, some functionality may be limited, unavailable, or not work on platforms other than Windows.\
+Most should still work on Linux, however.\
+Functions which are platform-specific will be documented as such in their Get-Help documentation.
+
+Specific requirements for each module can be found in the module manifests and will be automatically imported or, if unavailable, PowerShell will tell you what's missing.
+
+### Usage
+From a PowerShell 7.4 or higher prompt, navigate to your Terminal.Gui repository directory, and then into the Scripts directory (the same directory as this document).
+
+#### Import Module and Configure Environment
+Run the following command to import all Terminal.Gui.PowerShell.* modules:
+```powershell
+Import-Module ./Terminal.Gui.PowerShell.psd1
+```
+If the environment meets the requirements, the modules will now be loaded into the current powershell session and exported commands will be immediately available for use.
+
+#### Getting Help
+All exported functions and commandlets are provided with full PowerShell help annotations compatible with `Get-Help`.
+
+See [The Get-Help documentation at Microsoft Learn]([https://](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-help?view=powershell-7.4)) for Get-Help information.
+
+#### Cleaning Up/Resetting Environment
+No environment changes made by the modules on import are persistent.
+
+When you are finished using the modules, you can optionally unload the modules, which will also reset the configuration changes made on import, by simply exiting the PowerShell session (`exit`) or by running the following command:\
+**NOTE DIFFERENT TEXT FROM IMPORT COMMAND!**
+```powershell
+Remove-Module Terminal.Gui.PowerShell
+```
+
+### LICENSE
+MIT License
+
+Original Author: Brandon Thetford (@dodexahedron)
+
+See COPYRIGHT in this directory for license text.

+ 117 - 0
Scripts/Terminal.Gui.PowerShell.Analyzers.psd1

@@ -0,0 +1,117 @@
+#
+# Module manifest for module 'Terminal.Gui.Powershell.Analyzers'
+#
+# Generated by: Brandon Thetford (GitHub @dodexahedron)
+#
+# Generated on: 4/24/2024
+#
+
+@{
+
+# Script module or binary module file associated with this manifest.
+RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+CompatiblePSEditions = @('Core')
+
+# ID used to uniquely identify this module
+GUID = '3e85001d-6539-4cf1-b71c-ec9e983f7fc8'
+
+# Author of this module
+Author = 'Brandon Thetford (GitHub @dodexahedron)'
+
+# Company or vendor of this module
+CompanyName = 'The Terminal.Gui Project'
+
+# Copyright statement for this module
+Copyright = '(c) Brandon Thetford (GitHub @dodexahedron). Provided to the Terminal.Gui project and you under the terms of the MIT License.'
+
+# Description of the functionality provided by this module
+Description = 'Operations involving Terminal.Gui analyzer projects, fur use during development of Terminal.Gui'
+
+# Minimum version of the PowerShell engine required by this module
+PowerShellVersion = '7.4.0'
+
+# Name of the PowerShell host required by this module
+PowerShellHostName = 'ConsoleHost'
+
+# Minimum version of the PowerShell host required by this module
+# PowerShellHostVersion = ''
+
+# Processor architecture (None, X86, Amd64) required by this module
+ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+RequiredModules = @('Microsoft.PowerShell.Management','Microsoft.PowerShell.Utility','./Terminal.Gui.PowerShell.Core.psd1')
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules.
+NestedModules = @('./Terminal.Gui.PowerShell.Analyzers.psm1')
+
+# Functions to export from this module.
+FunctionsToExport = @('Build-Analyzers')
+
+# Cmdlets to export from this module.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = @()
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+AliasesToExport = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+    PSData = @{
+
+        # Tags applied to this module. These help with module discovery in online galleries.
+        # Tags = @()
+
+        # A URL to the license for this module.
+        LicenseUri = 'https://github.com/gui-cs/Terminal.Gui/Scripts/COPYRIGHT'
+
+        # A URL to the main website for this project.
+        ProjectUri = 'https://github.com/gui-cs/Terminal.Gui'
+
+        # A URL to an icon representing this module.
+        # IconUri = ''
+
+        # ReleaseNotes of this module
+        # ReleaseNotes = ''
+
+        # Prerelease string of this module
+        # Prerelease = ''
+
+        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+        # RequireLicenseAcceptance = $false
+
+        # External dependent modules of this module
+        # ExternalModuleDependencies = @()
+
+    } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+

+ 96 - 0
Scripts/Terminal.Gui.PowerShell.Analyzers.psm1

@@ -0,0 +1,96 @@
+<#
+  .SYNOPSIS
+  Builds all analyzer projects in Debug and Release configurations.
+  .DESCRIPTION
+  Uses dotnet build to build all analyzer projects, with optional behavior changes via switch parameters.
+  .PARAMETER AutoClose
+  Automatically close running Visual Studio processes which have the Terminal.sln solution loaded, before taking any other actions.
+  .PARAMETER AutoLaunch
+  Automatically start a new Visual Studio process and load the solution after completion.
+  .PARAMETER Force
+  Carry out operations unconditionally and do not prompt for confirmation.
+  .PARAMETER NoClean
+  Do not delete the bin and obj folders before building the analyzers. Usually best not to use this, but can speed up the builds slightly.
+  .PARAMETER Quiet
+  Write less text output to the terminal.
+  .INPUTS
+  None
+  .OUTPUTS
+  None
+#>
+Function Build-Analyzers {
+  [CmdletBinding()]
+  param(
+    [Parameter(Mandatory=$false, HelpMessage="Automatically close running Visual Studio processes which have the Terminal.sln solution loaded, before taking any other actions.")]
+    [switch]$AutoClose,
+    [Parameter(Mandatory=$false, HelpMessage="Automatically start a new Visual Studio process and load the solution after completion.")]
+    [switch]$AutoLaunch,
+    [Parameter(Mandatory=$false, HelpMessage="Carry out operations unconditionally and do not prompt for confirmation.")]
+    [switch]$Force,
+    [Parameter(Mandatory=$false, HelpMessage="Do not delete the bin and obj folders before building the analyzers.")]
+    [switch]$NoClean,
+    [Parameter(Mandatory=$false, HelpMessage="Write less text output to the terminal.")]
+    [switch]$Quiet
+  )
+  
+  if($AutoClose) {
+    if(!$Quiet) {
+      Write-Host Closing Visual Studio processes
+    }
+    Close-Solution
+  }
+
+  if($Force){
+    $response = 'Y'
+  }
+  elseif(!$Force && $NoClean){
+    $response = ($r = Read-Host "Pre-build Terminal.Gui.InternalAnalyzers without removing old build artifacts? [Y/n]") ? $r : 'Y'
+  }
+  else{
+    $response = ($r = Read-Host "Delete bin and obj folders for Terminal.Gui and Terminal.Gui.InternalAnalyzers and pre-build Terminal.Gui.InternalAnalyzers? [Y/n]") ? $r : 'Y'
+  }
+
+  if (($response -ne 'Y')) {
+    Write-Host Took no action
+    return
+  }
+  
+  Push-Location $InternalAnalyzersProjectDirectory
+  
+  if(!$NoClean) {
+    if(!$Quiet) {
+      Write-Host Deleting bin and obj folders for Terminal.Gui
+    }
+    Remove-Item -Recurse -Force $TerminalGuiProjectDirectory/bin -ErrorAction SilentlyContinue
+    Remove-Item -Recurse -Force $TerminalGuiProjectDirectory/obj -ErrorAction SilentlyContinue
+
+    if(!$Quiet) {
+      Write-Host Deleting bin and obj folders for Terminal.Gui.InternalAnalyzers
+    }
+    Remove-Item -Recurse -Force $InternalAnalyzersProjectDirectory/bin -ErrorAction SilentlyContinue
+    Remove-Item -Recurse -Force $InternalAnalyzersProjectDirectory/obj -ErrorAction SilentlyContinue
+  }
+  
+  if(!$Quiet) {
+    Write-Host Building analyzers in Debug configuration
+  }
+  dotnet build $InternalAnalyzersProjectFilePath --no-incremental --nologo --force --configuration Debug
+
+  if(!$Quiet) {
+    Write-Host Building analyzers in Release configuration
+  }
+  dotnet build $InternalAnalyzersProjectFilePath --no-incremental --nologo --force --configuration Release
+
+  Pop-Location
+  
+  if(!$AutoLaunch) {
+    Write-Host -ForegroundColor Green Finished. Restart Visual Studio for changes to take effect.
+  } else {
+    if(!$Quiet) {
+      Write-Host -ForegroundColor Green Finished. Re-loading Terminal.sln.
+    }
+    Open-Solution
+  }
+
+  return
+}

+ 131 - 0
Scripts/Terminal.Gui.PowerShell.Build.psd1

@@ -0,0 +1,131 @@
+@{
+
+# No root module because this is a manifest module.
+RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+CompatiblePSEditions = @('Core')
+
+# ID used to uniquely identify this module
+GUID = 'c4a1de77-83fb-45a3-b1b5-18d275ef3601'
+
+# Author of this module
+Author = 'Brandon Thetford (GitHub @dodexahedron)'
+
+# Company or vendor of this module
+CompanyName = 'The Terminal.Gui Project'
+
+# Copyright statement for this module
+Copyright = 'Brandon Thetford (GitHub @dodexahedron), provided to the Terminal.Gui project and you under the MIT license'
+
+# Description of the functionality provided by this module
+Description = 'Build helper functions for Terminal.Gui.'
+
+# Minimum version of the PowerShell engine required by this module
+PowerShellVersion = '7.4.0'
+
+# Name of the PowerShell "host" subsystem (not system host name). Helps ensure that we know what to expect from the environment.
+PowerShellHostName = 'ConsoleHost'
+
+# Minimum version of the PowerShell host required by this module
+PowerShellHostVersion = '7.4.0'
+
+# Processor architecture (None, MSIL, X86, IA64, Amd64, Arm, or an empty string) required by this module. One value only.
+# Set to AMD64 here because development on Terminal.Gui isn't really supported on anything else.
+# Has nothing to do with runtime use of Terminal.Gui.
+ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+RequiredModules = @(
+    @{
+        ModuleName='Microsoft.PowerShell.Utility'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='Microsoft.PowerShell.Management'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='PSReadLine'
+        ModuleVersion='2.3.4'
+    },
+    "./Terminal.Gui.PowerShell.Core.psd1"
+)
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules.
+NestedModules = @('./Terminal.Gui.PowerShell.Build.psm1')
+
+# Functions to export from this module.
+FunctionsToExport = @('Build-TerminalGui')
+
+# Cmdlets to export from this module.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = @()
+
+# Aliases to export from this module.
+AliasesToExport = @()
+
+# List of all modules packaged with this module
+# ModuleList = @()
+
+# List of all files packaged with this module
+# FileList = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+    PSData = @{
+
+        # Tags applied to this module. These help with module discovery in online galleries.
+        # Tags = @()
+
+        # A URL to the license for this module.
+        LicenseUri = 'https://github.com/gui-cs/Terminal.Gui/tree/v2_develop/Scripts/COPYRIGHT'
+
+        # A URL to the main website for this project.
+        ProjectUri = 'https://github.com/gui-cs/Terminal.Gui'
+
+        # A URL to an icon representing this module.
+        # IconUri = ''
+
+        # ReleaseNotes of this module
+        ReleaseNotes = 'See change history and releases for Terminal.Gui on GitHub'
+
+        # Prerelease string of this module
+        # Prerelease = ''
+
+        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+        RequireLicenseAcceptance = $false
+
+        # External dependent modules of this module
+        # ExternalModuleDependencies = @()
+
+    } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+

+ 32 - 0
Scripts/Terminal.Gui.PowerShell.Build.psm1

@@ -0,0 +1,32 @@
+<#
+  .SYNOPSIS
+  Builds the Terminal.Gui library.
+  .DESCRIPTION
+  Builds the Terminal.Gui library.
+  Optional parameter sets are available to customize the build.
+  .PARAMETER versionBase
+  The base version for the Terminal.Gui library.
+#>
+Function Build-TerminalGui {
+  [CmdletBinding(SupportsShouldProcess, PositionalBinding=$false, DefaultParameterSetName="Basic", ConfirmImpact="Medium")]
+  [OutputType([bool],[PSObject])]
+  param(
+      [Parameter(Mandatory=$true)]
+      [Version]$versionBase,
+      [Parameter(Mandatory=$true, ParameterSetName="Custom")]
+      [switch]$Custom,
+      [Parameter(Mandatory=$false, ParameterSetName="Custom")]
+      [ValidateSet("Debug", "Release")]
+      [string]$slnBuildConfiguration = "Release",
+      [Parameter(Mandatory=$false, ParameterSetName="Custom")]
+      [ValidateSet("Any CPU", "x86"<#, "x64" #>)]
+      [string]$slnBuildPlatform = "Any CPU"
+  )
+
+  if(!$PSCmdlet.ShouldProcess("Building in $slnBuildConfiguration configuration for $slnBuildPlatform", "Terminal.Gui", "BUILDING")) {
+    return $null
+  }
+
+  Write-Host NOT IMPLEMENTED. No Action has been taken.
+  return $false
+}

+ 138 - 0
Scripts/Terminal.Gui.PowerShell.Core.psd1

@@ -0,0 +1,138 @@
+#
+# Module manifest for module 'Terminal.Gui.PowerShell'
+#
+# Generated by: Brandon Thetford (GitHub @dodexahedron)
+#
+# Generated on: 4/19/2024
+#
+
+@{
+
+# No root module because this is a manifest module.
+RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+CompatiblePSEditions = @('Core')
+
+# ID used to uniquely identify this module
+GUID = 'c661fb12-70ae-4a9e-a95c-786a7980681d'
+
+# Author of this module
+Author = 'Brandon Thetford (GitHub @dodexahedron)'
+
+# Company or vendor of this module
+CompanyName = 'The Terminal.Gui Project'
+
+# Copyright statement for this module
+Copyright = 'Brandon Thetford (GitHub @dodexahedron), provided to the Terminal.Gui project and you under the MIT license'
+
+# Description of the functionality provided by this module
+Description = 'Utilities for development-time operations on and management of components of Terminal.Gui code and other assets.'
+
+# Minimum version of the PowerShell engine required by this module
+PowerShellVersion = '7.4.0'
+
+# Name of the PowerShell "host" subsystem (not system host name). Helps ensure that we know what to expect from the environment.
+PowerShellHostName = 'ConsoleHost'
+
+# Minimum version of the PowerShell host required by this module
+PowerShellHostVersion = '7.4.0'
+
+# Processor architecture (None, MSIL, X86, IA64, Amd64, Arm, or an empty string) required by this module. One value only.
+# Set to AMD64 here because development on Terminal.Gui isn't really supported on anything else.
+# Has nothing to do with runtime use of Terminal.Gui.
+ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+RequiredModules = @(
+    @{
+        ModuleName='Microsoft.PowerShell.Utility'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='Microsoft.PowerShell.Management'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='PSReadLine'
+        ModuleVersion='2.3.4'
+    }
+)
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
+NestedModules = @('./Terminal.Gui.PowerShell.Core.psm1')
+
+# Functions to export from this module.
+FunctionsToExport = @('Open-Solution','Close-Solution')
+
+# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = @()
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+AliasesToExport = @()
+
+# List of all modules packaged with this module
+# ModuleList = @()
+
+# List of all files packaged with this module
+# FileList = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+    PSData = @{
+
+        # Tags applied to this module. These help with module discovery in online galleries.
+        # Tags = @()
+
+        # A URL to the license for this module.
+        LicenseUri = 'https://github.com/gui-cs/Terminal.Gui/tree/v2_develop/Scripts/COPYRIGHT'
+
+        # A URL to the main website for this project.
+        ProjectUri = 'https://github.com/gui-cs/Terminal.Gui'
+
+        # A URL to an icon representing this module.
+        # IconUri = ''
+
+        # ReleaseNotes of this module
+        ReleaseNotes = 'See change history and releases for Terminal.Gui on GitHub'
+
+        # Prerelease string of this module
+        # Prerelease = ''
+
+        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+        RequireLicenseAcceptance = $false
+
+        # External dependent modules of this module
+        # ExternalModuleDependencies = @()
+
+    } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+

+ 151 - 0
Scripts/Terminal.Gui.PowerShell.Core.psm1

@@ -0,0 +1,151 @@
+<#
+  .SYNOPSIS
+  (Windows Only) Opens Visual Studio and loads Terminal.sln.
+  .DESCRIPTION
+  (Windows Only) Opens Visual Studio and loads Terminal.sln.
+  .PARAMETER SolutionFilePath
+  (Optional) If specified, the path to the solution file. Typically unnecessary to supply this parameter.
+  .INPUTS
+  None
+  .OUTPUTS
+  None
+#>
+Function Open-Solution {
+  [CmdletBinding()]
+  param(
+    [Parameter(Mandatory=$false, HelpMessage="The path to the solution file to open.")]
+    [ValidatePattern(".*Terminal\.sln" )]
+    [string]$Path = $SolutionFilePath
+  )
+  
+  if(!$IsWindows) {
+    [string]$warningMessage = "The Open-Solution cmdlet is only supported on Windows.`n`
+    Attempt to open file $Path with the system default handler?"
+    
+    Write-Warning $warningMessage -WarningAction Inquire
+  }
+  
+  Invoke-Item $Path
+  return
+}
+
+<#
+  .SYNOPSIS
+  (Windows Only) Closes Visual Studio processes with Terminal.sln loaded.
+  .DESCRIPTION
+  (Windows Only) Closes Visual Studio processes with Terminal.sln loaded by finding any VS processes launched with the solution file or with 'Terminal' in their main window titles.
+  .INPUTS
+  None
+  .OUTPUTS
+  None
+#>
+Function Close-Solution {
+  $vsProcesses = Get-Process -Name devenv | Where-Object { ($_.CommandLine -Match ".*Terminal\.sln.*" -or $_.MainWindowTitle -Match "Terminal.*") }
+  Stop-Process -InputObject $vsProcesses
+  Remove-Variable vsProcesses
+}
+
+<#
+  .SYNOPSIS
+  Sets up a standard environment for other Terminal.Gui.PowerShell scripts and modules.
+  .DESCRIPTION
+  Configures environment variables and global variables for other Terminal.Gui.PowerShell scripts to use.
+  Also modifies the prompt to indicate the session has been altered.
+  Reset changes by exiting the session or by calling Reset-PowerShellEnvironment or ./ResetEnvironment.ps1.
+  .PARAMETER Debug
+  Minimally supported for Write-Debug calls in this function only.
+  .NOTES
+  Mostly does not respect common parameters like WhatIf, Confirm, etc.
+  This is just meant to be called by other scripts.
+  Calling this manually is not supported.
+#>
+Function Set-PowerShellEnvironment {
+  [CmdletBinding()]
+  param()
+
+  # Set up some common globals
+  New-Variable -Name ScriptsDirectory -Value $PSScriptRoot -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name RepositoryRootDirectory -Value (Join-Path -Resolve $ScriptsDirectory "..") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name SolutionFilePath -Value (Join-Path -Resolve $RepositoryRootDirectory "Terminal.sln") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name TerminalGuiProjectDirectory -Value (Join-Path -Resolve $RepositoryRootDirectory "Terminal.Gui") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name TerminalGuiProjectFilePath -Value (Join-Path -Resolve $TerminalGuiProjectDirectory "Terminal.Gui.csproj") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name AnalyzersDirectory -Value (Join-Path -Resolve $RepositoryRootDirectory "Analyzers") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name InternalAnalyzersProjectDirectory -Value (Join-Path -Resolve $AnalyzersDirectory "Terminal.Gui.Analyzers.Internal") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name InternalAnalyzersProjectFilePath -Value (Join-Path -Resolve $InternalAnalyzersProjectDirectory "Terminal.Gui.Analyzers.Internal.csproj") -Option ReadOnly -Scope Global -Visibility Public
+
+  # Save existing PSModulePath for optional reset later.
+  # If it is already saved, do not overwrite, but continue anyway.
+  New-Variable -Name OriginalPSModulePath -Visibility Public -Option ReadOnly -Scope Global -Value ($Env:PSModulePath) -ErrorAction SilentlyContinue
+  Write-Debug -Message "`$OriginalPSModulePath is $OriginalPSModulePath" -Debug:$DebugPreference
+
+  # Get platform-specific path variable entry separator. Continue if it's already set.
+  New-Variable -Name PathVarSeparator -Visibility Public -Option ReadOnly -Scope Global -Value ";" -Description 'Separator character used in environment variables such as $Env:PSModulePath' -ErrorAction SilentlyContinue
+
+  if(!$IsWindows) {
+    $PathVarSeparator = ':'
+  }
+  Write-Debug -Message "`$PathVarSeparator is $PathVarSeparator" -Debug:$DebugPreference
+
+  # If Env:PSModulePath already has the current path, don't append it again.
+  if($Env:PSModulePath -notlike "*$((Resolve-Path .).Path)*") {
+    Write-Debug -Message "Appending $((Resolve-Path .).Path) to `$Env:PSModulePath" -Debug:$DebugPreference
+    $env:PSModulePath = Join-String -Separator $PathVarSeparator -InputObject @( $env:PSModulePath, (Resolve-Path .).Path )
+  }
+  Write-Debug -Message "`$Env:PSModulePath is $Env:PSModulePath" -Debug:$DebugPreference
+}
+
+
+<#
+  .SYNOPSIS
+  Resets changes made by ConfigureEnvironment.pst to the current PowerShell environment.
+  .DESCRIPTION
+  Optional function to undo changes to the current session made by ConfigureEnvironment.ps1.
+  Changes only affect the current session, so exiting will also "reset." 
+  .PARAMETER Exit
+  Switch parameter that, if specified, exits the current PowerShell environment.
+  Does not bother doing any other operations, as none are necessary.
+  .INPUTS
+  None
+  .OUTPUTS
+  None
+  .EXAMPLE
+  Reset-PowerShellEnvironment
+  To undo changes in the current session.
+  .EXAMPLE
+  Reset-PowerShellEnvironment -Exit
+  To exit the current session. Same as simply using the Exit command.
+#>
+Function Reset-PowerShellEnvironment {
+  [CmdletBinding(DefaultParameterSetName="Basic")]
+  param(
+    [Parameter(Mandatory=$false, ParameterSetName="Basic")]
+    [switch]$Exit
+  )
+
+  if($Exit) {
+    [Environment]::Exit(0)
+  }
+
+  if(Get-Variable -Name OriginalPSModulePath -Scope Global -ErrorAction SilentlyContinue){
+    $Env:PSModulePath = $OriginalPSModulePath
+    Remove-Variable -Name OriginalPSModulePath -Scope Global -Force -ErrorAction SilentlyContinue
+  }
+
+  Remove-Variable -Name PathVarSeparator -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name RepositoryRootDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name SolutionFilePath -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name TerminalGuiProjectDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name TerminalGuiProjectFilePath -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name ScriptsDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name AnalyzersDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name InternalAnalyzersProjectDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name InternalAnalyzersProjectFilePath -Scope Global -Force -ErrorAction SilentlyContinue
+}
+
+# This ensures the environment is reset when unloading the module.
+# Without this, function:prompt will be undefined.
+$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { 
+  Reset-PowerShellEnvironment
+}
+
+Set-PowerShellEnvironment

+ 135 - 0
Scripts/Terminal.Gui.PowerShell.Git.psd1

@@ -0,0 +1,135 @@
+#
+# Module manifest for module 'Terminal.Gui.PowerShell.Git'
+#
+# Generated by: Brandon Thetford
+#
+# Generated on: 4/26/2024
+#
+
+@{
+
+# Script module or binary module file associated with this manifest.
+RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+CompatiblePSEditions = 'Core'
+
+# ID used to uniquely identify this module
+GUID = '33a6c4c9-c0a7-4c09-b171-1da0878f93ea'
+
+# Author of this module
+Author = 'Brandon Thetford (GitHub @dodexahedron)'
+
+# Company or vendor of this module
+CompanyName = 'The Terminal.Gui Project'
+
+# Copyright statement for this module
+Copyright = 'Brandon Thetford (GitHub @dodexahedron), provided to the Terminal.Gui project and you under the MIT license'
+
+# Description of the functionality provided by this module
+Description = 'Simple helper commands for common git operations.'
+
+# Minimum version of the PowerShell engine required by this module
+PowerShellVersion = '7.4'
+
+# Name of the PowerShell host required by this module
+PowerShellHostName = 'ConsoleHost'
+
+# Minimum version of the PowerShell host required by this module
+PowerShellHostVersion = '7.4.0'
+
+# Processor architecture (None, MSIL, X86, IA64, Amd64, Arm, or an empty string) required by this module. One value only.
+# Set to AMD64 here because development on Terminal.Gui isn't really supported on anything else.
+# Has nothing to do with runtime use of Terminal.Gui.
+ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+RequiredModules = @(
+    @{
+        ModuleName='Microsoft.PowerShell.Utility'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='Microsoft.PowerShell.Management'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='PSReadLine'
+        ModuleVersion='2.3.4'
+    }
+)
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+FormatsToProcess = @()
+
+# Modules to import as nested modules.
+NestedModules = @("./Terminal.Gui.PowerShell.Git.psm1")
+
+# Functions to export from this module.
+FunctionsToExport = @('New-GitBranch')
+
+# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = @()
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+AliasesToExport = @()
+
+# DSC resources to export from this module
+DscResourcesToExport = @()
+
+# List of all modules packaged with this module
+ModuleList = @('./Terminal.Gui.PowerShell.Git.psm1')
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+    PSData = @{
+
+        # Tags applied to this module. These help with module discovery in online galleries.
+        # Tags = @()
+
+        # A URL to the license for this module.
+        # LicenseUri = ''
+
+        # A URL to the main website for this project.
+        # ProjectUri = ''
+
+        # A URL to an icon representing this module.
+        # IconUri = ''
+
+        # ReleaseNotes of this module
+        # ReleaseNotes = ''
+
+        # Prerelease string of this module
+        # Prerelease = ''
+
+        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+        # RequireLicenseAcceptance = $false
+
+        # External dependent modules of this module
+        # ExternalModuleDependencies = @()
+
+    } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+

+ 111 - 0
Scripts/Terminal.Gui.PowerShell.Git.psm1

@@ -0,0 +1,111 @@
+<#
+  .SYNOPSIS
+  Creates a new branch with the specified name.
+  .DESCRIPTION
+  Creates a new branch with the specified name.
+  .PARAMETER Name
+  The name of the new branch.
+  Always required.
+  Must match the .net regex pattern "v2_\d{4}_[a-zA-Z0-9()_-]+".
+  Must also otherwise be a valid identifier for a git branch and follow any other project guidelines.
+  .PARAMETER NoSwitch
+  If specified, does not automatically switch to your new branch after creating it.
+  Default is to switch to the new branch after creating it.
+  .PARAMETER Push
+  If specified, automatically pushes the new branch to your remote after creating it.
+  .PARAMETER Remote
+  The name of the git remote, as configured.
+  If you never explicitly set this yourself, it is typically "origin".
+  If you only have one remote defined or have not explicitly set a remote yourself, do not provide this parameter; It will be detected automatically.
+  .INPUTS
+  None
+  .OUTPUTS
+  The name of the current branch after the operation, as a String.
+  If NoSwitch was specified and the operation succeeded, this should be the source branch.
+  If NoSwith was not specified or was explicitly set to $false and the operation succeeded, this should be the new branch.
+  If an exception occurs, does not return. Exceptions are unhandled and are the responsibility of the caller.
+  .NOTES
+  Errors thrown by git commands are not explicitly handled.
+#>
+Function New-GitBranch {
+  [CmdletBinding(PositionalBinding=$false, SupportsShouldProcess=$true, ConfirmImpact="Low", DefaultParameterSetName="Basic")]
+  param(
+    [Parameter(Mandatory=$true, ParameterSetName="Basic")]
+    [Parameter(Mandatory=$true, ParameterSetName="NoSwitch")]
+    [Parameter(Mandatory=$true, ParameterSetName="Push")]
+    [ValidatePattern("v2_\d{4}_[a-zA-Z0-9()_-]+")]
+    [string]$Name,
+    [Parameter(Mandatory=$true,ParameterSetName="NoSwitch",DontShow)]
+    [switch]$NoSwitch,
+    [Parameter(Mandatory=$false, ParameterSetName="Basic")]
+    [Parameter(Mandatory=$true, ParameterSetName="Push")]
+    [switch]$Push,
+    [Parameter(Mandatory=$false, ParameterSetName="Push")]
+    [string]$Remote = $null
+  )
+  $currentBranch = (& git branch --show-current)
+
+  if(!$PSCmdlet.ShouldProcess("Creating new branch named $Name from $currentBranch", $Name, "Creating branch")) {
+    return $null
+  }
+
+  git branch $Name
+
+  if(!$NoSwitch) {
+    git switch $Name
+
+    if($Push) {
+      if([String]::IsNullOrWhiteSpace($Remote)) {
+        $tempRemotes = (git remote show)
+        if($tempRemotes -is [array]){
+          # If we've gotten here, Push was specified, a remote was not specified or was blank, and there are multiple remotes defined locally.
+          # Not going to support that. Just error out.
+          Remove-Variable tempRemotes
+          throw "No Remote specified and multiple remotes are defined. Cannot continue."
+        } else {
+          # Push is set, Remote wasn't, but there's only one defined. Safe to continue. Use the only remote.
+          $Remote = $tempRemotes
+          Remove-Variable tempRemotes
+        }
+      }
+
+      # Push is set, and either Remote was specified or there's only one remote defined and we will use that.
+      # Perform the push. 
+      git push --set-upstream $Remote $Name
+    }
+  } else{
+    # NoSwitch was specified.
+    # Return the current branch name.
+    return $currentBranch
+  }
+
+  # If we made it to this point, return the Name that was specified.
+  return $Name
+}
+
+<#
+  .SYNOPSIS
+  Checks if the command 'git' is available in the current session.
+  .DESCRIPTION
+  Checks if the command 'git' is available in the current session.
+  Throws an error if not.
+  Returns $true if git is available.
+  Only intended for use in scripts and module manifests.
+  .INPUTS
+  None
+  .OUTPUTS
+  If git exists, $true.
+  Otherwise, $false.
+#>
+Function Test-GitAvailable {
+  [OutputType([Boolean])]
+  [CmdletBinding()]
+  param()
+  if($null -eq (Get-Command git -ErrorAction Ignore)) {
+    Write-Error -Message "git was not found. Git functionality will not work." -Category ObjectNotFound -TargetObject "git"
+    return $false
+  }
+  return $true
+}
+
+Test-GitAvailable -ErrorAction Continue

+ 150 - 0
Scripts/Terminal.Gui.PowerShell.psd1

@@ -0,0 +1,150 @@
+<#
+  .SYNOPSIS
+  All-inclusive module that includes all other Terminal.Gui.PowerShell.* modules.
+  .DESCRIPTION
+  All-inclusive module that includes all other Terminal.Gui.PowerShell.* modules.
+  .EXAMPLE
+  Import-Module ./Terminal.Gui.PowerShell.psd1
+  .NOTES
+  Doc comments on manifest files are not supported by Get-Help as of PowerShell 7.4.2.
+  This comment block is purely informational and will not interfere with module loading.
+#>
+
+
+@{
+
+# No root module because this is a manifest module.
+RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+CompatiblePSEditions = @('Core')
+
+# ID used to uniquely identify this module
+GUID = 'f28198f9-cf4b-4ab0-9f94-aef5616b7989'
+
+# Author of this module
+Author = 'Brandon Thetford (GitHub @dodexahedron)'
+
+# Company or vendor of this module
+CompanyName = 'The Terminal.Gui Project'
+
+# Copyright statement for this module
+Copyright = 'Brandon Thetford (GitHub @dodexahedron), provided to the Terminal.Gui project and you under the MIT license'
+
+# Description of the functionality provided by this module
+Description = 'Utilities for development-time operations on and management of components of Terminal.Gui code and other assets.'
+
+# Minimum version of the PowerShell engine required by this module
+PowerShellVersion = '7.4.0'
+
+# Name of the PowerShell "host" subsystem (not system host name). Helps ensure that we know what to expect from the environment.
+PowerShellHostName = 'ConsoleHost'
+
+# Minimum version of the PowerShell host required by this module
+PowerShellHostVersion = '7.4.0'
+
+# Processor architecture (None, MSIL, X86, IA64, Amd64, Arm, or an empty string) required by this module. One value only.
+# Set to AMD64 here because development on Terminal.Gui isn't really supported on anything else.
+# Has nothing to do with runtime use of Terminal.Gui.
+ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+RequiredModules = @(
+    @{
+        ModuleName='Microsoft.PowerShell.Utility'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='Microsoft.PowerShell.Management'
+        ModuleVersion='7.0.0'
+    },
+    @{
+        ModuleName='PSReadLine'
+        ModuleVersion='2.3.4'
+    }
+)
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules of this module.
+# This module is just a shortcut that loads all of our modules.
+NestedModules = @('./Terminal.Gui.PowerShell.Core.psd1', './Terminal.Gui.PowerShell.Analyzers.psd1', './Terminal.Gui.PowerShell.Git.psd1', './Terminal.Gui.PowerShell.Build.psd1')
+
+# Functions to export from this module.
+# Not filtered, so exports all functions exported by all nested modules.
+FunctionsToExport = '*'
+
+# Cmdlets to export from this module.
+# We don't have any, so empty array.
+CmdletsToExport = @()
+
+# Variables to export from this module.
+# We explicitly control scope of variables, so empty array.
+VariablesToExport = @()
+
+# Aliases to export from this module.
+# None defined at this time.
+AliasesToExport = @()
+
+# List of all modules packaged with this module
+# This is informational ONLY, so it's just blank right now.
+# ModuleList = @()
+
+# List of all files packaged with this module
+# This is informational ONLY, so it's just blank right now.
+# FileList = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+    PSData = @{
+
+        # Tags applied to this module. These help with module discovery in online galleries.
+        # Tags = @()
+
+        # A URL to the license for this module.
+        LicenseUri = 'https://github.com/gui-cs/Terminal.Gui/tree/v2_develop/Scripts/COPYRIGHT'
+
+        # A URL to the main website for this project.
+        ProjectUri = 'https://github.com/gui-cs/Terminal.Gui'
+
+        # A URL to an icon representing this module.
+        # IconUri = ''
+
+        # ReleaseNotes of this module
+        ReleaseNotes = 'See change history and releases for Terminal.Gui on GitHub'
+
+        # Prerelease string of this module
+        # Prerelease = ''
+
+        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+        RequireLicenseAcceptance = $false
+
+        # External dependent modules of this module
+        # ExternalModuleDependencies = @()
+
+    } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+

+ 0 - 1325
Terminal.Gui/Application.cs

@@ -1,1325 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Linq;
-using System.Globalization;
-using System.Reflection;
-using System.IO;
-using System.Text.Json.Serialization;
-
-namespace Terminal.Gui {
-	/// <summary>
-	/// A static, singleton class representing the application. This class is the entry point for the application.
-	/// </summary>
-	/// <example>
-	/// <code>
-	/// // A simple Terminal.Gui app that creates a window with a frame and title with 
-	/// // 5 rows/columns of padding.
-	/// Application.Init();
-	/// var win = new Window ($"Example App ({Application.QuitKey} to quit)") {
-	///   X = 5,
-	///   Y = 5,
-	///   Width = Dim.Fill (5),
-	///   Height = Dim.Fill (5)
-	/// };
-	/// Application.Top.Add(win);
-	/// Application.Run();
-	/// Application.Shutdown();
-	/// </code>
-	/// </example>
-	/// <remarks>
-	///  <para>
-	///   Creates a instance of <see cref="Terminal.Gui.MainLoop"/> to process input events, handle timers and
-	///   other sources of data. It is accessible via the <see cref="MainLoop"/> property.
-	///  </para>
-	///  <para>
-	///   The <see cref="Iteration"/> event is invoked on each iteration of the <see cref="Terminal.Gui.MainLoop"/>.
-	///  </para>
-	///  <para>
-	///   When invoked it sets the <see cref="SynchronizationContext"/> to one that is tied
-	///   to the <see cref="MainLoop"/>, allowing user code to use async/await.
-	///  </para>
-	/// </remarks>
-	public static partial class Application {
-
-		/// <summary>
-		/// The current <see cref="ConsoleDriver"/> in use.
-		/// </summary>
-		public static ConsoleDriver Driver;
-
-		/// <summary>
-		/// If <see langword="true"/>, forces the use of the System.Console-based (see <see cref="NetDriver"/>) driver. The default is <see langword="false"/>.
-		/// </summary>
-		public static bool UseSystemConsole { get; set; } = false;
-
-		// For Unit testing - ignores UseSystemConsole
-		internal static bool _forceFakeConsole;
-		
-		private static List<CultureInfo> _cachedSupportedCultures;
-
-		/// <summary>
-		/// Gets all cultures supported by the application without the invariant language.
-		/// </summary>
-		public static List<CultureInfo> SupportedCultures => _cachedSupportedCultures;
-
-		private static List<CultureInfo> GetSupportedCultures ()
-		{
-			CultureInfo [] culture = CultureInfo.GetCultures (CultureTypes.AllCultures);
-
-			// Get the assembly
-			Assembly assembly = Assembly.GetExecutingAssembly ();
-
-			//Find the location of the assembly
-			string assemblyLocation = AppDomain.CurrentDomain.BaseDirectory;
-
-			// Find the resource file name of the assembly
-			string resourceFilename = $"{Path.GetFileNameWithoutExtension (assembly.Location)}.resources.dll";
-
-			// Return all culture for which satellite folder found with culture code.
-			return culture.Where (cultureInfo =>
-			   assemblyLocation != null &&
-			   Directory.Exists (Path.Combine (assemblyLocation, cultureInfo.Name)) &&
-			   File.Exists (Path.Combine (assemblyLocation, cultureInfo.Name, resourceFilename))
-			).ToList ();
-		}
-
-		#region Initialization (Init/Shutdown)
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="Terminal.Gui"/> Application. 
-		/// </summary>
-		/// <para>
-		/// Call this method once per instance (or after <see cref="Shutdown"/> has been called).
-		/// </para>
-		/// <para>
-		/// This function loads the right <see cref="ConsoleDriver"/> for the platform, 
-		/// Creates a <see cref="Toplevel"/>. and assigns it to <see cref="Top"/>
-		/// </para>
-		/// <para>
-		/// <see cref="Shutdown"/> must be called when the application is closing (typically after <see cref="Run(Func{Exception, bool})"/> has 
-		/// returned) to ensure resources are cleaned up and terminal settings restored.
-		/// </para>
-		/// <para>
-		/// The <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver, IMainLoopDriver)"/> function 
-		/// combines <see cref="Init(ConsoleDriver, IMainLoopDriver)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
-		/// into a single call. An applciation cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver, IMainLoopDriver)"/> 
-		/// without explicitly calling <see cref="Init(ConsoleDriver, IMainLoopDriver)"/>.
-		/// </para>
-		/// <param name="driver">
-		/// The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the
-		/// platform will be used (see <see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, and <see cref="NetDriver"/>).</param>
-		/// <param name="mainLoopDriver">
-		/// Specifies the <see cref="MainLoop"/> to use. 
-		/// Must not be <see langword="null"/> if <paramref name="driver"/> is not <see langword="null"/>.
-		/// </param>
-		public static void Init (ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) => InternalInit (() => Toplevel.Create (), driver, mainLoopDriver);
-
-		internal static bool _initialized = false;
-		internal static int _mainThreadId = -1;
-
-		// INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop.
-		//
-		// Called from:
-		// 
-		// Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset.
-		// Run<T>() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run<T>() to be called without calling Init first.
-		// 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.
-		internal static void InternalInit (Func<Toplevel> topLevelFactory, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null, bool calledViaRunT = false)
-		{
-			if (_initialized && driver == null) {
-				return;
-			}
-
-			if (_initialized) {
-				throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown.");
-			}
-
-			if (!calledViaRunT) {
-				// Reset all class variables (Application is a singleton).
-				ResetState ();
-			}
-
-			// For UnitTests
-			if (driver != null) {
-				Driver = driver;
-			}
-
-			// Start the process of configuration management.
-			// Note that we end up calling LoadConfigurationFromAllSources
-			// multiple times. We need to do this because some settings are only
-			// valid after a Driver is loaded. In this cases we need just 
-			// `Settings` so we can determine which driver to use.
-			ConfigurationManager.Load (true);
-			ConfigurationManager.Apply ();
-
-			if (Driver == null) {
-				var p = Environment.OSVersion.Platform;
-				if (_forceFakeConsole) {
-					// For Unit Testing only
-					Driver = new FakeDriver ();
-				} else if (UseSystemConsole) {
-					Driver = new NetDriver ();
-				} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
-					Driver = new WindowsDriver ();
-				} else {
-					Driver = new CursesDriver ();
-				}
-				if (Driver == null) {
-					throw new InvalidOperationException ("Init could not determine the ConsoleDriver to use.");
-				}
-			}
-
-			if (mainLoopDriver == null) {
-				// TODO: Move this logic into ConsoleDriver
-				if (Driver is FakeDriver) {
-					mainLoopDriver = new FakeMainLoop (Driver);
-				} else if (Driver is NetDriver) {
-					mainLoopDriver = new NetMainLoop (Driver);
-				} else if (Driver is WindowsDriver) {
-					mainLoopDriver = new WindowsMainLoop (Driver);
-				} else if (Driver is CursesDriver) {
-					mainLoopDriver = new UnixMainLoop (Driver);
-				}
-				if (mainLoopDriver == null) {
-					throw new InvalidOperationException ("Init could not determine the MainLoopDriver to use.");
-				}
-			}
-
-			MainLoop = new MainLoop (mainLoopDriver);
-
-			try {
-				Driver.Init (OnTerminalResized);
-			} catch (InvalidOperationException ex) {
-				// This is a case where the driver is unable to initialize the console.
-				// This can happen if the console is already in use by another process or
-				// if running in unit tests.
-				// In this case, we want to throw a more specific exception.
-				throw new InvalidOperationException ("Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", ex);
-			}
-
-			SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
-
-			Top = topLevelFactory ();
-			Current = Top;
-			_cachedSupportedCultures = GetSupportedCultures ();
-			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
-			_initialized = true;
-		}
-
-
-		/// <summary>
-		/// Shutdown an application initialized with <see cref="Init(ConsoleDriver, IMainLoopDriver)"/>.
-		/// </summary>
-		/// <remarks>
-		/// Shutdown must be called for every call to <see cref="Init(ConsoleDriver, IMainLoopDriver)"/> or <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>
-		/// to ensure all resources are cleaned up (Disposed) and terminal settings are restored.
-		/// </remarks>
-		public static void Shutdown ()
-		{
-			ResetState ();
-			ConfigurationManager.PrintJsonErrors ();
-		}
-
-		// Encapsulate all setting of initial state for Application; Having
-		// this in a function like this ensures we don't make mistakes in
-		// guaranteeing that the state of this singleton is deterministic when Init
-		// starts running and after Shutdown returns.
-		static void ResetState ()
-		{
-			// Shutdown is the bookend for Init. As such it needs to clean up all resources
-			// Init created. Apps that do any threading will need to code defensively for this.
-			// e.g. see Issue #537
-			foreach (var t in _toplevels) {
-				t.Running = false;
-				t.Dispose ();
-			}
-			_toplevels.Clear ();
-			Current = null;
-			Top?.Dispose ();
-			Top = null;
-
-			// BUGBUG: OverlappedTop is not cleared here, but it should be?
-
-			MainLoop?.Stop();
-			MainLoop = null;
-			Driver?.End ();
-			Driver = null;
-			Iteration = null;
-			RootMouseEvent = null;
-			RootKeyEvent = null;
-			TerminalResized = null;
-			_mainThreadId = -1;
-			NotifyNewRunState = null;
-			NotifyStopRunState = null;
-			_initialized = false;
-			_mouseGrabView = null;
-			_lastMouseOwnerView = null;
-
-			// Reset synchronization context to allow the user to run async/await,
-			// as the main loop has been ended, the synchronization context from 
-			// gui.cs does no longer process any callbacks. See #1084 for more details:
-			// (https://github.com/gui-cs/Terminal.Gui/issues/1084).
-			SynchronizationContext.SetSynchronizationContext (syncContext: null);
-		}
-
-		#endregion Initialization (Init/Shutdown)
-
-		#region Run (Begin, Run, End)
-
-		/// <summary>
-		/// Notify that a new <see cref="RunState"/> was created (<see cref="Begin(Toplevel)"/> was called). The token is created in 
-		/// <see cref="Begin(Toplevel)"/> and this event will be fired before that function exits.
-		/// </summary>
-		/// <remarks>
-		///	If <see cref="ExitRunLoopAfterFirstIteration"/> is <see langword="true"/> callers to
-		///	<see cref="Begin(Toplevel)"/> must also subscribe to <see cref="NotifyStopRunState"/>
-		///	and manually dispose of the <see cref="RunState"/> token when the application is done.
-		/// </remarks>
-		public static event EventHandler<RunStateEventArgs> NotifyNewRunState;
-
-		/// <summary>
-		/// Notify that a existent <see cref="RunState"/> is stopping (<see cref="End(RunState)"/> was called).
-		/// </summary>
-		/// <remarks>
-		///	If <see cref="ExitRunLoopAfterFirstIteration"/> is <see langword="true"/> callers to
-		///	<see cref="Begin(Toplevel)"/> must also subscribe to <see cref="NotifyStopRunState"/>
-		///	and manually dispose of the <see cref="RunState"/> token when the application is done.
-		/// </remarks>
-		public static event EventHandler<ToplevelEventArgs> NotifyStopRunState;
-
-		/// <summary>
-		/// Building block API: Prepares the provided <see cref="Toplevel"/> for execution.
-		/// </summary>
-		/// <returns>The <see cref="RunState"/> handle that needs to be passed to the <see cref="End(RunState)"/> method upon completion.</returns>
-		/// <param name="Toplevel">The <see cref="Toplevel"/> to prepare execution for.</param>
-		/// <remarks>
-		/// This method prepares the provided <see cref="Toplevel"/> for running with the focus,
-		/// it adds this to the list of <see cref="Toplevel"/>s, sets up the <see cref="MainLoop"/> to process the
-		/// event, lays out the Subviews, focuses the first element, and draws the
-		/// <see cref="Toplevel"/> in the screen. This is usually followed by executing
-		/// the <see cref="RunLoop"/> method, and then the <see cref="End(RunState)"/> method upon termination which will
-		///  undo these changes.
-		/// </remarks>
-		public static RunState Begin (Toplevel Toplevel)
-		{
-			if (Toplevel == null) {
-				throw new ArgumentNullException (nameof (Toplevel));
-			} else if (Toplevel.IsOverlappedContainer && OverlappedTop != Toplevel && OverlappedTop != null) {
-				throw new InvalidOperationException ("Only one Overlapped Container is allowed.");
-			}
-
-			// Ensure the mouse is ungrabed.
-			_mouseGrabView = null;
-
-			var rs = new RunState (Toplevel);
-
-			// View implements ISupportInitializeNotification which is derived from ISupportInitialize
-			if (!Toplevel.IsInitialized) {
-				Toplevel.BeginInit ();
-				Toplevel.EndInit ();
-			}
-
-			lock (_toplevels) {
-				// If Top was already initialized with Init, and Begin has never been called
-				// Top was not added to the Toplevels Stack. It will thus never get disposed.
-				// Clean it up here:
-				if (Top != null && Toplevel != Top && !_toplevels.Contains (Top)) {
-					Top.Dispose ();
-					Top = null;
-				} else if (Top != null && Toplevel != Top && _toplevels.Contains (Top)) {
-					Top.OnLeave (Toplevel);
-				}
-				if (string.IsNullOrEmpty (Toplevel.Id)) {
-					var count = 1;
-					var id = (_toplevels.Count + count).ToString ();
-					while (_toplevels.Count > 0 && _toplevels.FirstOrDefault (x => x.Id == id) != null) {
-						count++;
-						id = (_toplevels.Count + count).ToString ();
-					}
-					Toplevel.Id = (_toplevels.Count + count).ToString ();
-
-					_toplevels.Push (Toplevel);
-				} else {
-					var dup = _toplevels.FirstOrDefault (x => x.Id == Toplevel.Id);
-					if (dup == null) {
-						_toplevels.Push (Toplevel);
-					}
-				}
-
-				if (_toplevels.FindDuplicates (new ToplevelEqualityComparer ()).Count > 0) {
-					throw new ArgumentException ("There are duplicates Toplevels Id's");
-				}
-			}
-			if (Top == null || Toplevel.IsOverlappedContainer) {
-				Top = Toplevel;
-			}
-
-			var refreshDriver = true;
-			if (OverlappedTop == null || Toplevel.IsOverlappedContainer || (Current?.Modal == false && Toplevel.Modal)
-				|| (Current?.Modal == false && !Toplevel.Modal) || (Current?.Modal == true && Toplevel.Modal)) {
-
-				if (Toplevel.Visible) {
-					Current = Toplevel;
-					SetCurrentOverlappedAsTop ();
-				} else {
-					refreshDriver = false;
-				}
-			} else if ((OverlappedTop != null && Toplevel != OverlappedTop && Current?.Modal == true && !_toplevels.Peek ().Modal)
-				|| (OverlappedTop != null && Toplevel != OverlappedTop && Current?.Running == false)) {
-				refreshDriver = false;
-				MoveCurrent (Toplevel);
-			} else {
-				refreshDriver = false;
-				MoveCurrent (Current);
-			}
-
-			Driver.PrepareToRun (MainLoop, ProcessKeyEvent, ProcessKeyDownEvent, ProcessKeyUpEvent, ProcessMouseEvent);
-			if (Toplevel.LayoutStyle == LayoutStyle.Computed) {
-				Toplevel.SetRelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
-			}
-			Toplevel.LayoutSubviews ();
-			Toplevel.PositionToplevels ();
-			Toplevel.FocusFirst ();
-			if (refreshDriver) {
-				OverlappedTop?.OnChildLoaded (Toplevel);
-				Toplevel.OnLoaded ();
-				Toplevel.SetNeedsDisplay ();
-				Toplevel.Draw ();
-				Toplevel.PositionCursor ();
-				Driver.Refresh ();
-			}
-
-			NotifyNewRunState?.Invoke (Toplevel, new RunStateEventArgs (rs));
-			return rs;
-		}
-
-		/// <summary>
-		/// Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> with the value of <see cref="Top"/>.
-		/// </summary>
-		/// <remarks>
-		/// See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.
-		/// </remarks>
-		public static void Run (Func<Exception, bool> errorHandler = null)
-		{
-			Run (Top, errorHandler);
-		}
-
-		/// <summary>
-		/// Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> 
-		/// with a new instance of the specified <see cref="Toplevel"/>-derived class.
-		/// <para>
-		/// Calling <see cref="Init(ConsoleDriver, IMainLoopDriver)"/> first is not needed as this function will initialize the application.
-		/// </para>
-		/// <para>
-		/// <see cref="Shutdown"/> must be called when the application is closing (typically after Run> has 
-		/// returned) to ensure resources are cleaned up and terminal settings restored.
-		/// </para>
-		/// </summary>
-		/// <remarks>
-		/// See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.
-		/// </remarks>
-		/// <param name="errorHandler"></param>
-		/// <param name="driver">The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the
-		/// platform will be used (<see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, or <see cref="NetDriver"/>).
-		/// Must be <see langword="null"/> if <see cref="Init(ConsoleDriver, IMainLoopDriver)"/> has already been called. 
-		/// </param>
-		/// <param name="mainLoopDriver">Specifies the <see cref="MainLoop"/> to use.</param>
-		public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null) where T : Toplevel, new()
-		{
-			if (_initialized) {
-				if (Driver != null) {
-					// Init() has been called and we have a driver, so just run the app.
-					var top = new T ();
-					var type = top.GetType ().BaseType;
-					while (type != typeof (Toplevel) && type != typeof (object)) {
-						type = type.BaseType;
-					}
-					if (type != typeof (Toplevel)) {
-						throw new ArgumentException ($"{top.GetType ().Name} must be derived from TopLevel");
-					}
-					Run (top, errorHandler);
-				} else {
-					// This codepath should be impossible because Init(null, null) will select the platform default driver
-					throw new InvalidOperationException ("Init() completed without a driver being set (this should be impossible); Run<T>() cannot be called.");
-				}
-			} else {
-				// Init() has NOT been called.
-				InternalInit (() => new T (), driver, mainLoopDriver, calledViaRunT: true);
-				Run (Top, errorHandler);
-			}
-		}
-
-		/// <summary>
-		///  Runs the main loop on the given <see cref="Toplevel"/> container.
-		/// </summary>
-		/// <remarks>
-		///  <para>
-		///   This method is used to start processing events
-		///   for the main application, but it is also used to
-		///   run other modal <see cref="View"/>s such as <see cref="Dialog"/> boxes.
-		///  </para>
-		///  <para>
-		///   To make a <see cref="Run(Toplevel, Func{Exception, bool})"/> stop execution, call <see cref="Application.RequestStop"/>.
-		///  </para>
-		///  <para>
-		///   Calling <see cref="Run(Toplevel, Func{Exception, bool})"/> is equivalent to calling <see cref="Begin(Toplevel)"/>, followed by <see cref="RunLoop(RunState, bool)"/>,
-		///   and then calling <see cref="End(RunState)"/>.
-		///  </para>
-		///  <para>
-		///   Alternatively, to have a program control the main loop and 
-		///   process events manually, call <see cref="Begin(Toplevel)"/> to set things up manually and then
-		///   repeatedly call <see cref="RunLoop(RunState, bool)"/> with the wait parameter set to false. By doing this
-		///   the <see cref="RunLoop(RunState, bool)"/> method will only process any pending events, timers, idle handlers and
-		///   then return control immediately.
-		///  </para>
-		///  <para>
-		///   RELEASE builds only: When <paramref name="errorHandler"/> is <see langword="null"/> any exeptions will be rethrown. 
-		///   Otherwise, if <paramref name="errorHandler"/> will be called. If <paramref name="errorHandler"/> 
-		///   returns <see langword="true"/> the <see cref="RunLoop(RunState, bool)"/> will resume; otherwise 
-		///   this method will exit.
-		///  </para>
-		/// </remarks>
-		/// <param name="view">The <see cref="Toplevel"/> to run modally.</param>
-		/// <param name="errorHandler">RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true, rethrows when null).</param>
-		public static void Run (Toplevel view, Func<Exception, bool> errorHandler = null)
-		{
-			var resume = true;
-			while (resume) {
-#if !DEBUG
-				try {
-#endif
-				resume = false;
-				var runToken = Begin (view);
-				// If ExitRunLoopAfterFirstIteration is true then the user must dispose of the runToken
-				// by using NotifyStopRunState event.
-				RunLoop (runToken);
-				if (!ExitRunLoopAfterFirstIteration) {
-					End (runToken);
-				}
-#if !DEBUG
-				}
-				catch (Exception error)
-				{
-					if (errorHandler == null)
-					{
-						throw;
-					}
-					resume = errorHandler(error);
-				}
-#endif
-			}
-		}
-
-		/// <summary>
-		/// Triggers a refresh of the entire display.
-		/// </summary>
-		public static void Refresh ()
-		{
-			// TODO: Figure out how to remove this call to ClearContents. Refresh should just repaint damaged areas, not clear
-			Driver.ClearContents();
-			View last = null;
-			foreach (var v in _toplevels.Reverse ()) {
-				if (v.Visible) {
-					v.SetNeedsDisplay ();
-					v.SetSubViewNeedsDisplay ();
-					v.Draw ();
-				}
-				last = v;
-			}
-			last?.PositionCursor ();
-			Driver.Refresh ();
-		}
-
-		/// <summary>
-		///  This event is raised on each iteration of the <see cref="MainLoop"/>. 
-		/// </summary>
-		/// <remarks>
-		///  See also <see cref="Timeout"/>
-		/// </remarks>
-		public static Action Iteration;
-
-		/// <summary>
-		/// The <see cref="MainLoop"/> driver for the application
-		/// </summary>
-		/// <value>The main loop.</value>
-		public static MainLoop MainLoop { get; private set; }
-
-		/// <summary>
-		/// Set to true to cause the RunLoop method to exit after the first iterations.
-		/// Set to false (the default) to cause the RunLoop to continue running until Application.RequestStop() is called.
-		/// </summary>
-		public static bool ExitRunLoopAfterFirstIteration { get; set; } = false;
-
-		//
-		// provides the sync context set while executing code in Terminal.Gui, to let
-		// users use async/await on their code
-		//
-		class MainLoopSyncContext : SynchronizationContext {
-			readonly MainLoop mainLoop;
-
-			public MainLoopSyncContext (MainLoop mainLoop)
-			{
-				this.mainLoop = mainLoop;
-			}
-
-			public override SynchronizationContext CreateCopy ()
-			{
-				return new MainLoopSyncContext (MainLoop);
-			}
-
-			public override void Post (SendOrPostCallback d, object state)
-			{
-				mainLoop.AddIdle (() => {
-					d (state);
-					return false;
-				});
-				//mainLoop.Driver.Wakeup ();
-			}
-
-			public override void Send (SendOrPostCallback d, object state)
-			{
-				if (Thread.CurrentThread.ManagedThreadId == _mainThreadId) {
-					d (state);
-				} else {
-					var wasExecuted = false;
-					mainLoop.Invoke (() => {
-						d (state);
-						wasExecuted = true;
-					});
-					while (!wasExecuted) {
-						Thread.Sleep (15);
-					}
-				}
-			}
-		}
-
-		/// <summary>
-		///  Building block API: Runs the <see cref="MainLoop"/> for the created <see cref="Toplevel"/>.
-		/// </summary>
-		/// <remarks>
-		///  Use the <paramref name="wait"/> parameter to control whether this is a blocking or non-blocking call.
-		/// </remarks>
-		/// <param name="state">The state returned by the <see cref="Begin(Toplevel)"/> method.</param>
-		/// <param name="wait">By default this is <see langword="true"/> which will execute the loop waiting for events, 
-		/// if set to <see langword="false"/>, a single iteration will execute.</param>
-		public static void RunLoop (RunState state, bool wait = true)
-		{
-			if (state == null)
-				throw new ArgumentNullException (nameof (state));
-			if (state.Toplevel == null)
-				throw new ObjectDisposedException ("state");
-
-			bool firstIteration = true;
-			for (state.Toplevel.Running = true; state.Toplevel.Running;) {
-				if (ExitRunLoopAfterFirstIteration && !firstIteration) {
-					return;
-				}
-				RunMainLoopIteration (ref state, wait, ref firstIteration);
-			}
-		}
-
-		/// <summary>
-		/// Run one iteration of the <see cref="MainLoop"/>.
-		/// </summary>
-		/// <param name="state">The state returned by <see cref="Begin(Toplevel)"/>.</param>
-		/// <param name="wait">If <see langword="true"/> will execute the <see cref="MainLoop"/> waiting for events. If <see langword="true"/>
-		/// will return after a single iteration.</param>
-		/// <param name="firstIteration">Set to <see langword="true"/> if this is the first run loop iteration. Upon return,
-		/// it will be set to <see langword="false"/> if at least one iteration happened.</param>
-		public static void RunMainLoopIteration (ref RunState state, bool wait, ref bool firstIteration)
-		{
-			if (MainLoop.EventsPending (wait)) {
-				// Notify Toplevel it's ready
-				if (firstIteration) {
-					state.Toplevel.OnReady ();
-				}
-
-				MainLoop.RunIteration ();
-				Iteration?.Invoke ();
-
-				EnsureModalOrVisibleAlwaysOnTop (state.Toplevel);
-				if (state.Toplevel != Current) {
-					OverlappedTop?.OnDeactivate (state.Toplevel);
-					state.Toplevel = Current;
-					OverlappedTop?.OnActivate (state.Toplevel);
-					Top.SetSubViewNeedsDisplay ();
-					Refresh ();
-				} else if (Current.SuperView == null && Current?.Modal == true) {
-					Refresh ();
-				}
-				if (Driver.EnsureCursorVisibility ()) {
-					state.Toplevel.SetNeedsDisplay ();
-				}
-			} else if (!wait) {
-				return;
-			}
-			firstIteration = false;
-
-			if (state.Toplevel != Top && 
-				(Top.NeedsDisplay|| Top.SubViewNeedsDisplay || Top.LayoutNeeded)) {
-				state.Toplevel.SetNeedsDisplay (state.Toplevel.Frame);
-				Top.Clear ();
-				Top.Draw ();
-				foreach (var top in _toplevels.Reverse ()) {
-					if (top != Top && top != state.Toplevel) {
-						top.SetNeedsDisplay ();
-						top.SetSubViewNeedsDisplay ();
-						top.Clear ();
-						top.Draw ();
-					}
-				}
-			}
-			if (_toplevels.Count == 1 && state.Toplevel == Top
-				&& (Driver.Cols != state.Toplevel.Frame.Width || Driver.Rows != state.Toplevel.Frame.Height)
-				&& (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded)) {
-
-				state.Toplevel.Clear ();
-			}
-
-			if (state.Toplevel.NeedsDisplay || 
-				state.Toplevel.SubViewNeedsDisplay || 
-				state.Toplevel.LayoutNeeded || 
-				OverlappedChildNeedsDisplay ()) {
-				state.Toplevel.Clear ();
-				state.Toplevel.Draw ();
-				state.Toplevel.PositionCursor ();
-				Driver.Refresh ();
-			} else {
-				Driver.UpdateCursor ();
-			}
-			if (state.Toplevel != Top && 
-				!state.Toplevel.Modal &&
-				(Top.NeedsDisplay|| Top.SubViewNeedsDisplay || Top.LayoutNeeded)) {
-				Top.Draw ();
-			}
-		}
-
-		/// <summary>
-		/// Wakes up the <see cref="MainLoop"/> that might be waiting on input; must be thread safe.
-		/// </summary>
-		public static void DoEvents ()
-		{
-			MainLoop.MainLoopDriver.Wakeup ();
-		}
-
-		/// <summary>
-		/// Stops running the most recent <see cref="Toplevel"/> or the <paramref name="top"/> if provided.
-		/// </summary>
-		/// <param name="top">The <see cref="Toplevel"/> to stop.</param>
-		/// <remarks>
-		///  <para>
-		///  This will cause <see cref="Application.Run(Func{Exception, bool})"/> to return.
-		///  </para>
-		///  <para>
-		///   Calling <see cref="Application.RequestStop"/> is equivalent to setting the <see cref="Toplevel.Running"/> property 
-		///   on the currently running <see cref="Toplevel"/> to false.
-		///  </para>
-		/// </remarks>
-		public static void RequestStop (Toplevel top = null)
-		{
-			if (OverlappedTop == null || top == null || (OverlappedTop == null && top != null)) {
-				top = Current;
-			}
-
-			if (OverlappedTop != null && top.IsOverlappedContainer && top?.Running == true
-				&& (Current?.Modal == false || (Current?.Modal == true && Current?.Running == false))) {
-
-				OverlappedTop.RequestStop ();
-			} else if (OverlappedTop != null && top != Current && Current?.Running == true && Current?.Modal == true
-				&& top.Modal && top.Running) {
-
-				var ev = new ToplevelClosingEventArgs (Current);
-				Current.OnClosing (ev);
-				if (ev.Cancel) {
-					return;
-				}
-				ev = new ToplevelClosingEventArgs (top);
-				top.OnClosing (ev);
-				if (ev.Cancel) {
-					return;
-				}
-				Current.Running = false;
-				OnNotifyStopRunState (Current);
-				top.Running = false;
-				OnNotifyStopRunState (top);
-			} else if ((OverlappedTop != null && top != OverlappedTop && top != Current && Current?.Modal == false
-				&& Current?.Running == true && !top.Running)
-				|| (OverlappedTop != null && top != OverlappedTop && top != Current && Current?.Modal == false
-				&& Current?.Running == false && !top.Running && _toplevels.ToArray () [1].Running)) {
-
-				MoveCurrent (top);
-			} else if (OverlappedTop != null && Current != top && Current?.Running == true && !top.Running
-				&& Current?.Modal == true && top.Modal) {
-				// The Current and the top are both modal so needed to set the Current.Running to false too.
-				Current.Running = false;
-				OnNotifyStopRunState (Current);
-			} else if (OverlappedTop != null && Current == top && OverlappedTop?.Running == true && Current?.Running == true && top.Running
-				&& Current?.Modal == true && top.Modal) {
-				// The OverlappedTop was requested to stop inside a modal Toplevel which is the Current and top,
-				// both are the same, so needed to set the Current.Running to false too.
-				Current.Running = false;
-				OnNotifyStopRunState (Current);
-			} else {
-				Toplevel currentTop;
-				if (top == Current || (Current?.Modal == true && !top.Modal)) {
-					currentTop = Current;
-				} else {
-					currentTop = top;
-				}
-				if (!currentTop.Running) {
-					return;
-				}
-				var ev = new ToplevelClosingEventArgs (currentTop);
-				currentTop.OnClosing (ev);
-				if (ev.Cancel) {
-					return;
-				}
-				currentTop.Running = false;
-				OnNotifyStopRunState (currentTop);
-			}
-		}
-
-		static void OnNotifyStopRunState (Toplevel top)
-		{
-			if (ExitRunLoopAfterFirstIteration) {
-				NotifyStopRunState?.Invoke (top, new ToplevelEventArgs (top));
-			}
-		}
-
-		/// <summary>
-		/// Building block API: completes the execution of a <see cref="Toplevel"/> that was started with <see cref="Begin(Toplevel)"/> .
-		/// </summary>
-		/// <param name="runState">The <see cref="RunState"/> returned by the <see cref="Begin(Toplevel)"/> method.</param>
-		public static void End (RunState runState)
-		{
-			if (runState == null)
-				throw new ArgumentNullException (nameof (runState));
-
-			if (OverlappedTop != null) {
-				OverlappedTop.OnChildUnloaded (runState.Toplevel);
-			} else {
-				runState.Toplevel.OnUnloaded ();
-			}
-
-			// End the RunState.Toplevel 
-			// First, take it off the Toplevel Stack
-			if (_toplevels.Count > 0) {
-				if (_toplevels.Peek () != runState.Toplevel) {
-					// If there the top of the stack is not the RunState.Toplevel then
-					// this call to End is not balanced with the call to Begin that started the RunState
-					throw new ArgumentException ("End must be balanced with calls to Begin");
-				}
-				_toplevels.Pop ();
-			}
-
-			// Notify that it is closing
-			runState.Toplevel?.OnClosed (runState.Toplevel);
-
-			// If there is a OverlappedTop that is not the RunState.Toplevel then runstate.TopLevel 
-			// is a child of MidTop and we should notify the OverlappedTop that it is closing
-			if (OverlappedTop != null && !(runState.Toplevel).Modal && runState.Toplevel != OverlappedTop) {
-				OverlappedTop.OnChildClosed (runState.Toplevel);
-			}
-
-			// Set Current and Top to the next TopLevel on the stack
-			if (_toplevels.Count == 0) {
-				Current = null;
-			} else {
-				Current = _toplevels.Peek ();
-				if (_toplevels.Count == 1 && Current == OverlappedTop) {
-					OverlappedTop.OnAllChildClosed ();
-				} else {
-					SetCurrentOverlappedAsTop ();
-					Current.OnEnter (Current);
-				}
-				Refresh ();
-			}
-
-			runState.Toplevel?.Dispose ();
-			runState.Toplevel = null;
-			runState.Dispose ();
-		}
-
-		#endregion Run (Begin, Run, End)
-
-		#region Toplevel handling
-		static readonly Stack<Toplevel> _toplevels = new Stack<Toplevel> ();
-
-		/// <summary>
-		/// The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Application.Top"/>)
-		/// </summary>
-		/// <value>The top.</value>
-		public static Toplevel Top { get; private set; }
-
-		/// <summary>
-		/// The current <see cref="Toplevel"/> object. This is updated when <see cref="Application.Run(Func{Exception, bool})"/> 
-		/// enters and leaves to point to the current <see cref="Toplevel"/> .
-		/// </summary>
-		/// <value>The current.</value>
-		public static Toplevel Current { get; private set; }
-
-		static void EnsureModalOrVisibleAlwaysOnTop (Toplevel Toplevel)
-		{
-			if (!Toplevel.Running || (Toplevel == Current && Toplevel.Visible) || OverlappedTop == null || _toplevels.Peek ().Modal) {
-				return;
-			}
-
-			foreach (var top in _toplevels.Reverse ()) {
-				if (top.Modal && top != Current) {
-					MoveCurrent (top);
-					return;
-				}
-			}
-			if (!Toplevel.Visible && Toplevel == Current) {
-				OverlappedMoveNext ();
-			}
-		}
-
-		static View FindDeepestTop (Toplevel start, int x, int y, out int resx, out int resy)
-		{
-			var startFrame = start.Frame;
-
-			if (!startFrame.Contains (x, y)) {
-				resx = 0;
-				resy = 0;
-				return null;
-			}
-
-			if (_toplevels != null) {
-				int count = _toplevels.Count;
-				if (count > 0) {
-					var rx = x - startFrame.X;
-					var ry = y - startFrame.Y;
-					foreach (var t in _toplevels) {
-						if (t != Current) {
-							if (t != start && t.Visible && t.Frame.Contains (rx, ry)) {
-								start = t;
-								break;
-							}
-						}
-					}
-				}
-			}
-			resx = x - startFrame.X;
-			resy = y - startFrame.Y;
-			return start;
-		}
-
-		static View FindTopFromView (View view)
-		{
-			View top = view?.SuperView != null && view?.SuperView != Top
-				? view.SuperView : view;
-
-			while (top?.SuperView != null && top?.SuperView != Top) {
-				top = top.SuperView;
-			}
-			return top;
-		}
-
-		// Only return true if the Current has changed.
-		static bool MoveCurrent (Toplevel top)
-		{
-			// The Current is modal and the top is not modal Toplevel then
-			// the Current must be moved above the first not modal Toplevel.
-			if (OverlappedTop != null && top != OverlappedTop && top != Current && Current?.Modal == true && !_toplevels.Peek ().Modal) {
-				lock (_toplevels) {
-					_toplevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
-				}
-				var index = 0;
-				var savedToplevels = _toplevels.ToArray ();
-				foreach (var t in savedToplevels) {
-					if (!t.Modal && t != Current && t != top && t != savedToplevels [index]) {
-						lock (_toplevels) {
-							_toplevels.MoveTo (top, index, new ToplevelEqualityComparer ());
-						}
-					}
-					index++;
-				}
-				return false;
-			}
-			// The Current and the top are both not running Toplevel then
-			// the top must be moved above the first not running Toplevel.
-			if (OverlappedTop != null && top != OverlappedTop && top != Current && Current?.Running == false && !top.Running) {
-				lock (_toplevels) {
-					_toplevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
-				}
-				var index = 0;
-				foreach (var t in _toplevels.ToArray ()) {
-					if (!t.Running && t != Current && index > 0) {
-						lock (_toplevels) {
-							_toplevels.MoveTo (top, index - 1, new ToplevelEqualityComparer ());
-						}
-					}
-					index++;
-				}
-				return false;
-			}
-			if ((OverlappedTop != null && top?.Modal == true && _toplevels.Peek () != top)
-				|| (OverlappedTop != null && Current != OverlappedTop && Current?.Modal == false && top == OverlappedTop)
-				|| (OverlappedTop != null && Current?.Modal == false && top != Current)
-				|| (OverlappedTop != null && Current?.Modal == true && top == OverlappedTop)) {
-				lock (_toplevels) {
-					_toplevels.MoveTo (top, 0, new ToplevelEqualityComparer ());
-					Current = top;
-				}
-			}
-			return true;
-		}
-
-		/// <summary>
-		/// Invoked when the terminal was resized. The new size of the terminal is provided.
-		/// </summary>
-		public static Action<ResizedEventArgs> TerminalResized;
-
-		static void OnTerminalResized ()
-		{
-			var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
-			TerminalResized?.Invoke (new ResizedEventArgs () { Cols = full.Width, Rows = full.Height });
-			foreach (var t in _toplevels) {
-				t.SetRelativeLayout (full);
-				t.LayoutSubviews ();
-				t.PositionToplevels ();
-				t.OnTerminalResized (new SizeChangedEventArgs (full.Size));
-			}
-			Refresh ();
-		}
-
-		#endregion Toplevel handling
-
-		#region Mouse handling
-		/// <summary>
-		/// Disable or enable the mouse. The mouse is enabled by default.
-		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-		public static bool IsMouseDisabled { get; set; }
-
-		/// <summary>
-		/// The current <see cref="View"/> object that wants continuous mouse button pressed events.
-		/// </summary>
-		public static View WantContinuousButtonPressedView { get; private set; }
-
-		static View _mouseGrabView;
-
-		/// <summary>
-		/// The view that grabbed the mouse, to where mouse events will be routed to.
-		/// </summary>
-		public static View MouseGrabView => _mouseGrabView;
-
-		/// <summary>
-		/// Invoked when a view wants to grab the mouse; can be canceled.
-		/// </summary>
-		public static event EventHandler<GrabMouseEventArgs> GrabbingMouse;
-
-		/// <summary>
-		/// Invoked when a view wants ungrab the mouse; can be canceled.
-		/// </summary>
-		public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
-
-		/// <summary>
-		/// Invoked after a view has grabbed the mouse.
-		/// </summary>
-		public static event EventHandler<ViewEventArgs> GrabbedMouse;
-
-		/// <summary>
-		/// Invoked after a view has ungrabbed the mouse.
-		/// </summary>
-		public static event EventHandler<ViewEventArgs> UnGrabbedMouse;
-
-		/// <summary>
-		/// Grabs the mouse, forcing all mouse events to be routed to the specified view until <see cref="UngrabMouse"/> is called.
-		/// </summary>
-		/// <param name="view">View that will receive all mouse events until <see cref="UngrabMouse"/> is invoked.</param>
-		public static void GrabMouse (View view)
-		{
-			if (view == null)
-				return;
-			if (!OnGrabbingMouse (view)) {
-				OnGrabbedMouse (view);
-				_mouseGrabView = view;
-				//Driver.UncookMouse ();
-			}
-		}
-
-		/// <summary>
-		/// Releases the mouse grab, so mouse events will be routed to the view on which the mouse is.
-		/// </summary>
-		public static void UngrabMouse ()
-		{
-			if (_mouseGrabView == null)
-				return;
-			if (!OnUnGrabbingMouse (_mouseGrabView)) {
-				OnUnGrabbedMouse (_mouseGrabView);
-				_mouseGrabView = null;
-				//Driver.CookMouse ();
-			}
-		}
-
-		static bool OnGrabbingMouse (View view)
-		{
-			if (view == null)
-				return false;
-			var evArgs = new GrabMouseEventArgs (view);
-			GrabbingMouse?.Invoke (view, evArgs);
-			return evArgs.Cancel;
-		}
-
-		static bool OnUnGrabbingMouse (View view)
-		{
-			if (view == null)
-				return false;
-			var evArgs = new GrabMouseEventArgs (view);
-			UnGrabbingMouse?.Invoke (view, evArgs);
-			return evArgs.Cancel;
-		}
-
-		static void OnGrabbedMouse (View view)
-		{
-			if (view == null)
-				return;
-			GrabbedMouse?.Invoke (view, new ViewEventArgs (view));
-		}
-
-		static void OnUnGrabbedMouse (View view)
-		{
-			if (view == null)
-				return;
-			UnGrabbedMouse?.Invoke (view, new ViewEventArgs (view));
-		}
-
-		/// <summary>
-		/// Merely a debugging aid to see the raw mouse events
-		/// </summary>
-		public static Action<MouseEvent> RootMouseEvent;
-
-		static View _lastMouseOwnerView;
-
-		static void ProcessMouseEvent (MouseEvent me)
-		{
-			static bool OutsideBounds (Point p, Rect r) => p.X < 0 || p.X > r.Right || p.Y < 0 || p.Y > r.Bottom;
-
-			if (IsMouseDisabled) {
-				return;
-			}
-
-			var view = View.FindDeepestView (Current, me.X, me.Y, out int rx, out int ry);
-
-			if (view != null && view.WantContinuousButtonPressed) {
-				WantContinuousButtonPressedView = view;
-			} else {
-				WantContinuousButtonPressedView = null;
-			}
-			if (view != null) {
-				me.View = view;
-			}
-			RootMouseEvent?.Invoke (me);
-
-			if (me.Handled) {
-				return;
-			}
-
-			if (_mouseGrabView != null) {
-				var newxy = _mouseGrabView.ScreenToView (me.X, me.Y);
-				var nme = new MouseEvent () {
-					X = newxy.X,
-					Y = newxy.Y,
-					Flags = me.Flags,
-					OfX = me.X - newxy.X,
-					OfY = me.Y - newxy.Y,
-					View = view
-				};
-				if (OutsideBounds (new Point (nme.X, nme.Y), _mouseGrabView.Bounds)) {
-					_lastMouseOwnerView?.OnMouseLeave (me);
-				}
-				//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
-				if (_mouseGrabView?.OnMouseEvent (nme) == true) {
-					return;
-				}
-			}
-
-			if ((view == null || view == OverlappedTop) && !Current.Modal && OverlappedTop != null
-				&& me.Flags != MouseFlags.ReportMousePosition && me.Flags != 0) {
-
-				var top = FindDeepestTop (Top, me.X, me.Y, out _, out _);
-				view = View.FindDeepestView (top, me.X, me.Y, out rx, out ry);
-
-				if (view != null && view != OverlappedTop && top != Current) {
-					MoveCurrent ((Toplevel)top);
-				}
-			}
-
-			if (view != null) {
-				var nme = new MouseEvent () {
-					X = rx,
-					Y = ry,
-					Flags = me.Flags,
-					OfX = 0,
-					OfY = 0,
-					View = view
-				};
-
-				if (_lastMouseOwnerView == null) {
-					_lastMouseOwnerView = view;
-					view.OnMouseEnter (nme);
-				} else if (_lastMouseOwnerView != view) {
-					_lastMouseOwnerView.OnMouseLeave (nme);
-					view.OnMouseEnter (nme);
-					_lastMouseOwnerView = view;
-				}
-
-				if (!view.WantMousePositionReports && me.Flags == MouseFlags.ReportMousePosition)
-					return;
-
-				if (view.WantContinuousButtonPressed)
-					WantContinuousButtonPressedView = view;
-				else
-					WantContinuousButtonPressedView = null;
-
-				// Should we bubbled up the event, if it is not handled?
-				view.OnMouseEvent (nme);
-
-				BringOverlappedTopToFront ();
-			}
-		}
-		#endregion Mouse handling
-
-		#region Keyboard handling
-
-
-		static Key _alternateForwardKey = Key.PageDown | Key.CtrlMask;
-
-		/// <summary>
-		/// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.
-		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
-		public static Key AlternateForwardKey {
-			get => _alternateForwardKey;
-			set {
-				if (_alternateForwardKey != value) {
-					var oldKey = _alternateForwardKey;
-					_alternateForwardKey = value;
-					OnAlternateForwardKeyChanged (new KeyChangedEventArgs (oldKey, value));
-				}
-			}
-		}
-
-		static void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
-		{
-			foreach (var top in _toplevels.ToArray ()) {
-				top.OnAlternateForwardKeyChanged (e);
-			}
-		}
-
-		static Key _alternateBackwardKey = Key.PageUp | Key.CtrlMask;
-
-		/// <summary>
-		/// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.
-		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
-		public static Key AlternateBackwardKey {
-			get => _alternateBackwardKey;
-			set {
-				if (_alternateBackwardKey != value) {
-					var oldKey = _alternateBackwardKey;
-					_alternateBackwardKey = value;
-					OnAlternateBackwardKeyChanged (new KeyChangedEventArgs (oldKey, value));
-				}
-			}
-		}
-
-		static void OnAlternateBackwardKeyChanged (KeyChangedEventArgs oldKey)
-		{
-			foreach (var top in _toplevels.ToArray ()) {
-				top.OnAlternateBackwardKeyChanged (oldKey);
-			}
-		}
-
-		static Key _quitKey = Key.Q | Key.CtrlMask;
-
-		/// <summary>
-		/// Gets or sets the key to quit the application.
-		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
-		public static Key QuitKey {
-			get => _quitKey;
-			set {
-				if (_quitKey != value) {
-					var oldKey = _quitKey;
-					_quitKey = value;
-					OnQuitKeyChanged (new KeyChangedEventArgs (oldKey, value));
-				}
-			}
-		}
-		static void OnQuitKeyChanged (KeyChangedEventArgs e)
-		{
-			// Duplicate the list so if it changes during enumeration we're safe
-			foreach (var top in _toplevels.ToArray ()) {
-				top.OnQuitKeyChanged (e);
-			}
-		}
-
-		static void ProcessKeyEvent (KeyEvent ke)
-		{
-			if (RootKeyEvent?.Invoke (ke) ?? false) {
-				return;
-			}
-
-			var chain = _toplevels.ToList ();
-			foreach (var topLevel in chain) {
-				if (topLevel.ProcessHotKey (ke))
-					return;
-				if (topLevel.Modal)
-					break;
-			}
-
-			foreach (var topLevel in chain) {
-				if (topLevel.ProcessKey (ke))
-					return;
-				if (topLevel.Modal)
-					break;
-			}
-
-			foreach (var topLevel in chain) {
-				// Process the key normally
-				if (topLevel.ProcessColdKey (ke))
-					return;
-				if (topLevel.Modal)
-					break;
-			}
-		}
-
-		static void ProcessKeyDownEvent (KeyEvent ke)
-		{
-			var chain = _toplevels.ToList ();
-			foreach (var topLevel in chain) {
-				if (topLevel.OnKeyDown (ke))
-					return;
-				if (topLevel.Modal)
-					break;
-			}
-		}
-
-		static void ProcessKeyUpEvent (KeyEvent ke)
-		{
-			var chain = _toplevels.ToList ();
-			foreach (var topLevel in chain) {
-				if (topLevel.OnKeyUp (ke))
-					return;
-				if (topLevel.Modal)
-					break;
-			}
-		}
-
-		/// <summary>
-		/// <para>
-		/// Called for new KeyPress events before any processing is performed or
-		/// views evaluate. Use for global key handling and/or debugging.
-		/// </para>
-		/// <para>Return true to suppress the KeyPress event</para>
-		/// </summary>
-		public static Func<KeyEvent, bool> RootKeyEvent;
-
-		#endregion Keyboard handling
-	}
-}

+ 1500 - 0
Terminal.Gui/Application/Application.cs

@@ -0,0 +1,1500 @@
+using System.Diagnostics;
+using System.Globalization;
+using System.Reflection;
+
+namespace Terminal.Gui;
+
+/// <summary>A static, singleton class representing the application. This class is the entry point for the application.</summary>
+/// <example>
+///     <code>
+///     Application.Init();
+///     var win = new Window ($"Example App ({Application.QuitKey} to quit)");
+///     Application.Run(win);
+///     win.Dispose();
+///     Application.Shutdown();
+///     </code>
+/// </example>
+/// <remarks>TODO: Flush this out.</remarks>
+public static partial class Application
+{
+    // For Unit testing - ignores UseSystemConsole
+    internal static bool _forceFakeConsole;
+
+    /// <summary>Gets the <see cref="ConsoleDriver"/> that has been selected. See also <see cref="ForceDriver"/>.</summary>
+    public static ConsoleDriver Driver { get; internal set; }
+
+    /// <summary>
+    ///     Gets or sets whether <see cref="Application.Driver"/> will be forced to output only the 16 colors defined in
+    ///     <see cref="ColorName"/>. The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be output
+    ///     as long as the selected <see cref="ConsoleDriver"/> supports TrueColor.
+    /// </summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static bool Force16Colors { get; set; }
+
+    /// <summary>
+    ///     Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not
+    ///     specified, the driver is selected based on the platform.
+    /// </summary>
+    /// <remarks>
+    ///     Note, <see cref="Application.Init(ConsoleDriver, string)"/> will override this configuration setting if called
+    ///     with either `driver` or `driverName` specified.
+    /// </remarks>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static string ForceDriver { get; set; } = string.Empty;
+
+    /// <summary>Gets all cultures supported by the application without the invariant language.</summary>
+    public static List<CultureInfo> SupportedCultures { get; private set; }
+
+    internal static List<CultureInfo> GetSupportedCultures ()
+    {
+        CultureInfo [] culture = CultureInfo.GetCultures (CultureTypes.AllCultures);
+
+        // Get the assembly
+        var assembly = Assembly.GetExecutingAssembly ();
+
+        //Find the location of the assembly
+        string assemblyLocation = AppDomain.CurrentDomain.BaseDirectory;
+
+        // Find the resource file name of the assembly
+        var resourceFilename = $"{Path.GetFileNameWithoutExtension (assembly.Location)}.resources.dll";
+
+        // Return all culture for which satellite folder found with culture code.
+        return culture.Where (
+                              cultureInfo =>
+                                  Directory.Exists (Path.Combine (assemblyLocation, cultureInfo.Name))
+                                  && File.Exists (Path.Combine (assemblyLocation, cultureInfo.Name, resourceFilename))
+                             )
+                      .ToList ();
+    }
+
+    // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
+    // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
+    private static Toplevel _cachedRunStateToplevel;
+
+    // IMPORTANT: Ensure all property/fields are reset here. See Init_ResetState_Resets_Properties unit test.
+    // Encapsulate all setting of initial state for Application; Having
+    // this in a function like this ensures we don't make mistakes in
+    // guaranteeing that the state of this singleton is deterministic when Init
+    // starts running and after Shutdown returns.
+    internal static void ResetState (bool ignoreDisposed = false)
+    {
+        // Shutdown is the bookend for Init. As such it needs to clean up all resources
+        // Init created. Apps that do any threading will need to code defensively for this.
+        // e.g. see Issue #537
+        foreach (Toplevel t in _topLevels)
+        {
+            t.Running = false;
+        }
+
+        _topLevels.Clear ();
+        Current = null;
+#if DEBUG_IDISPOSABLE
+
+        // Don't dispose the Top. It's up to caller dispose it
+        if (!ignoreDisposed && Top is { })
+        {
+            Debug.Assert (Top.WasDisposed);
+
+            // If End wasn't called _cachedRunStateToplevel may be null
+            if (_cachedRunStateToplevel is { })
+            {
+                Debug.Assert (_cachedRunStateToplevel.WasDisposed);
+                Debug.Assert (_cachedRunStateToplevel == Top);
+            }
+        }
+#endif
+        Top = null;
+        _cachedRunStateToplevel = null;
+
+        // MainLoop stuff
+        MainLoop?.Dispose ();
+        MainLoop = null;
+        _mainThreadId = -1;
+        Iteration = null;
+        EndAfterFirstIteration = false;
+
+        // Driver stuff
+        if (Driver is { })
+        {
+            Driver.SizeChanged -= Driver_SizeChanged;
+            Driver.KeyDown -= Driver_KeyDown;
+            Driver.KeyUp -= Driver_KeyUp;
+            Driver.MouseEvent -= Driver_MouseEvent;
+            Driver?.End ();
+            Driver = null;
+        }
+
+        // Don't reset ForceDriver; it needs to be set before Init is called.
+        //ForceDriver = string.Empty;
+        //Force16Colors = false;
+        _forceFakeConsole = false;
+
+        // Run State stuff
+        NotifyNewRunState = null;
+        NotifyStopRunState = null;
+        MouseGrabView = null;
+        _initialized = false;
+
+        // Mouse
+        _mouseEnteredView = null;
+        WantContinuousButtonPressedView = null;
+        MouseEvent = null;
+        GrabbedMouse = null;
+        UnGrabbingMouse = null;
+        GrabbedMouse = null;
+        UnGrabbedMouse = null;
+
+        // Keyboard
+        AlternateBackwardKey = Key.Empty;
+        AlternateForwardKey = Key.Empty;
+        QuitKey = Key.Empty;
+        KeyDown = null;
+        KeyUp = null;
+        SizeChanging = null;
+        ClearKeyBindings ();
+
+        Colors.Reset ();
+
+        // Reset synchronization context to allow the user to run async/await,
+        // as the main loop has been ended, the synchronization context from 
+        // gui.cs does no longer process any callbacks. See #1084 for more details:
+        // (https://github.com/gui-cs/Terminal.Gui/issues/1084).
+        SynchronizationContext.SetSynchronizationContext (null);
+    }
+
+    #region Initialization (Init/Shutdown)
+
+    /// <summary>Initializes a new instance of <see cref="Terminal.Gui"/> Application.</summary>
+    /// <para>Call this method once per instance (or after <see cref="Shutdown"/> has been called).</para>
+    /// <para>
+    ///     This function loads the right <see cref="ConsoleDriver"/> for the platform, Creates a <see cref="Toplevel"/>. and
+    ///     assigns it to <see cref="Top"/>
+    /// </para>
+    /// <para>
+    ///     <see cref="Shutdown"/> must be called when the application is closing (typically after
+    ///     <see cref="Run{T}"/> has returned) to ensure resources are cleaned up and
+    ///     terminal settings
+    ///     restored.
+    /// </para>
+    /// <para>
+    ///     The <see cref="Run{T}"/> function combines
+    ///     <see cref="Init(ConsoleDriver, string)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
+    ///     into a single
+    ///     call. An application cam use <see cref="Run{T}"/> without explicitly calling
+    ///     <see cref="Init(ConsoleDriver, string)"/>.
+    /// </para>
+    /// <param name="driver">
+    ///     The <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>
+    /// <param name="driverName">
+    ///     The short name (e.g. "net", "windows", "ansi", "fake", or "curses") of the
+    ///     <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>
+    public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (driver, driverName); }
+
+    internal static bool _initialized;
+    internal static int _mainThreadId = -1;
+
+    // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop.
+    //
+    // Called from:
+    // 
+    // Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset.
+    // Run<T>() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run<T>() to be called without calling Init first.
+    // 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.
+    internal static void InternalInit (
+        ConsoleDriver driver = null,
+        string driverName = null,
+        bool calledViaRunT = false
+    )
+    {
+        if (_initialized && driver is null)
+        {
+            return;
+        }
+
+        if (_initialized)
+        {
+            throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown.");
+        }
+
+        if (!calledViaRunT)
+        {
+            // Reset all class variables (Application is a singleton).
+            ResetState ();
+        }
+
+        // For UnitTests
+        if (driver is { })
+        {
+            Driver = driver;
+        }
+
+        // Start the process of configuration management.
+        // Note that we end up calling LoadConfigurationFromAllSources
+        // multiple times. We need to do this because some settings are only
+        // valid after a Driver is loaded. In this cases we need just 
+        // `Settings` so we can determine which driver to use.
+        // Don't reset, so we can inherit the theme from the previous run.
+        Load ();
+        Apply ();
+
+        // Ignore Configuration for ForceDriver if driverName is specified
+        if (!string.IsNullOrEmpty (driverName))
+        {
+            ForceDriver = driverName;
+        }
+
+        if (Driver is null)
+        {
+            PlatformID p = Environment.OSVersion.Platform;
+
+            if (string.IsNullOrEmpty (ForceDriver))
+            {
+                if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
+                {
+                    Driver = new WindowsDriver ();
+                }
+                else
+                {
+                    Driver = new CursesDriver ();
+                }
+            }
+            else
+            {
+                List<Type> drivers = GetDriverTypes ();
+                Type driverType = drivers.FirstOrDefault (t => t.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase));
+
+                if (driverType is { })
+                {
+                    Driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+                }
+                else
+                {
+                    throw new ArgumentException (
+                                                 $"Invalid driver name: {ForceDriver}. Valid names are {string.Join (", ", drivers.Select (t => t.Name))}"
+                                                );
+                }
+            }
+        }
+
+        try
+        {
+            MainLoop = Driver.Init ();
+        }
+        catch (InvalidOperationException ex)
+        {
+            // This is a case where the driver is unable to initialize the console.
+            // This can happen if the console is already in use by another process or
+            // if running in unit tests.
+            // In this case, we want to throw a more specific exception.
+            throw new InvalidOperationException (
+                                                 "Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.",
+                                                 ex
+                                                );
+        }
+
+        Driver.SizeChanged += (s, args) => OnSizeChanging (args);
+        Driver.KeyDown += (s, args) => OnKeyDown (args);
+        Driver.KeyUp += (s, args) => OnKeyUp (args);
+        Driver.MouseEvent += (s, args) => OnMouseEvent (args);
+
+        SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
+
+        SupportedCultures = GetSupportedCultures ();
+        _mainThreadId = Thread.CurrentThread.ManagedThreadId;
+        _initialized = true;
+        InitializedChanged?.Invoke (null, new (in _initialized));
+    }
+
+    private static void Driver_SizeChanged (object sender, SizeChangedEventArgs e) { OnSizeChanging (e); }
+    private static void Driver_KeyDown (object sender, Key e) { OnKeyDown (e); }
+    private static void Driver_KeyUp (object sender, Key e) { OnKeyUp (e); }
+    private static void Driver_MouseEvent (object sender, MouseEvent e) { OnMouseEvent (e); }
+
+    /// <summary>Gets of list of <see cref="ConsoleDriver"/> types that are available.</summary>
+    /// <returns></returns>
+    public static List<Type> GetDriverTypes ()
+    {
+        // use reflection to get the list of drivers
+        List<Type> driverTypes = new ();
+
+        foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ())
+        {
+            foreach (Type type in asm.GetTypes ())
+            {
+                if (type.IsSubclassOf (typeof (ConsoleDriver)) && !type.IsAbstract)
+                {
+                    driverTypes.Add (type);
+                }
+            }
+        }
+
+        return driverTypes;
+    }
+
+    /// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
+    /// <remarks>
+    ///     Shutdown must be called for every call to <see cref="Init"/> or
+    ///     <see cref="Application.Run(Toplevel, Func{Exception, bool})"/> to ensure all resources are cleaned
+    ///     up (Disposed)
+    ///     and terminal settings are restored.
+    /// </remarks>
+    public static void Shutdown ()
+    {
+        // TODO: Throw an exception if Init hasn't been called.
+        ResetState ();
+        PrintJsonErrors ();
+        InitializedChanged?.Invoke (null, new (in _initialized));
+    }
+
+#nullable enable
+    /// <summary>
+    ///     This event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
+    /// </summary>
+    /// <remarks>
+    ///     Intended to support unit tests that need to know when the application has been initialized.
+    /// </remarks>
+    public static event EventHandler<EventArgs<bool>>? InitializedChanged;
+#nullable restore
+
+    #endregion Initialization (Init/Shutdown)
+
+    #region Run (Begin, Run, End, Stop)
+
+    /// <summary>
+    ///     Notify that a new <see cref="RunState"/> was created (<see cref="Begin(Toplevel)"/> was called). The token is
+    ///     created in <see cref="Begin(Toplevel)"/> and this event will be fired before that function exits.
+    /// </summary>
+    /// <remarks>
+    ///     If <see cref="EndAfterFirstIteration"/> is <see langword="true"/> callers to <see cref="Begin(Toplevel)"/>
+    ///     must also subscribe to <see cref="NotifyStopRunState"/> and manually dispose of the <see cref="RunState"/> token
+    ///     when the application is done.
+    /// </remarks>
+    public static event EventHandler<RunStateEventArgs> NotifyNewRunState;
+
+    /// <summary>Notify that a existent <see cref="RunState"/> is stopping (<see cref="End(RunState)"/> was called).</summary>
+    /// <remarks>
+    ///     If <see cref="EndAfterFirstIteration"/> is <see langword="true"/> callers to <see cref="Begin(Toplevel)"/>
+    ///     must also subscribe to <see cref="NotifyStopRunState"/> and manually dispose of the <see cref="RunState"/> token
+    ///     when the application is done.
+    /// </remarks>
+    public static event EventHandler<ToplevelEventArgs> NotifyStopRunState;
+
+    /// <summary>Building block API: Prepares the provided <see cref="Toplevel"/> for execution.</summary>
+    /// <returns>
+    ///     The <see cref="RunState"/> handle that needs to be passed to the <see cref="End(RunState)"/> method upon
+    ///     completion.
+    /// </returns>
+    /// <param name="toplevel">The <see cref="Toplevel"/> to prepare execution for.</param>
+    /// <remarks>
+    ///     This method prepares the provided <see cref="Toplevel"/> for running with the focus, it adds this to the list
+    ///     of <see cref="Toplevel"/>s, lays out the Subviews, focuses the first element, and draws the <see cref="Toplevel"/>
+    ///     in the screen. This is usually followed by executing the <see cref="RunLoop"/> method, and then the
+    ///     <see cref="End(RunState)"/> method upon termination which will undo these changes.
+    /// </remarks>
+    public static RunState Begin (Toplevel toplevel)
+    {
+        ArgumentNullException.ThrowIfNull (toplevel);
+
+#if DEBUG_IDISPOSABLE
+        Debug.Assert (!toplevel.WasDisposed);
+
+        if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel)
+        {
+            Debug.Assert (_cachedRunStateToplevel.WasDisposed);
+        }
+#endif
+
+        if (toplevel.IsOverlappedContainer && OverlappedTop != toplevel && OverlappedTop is { })
+        {
+            throw new InvalidOperationException ("Only one Overlapped Container is allowed.");
+        }
+
+        // Ensure the mouse is ungrabbed.
+        MouseGrabView = null;
+
+        var rs = new RunState (toplevel);
+
+        // View implements ISupportInitializeNotification which is derived from ISupportInitialize
+        if (!toplevel.IsInitialized)
+        {
+            toplevel.BeginInit ();
+            toplevel.EndInit ();
+        }
+
+#if DEBUG_IDISPOSABLE
+        if (Top is { } && toplevel != Top && !_topLevels.Contains (Top))
+        {
+            // This assertion confirm if the Top was already disposed
+            Debug.Assert (Top.WasDisposed);
+            Debug.Assert (Top == _cachedRunStateToplevel);
+        }
+#endif
+
+        lock (_topLevels)
+        {
+            if (Top is { } && toplevel != Top && !_topLevels.Contains (Top))
+            {
+                // If Top was already disposed and isn't on the Toplevels Stack,
+                // clean it up here if is the same as _cachedRunStateToplevel
+                if (Top == _cachedRunStateToplevel)
+                {
+                    Top = null;
+                }
+                else
+                {
+                    // Probably this will never hit
+                    throw new ObjectDisposedException (Top.GetType ().FullName);
+                }
+            }
+            else if (OverlappedTop is { } && toplevel != Top && _topLevels.Contains (Top))
+            {
+                Top.OnLeave (toplevel);
+            }
+
+            // BUGBUG: We should not depend on `Id` internally. 
+            // BUGBUG: It is super unclear what this code does anyway.
+            if (string.IsNullOrEmpty (toplevel.Id))
+            {
+                var count = 1;
+                var id = (_topLevels.Count + count).ToString ();
+
+                while (_topLevels.Count > 0 && _topLevels.FirstOrDefault (x => x.Id == id) is { })
+                {
+                    count++;
+                    id = (_topLevels.Count + count).ToString ();
+                }
+
+                toplevel.Id = (_topLevels.Count + count).ToString ();
+
+                _topLevels.Push (toplevel);
+            }
+            else
+            {
+                Toplevel dup = _topLevels.FirstOrDefault (x => x.Id == toplevel.Id);
+
+                if (dup is null)
+                {
+                    _topLevels.Push (toplevel);
+                }
+            }
+
+            if (_topLevels.FindDuplicates (new ToplevelEqualityComparer ()).Count > 0)
+            {
+                throw new ArgumentException ("There are duplicates Toplevel IDs");
+            }
+        }
+
+        if (Top is null || toplevel.IsOverlappedContainer)
+        {
+            Top = toplevel;
+        }
+
+        var refreshDriver = true;
+
+        if (OverlappedTop is null
+            || toplevel.IsOverlappedContainer
+            || (Current?.Modal == false && toplevel.Modal)
+            || (Current?.Modal == false && !toplevel.Modal)
+            || (Current?.Modal == true && toplevel.Modal))
+        {
+            if (toplevel.Visible)
+            {
+                Current?.OnDeactivate (toplevel);
+                Toplevel previousCurrent = Current;
+                Current = toplevel;
+                Current.OnActivate (previousCurrent);
+
+                SetCurrentOverlappedAsTop ();
+            }
+            else
+            {
+                refreshDriver = false;
+            }
+        }
+        else if ((OverlappedTop != null
+                  && toplevel != OverlappedTop
+                  && Current?.Modal == true
+                  && !_topLevels.Peek ().Modal)
+                 || (OverlappedTop is { } && toplevel != OverlappedTop && Current?.Running == false))
+        {
+            refreshDriver = false;
+            MoveCurrent (toplevel);
+        }
+        else
+        {
+            refreshDriver = false;
+            MoveCurrent (Current);
+        }
+
+        toplevel.SetRelativeLayout (Driver.Screen.Size);
+
+        toplevel.LayoutSubviews ();
+        toplevel.PositionToplevels ();
+        toplevel.FocusFirst ();
+        BringOverlappedTopToFront ();
+
+        if (refreshDriver)
+        {
+            OverlappedTop?.OnChildLoaded (toplevel);
+            toplevel.OnLoaded ();
+            toplevel.SetNeedsDisplay ();
+            toplevel.Draw ();
+            Driver.UpdateScreen ();
+
+            if (PositionCursor (toplevel))
+            {
+                Driver.UpdateCursor ();
+            }
+        }
+
+        NotifyNewRunState?.Invoke (toplevel, new (rs));
+
+        return rs;
+    }
+
+    /// <summary>
+    ///     Calls <see cref="View.PositionCursor"/> on the most focused view in the view starting with <paramref name="view"/>.
+    /// </summary>
+    /// <remarks>
+    ///     Does nothing if <paramref name="view"/> is <see langword="null"/> or if the most focused view is not visible or
+    ///     enabled.
+    ///     <para>
+    ///         If the most focused view is not visible within it's superview, the cursor will be hidden.
+    ///     </para>
+    /// </remarks>
+    /// <returns><see langword="true"/> if a view positioned the cursor and the position is visible.</returns>
+    internal static bool PositionCursor (View view)
+    {
+        // Find the most focused view and position the cursor there.
+        View mostFocused = view?.MostFocused;
+
+        if (mostFocused is null)
+        {
+            if (view is { HasFocus: true })
+            {
+                mostFocused = view;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        // If the view is not visible or enabled, don't position the cursor
+        if (!mostFocused.Visible || !mostFocused.Enabled)
+        {
+            Driver.GetCursorVisibility (out CursorVisibility current);
+
+            if (current != CursorVisibility.Invisible)
+            {
+                Driver.SetCursorVisibility (CursorVisibility.Invisible);
+            }
+
+            return false;
+        }
+
+        // If the view is not visible within it's superview, don't position the cursor
+        Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty });
+        Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen;
+
+        if (!superViewViewport.IntersectsWith (mostFocusedViewport))
+        {
+            return false;
+        }
+
+        Point? cursor = mostFocused.PositionCursor ();
+
+        Driver.GetCursorVisibility (out CursorVisibility currentCursorVisibility);
+
+        if (cursor is { })
+        {
+            // Convert cursor to screen coords
+            cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location;
+
+            // If the cursor is not in a visible location in the SuperView, hide it
+            if (!superViewViewport.Contains (cursor.Value))
+            {
+                if (currentCursorVisibility != CursorVisibility.Invisible)
+                {
+                    Driver.SetCursorVisibility (CursorVisibility.Invisible);
+                }
+
+                return false;
+            }
+
+            // Show it
+            if (currentCursorVisibility == CursorVisibility.Invisible)
+            {
+                Driver.SetCursorVisibility (mostFocused.CursorVisibility);
+            }
+
+            return true;
+        }
+
+        if (currentCursorVisibility != CursorVisibility.Invisible)
+        {
+            Driver.SetCursorVisibility (CursorVisibility.Invisible);
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    ///     Runs the application by creating a <see cref="Toplevel"/> object and calling
+    ///     <see cref="Run(Toplevel, Func{Exception, bool})"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <para>Calling <see cref="Init"/> first is not needed as this function will initialize the application.</para>
+    ///     <para>
+    ///         <see cref="Shutdown"/> must be called when the application is closing (typically after Run> has returned) to
+    ///         ensure resources are cleaned up and terminal settings restored.
+    ///     </para>
+    ///     <para>
+    ///         The caller is responsible for disposing the object returned by this method.
+    ///     </para>
+    /// </remarks>
+    /// <returns>The created <see cref="Toplevel"/> object. The caller is responsible for disposing this object.</returns>
+    public static Toplevel Run (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null) { return Run<Toplevel> (errorHandler, driver); }
+
+    /// <summary>
+    ///     Runs the application by creating a <see cref="Toplevel"/>-derived object of type <c>T</c> and calling
+    ///     <see cref="Run(Toplevel, Func{Exception, bool})"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <para>Calling <see cref="Init"/> first is not needed as this function will initialize the application.</para>
+    ///     <para>
+    ///         <see cref="Shutdown"/> must be called when the application is closing (typically after Run> has returned) to
+    ///         ensure resources are cleaned up and terminal settings restored.
+    ///     </para>
+    ///     <para>
+    ///         The caller is responsible for disposing the object returned by this method.
+    ///     </para>
+    /// </remarks>
+    /// <param name="errorHandler"></param>
+    /// <param name="driver">
+    ///     The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the platform will
+    ///     be used ( <see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, or <see cref="NetDriver"/>). Must be
+    ///     <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>
+    public static T Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
+        where T : Toplevel, new()
+    {
+        if (!_initialized)
+        {
+            // Init() has NOT been called.
+            InternalInit (driver, null, true);
+        }
+
+        var top = new T ();
+
+        Run (top, errorHandler);
+
+        return top;
+    }
+
+    /// <summary>Runs the Application using the provided <see cref="Toplevel"/> view.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         This method is used to start processing events for the main application, but it is also used to run other
+    ///         modal <see cref="View"/>s such as <see cref="Dialog"/> boxes.
+    ///     </para>
+    ///     <para>
+    ///         To make a <see cref="Run(Toplevel, Func{Exception, bool})"/> stop execution, call
+    ///         <see cref="Application.RequestStop"/>.
+    ///     </para>
+    ///     <para>
+    ///         Calling <see cref="Run(Toplevel, Func{Exception, bool})"/> is equivalent to calling
+    ///         <see cref="Begin(Toplevel)"/>, followed by <see cref="RunLoop(RunState)"/>, and then calling
+    ///         <see cref="End(RunState)"/>.
+    ///     </para>
+    ///     <para>
+    ///         Alternatively, to have a program control the main loop and process events manually, call
+    ///         <see cref="Begin(Toplevel)"/> to set things up manually and then repeatedly call
+    ///         <see cref="RunLoop(RunState)"/> with the wait parameter set to false. By doing this the
+    ///         <see cref="RunLoop(RunState)"/> method will only process any pending events, timers, idle handlers and then
+    ///         return control immediately.
+    ///     </para>
+    ///     <para>When using <see cref="Run{T}"/> or
+    ///         <see cref="Run(System.Func{System.Exception,bool},Terminal.Gui.ConsoleDriver)"/>
+    ///         <see cref="Init"/> will be called automatically.
+    ///     </para>
+    ///     <para>
+    ///         RELEASE builds only: When <paramref name="errorHandler"/> is <see langword="null"/> any exceptions will be
+    ///         rethrown. Otherwise, if <paramref name="errorHandler"/> will be called. If <paramref name="errorHandler"/>
+    ///         returns <see langword="true"/> the <see cref="RunLoop(RunState)"/> will resume; otherwise this method will
+    ///         exit.
+    ///     </para>
+    /// </remarks>
+    /// <param name="view">The <see cref="Toplevel"/> to run as a modal.</param>
+    /// <param name="errorHandler">
+    ///     RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true,
+    ///     rethrows when null).
+    /// </param>
+    public static void Run (Toplevel view, Func<Exception, bool> errorHandler = null)
+    {
+        ArgumentNullException.ThrowIfNull (view);
+
+        if (_initialized)
+        {
+            if (Driver is null)
+            {
+                // Disposing before throwing
+                view.Dispose ();
+
+                // This code path should be impossible because Init(null, null) will select the platform default driver
+                throw new InvalidOperationException (
+                                                     "Init() completed without a driver being set (this should be impossible); Run<T>() cannot be called."
+                                                    );
+            }
+        }
+        else
+        {
+            // Init() has NOT been called.
+            throw new InvalidOperationException (
+                                                 "Init() has not been called. Only Run() or Run<T>() can be used without calling Init()."
+                                                );
+        }
+
+        var resume = true;
+
+        while (resume)
+        {
+#if !DEBUG
+            try
+            {
+#endif
+            resume = false;
+            RunState runState = Begin (view);
+
+            // If EndAfterFirstIteration is true then the user must dispose of the runToken
+            // by using NotifyStopRunState event.
+            RunLoop (runState);
+
+            if (runState.Toplevel is null)
+            {
+#if DEBUG_IDISPOSABLE
+                Debug.Assert (_topLevels.Count == 0);
+#endif
+                runState.Dispose ();
+
+                return;
+            }
+
+            if (!EndAfterFirstIteration)
+            {
+                End (runState);
+            }
+#if !DEBUG
+            }
+            catch (Exception error)
+            {
+                if (errorHandler is null)
+                {
+                    throw;
+                }
+
+                resume = errorHandler (error);
+            }
+#endif
+        }
+    }
+
+    /// <summary>Adds a timeout to the application.</summary>
+    /// <remarks>
+    ///     When time specified passes, the callback will be invoked. If the callback returns true, the timeout will be
+    ///     reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a
+    ///     token that can be used to stop the timeout by calling <see cref="RemoveTimeout(object)"/>.
+    /// </remarks>
+    public static object AddTimeout (TimeSpan time, Func<bool> callback) { return MainLoop?.AddTimeout (time, callback); }
+
+    /// <summary>Removes a previously scheduled timeout</summary>
+    /// <remarks>The token parameter is the value returned by <see cref="AddTimeout"/>.</remarks>
+    /// Returns
+    /// <c>true</c>
+    /// if the timeout is successfully removed; otherwise,
+    /// <c>false</c>
+    /// .
+    /// This method also returns
+    /// <c>false</c>
+    /// if the timeout is not found.
+    public static bool RemoveTimeout (object token) { return MainLoop?.RemoveTimeout (token) ?? false; }
+
+    /// <summary>Runs <paramref name="action"/> on the thread that is processing events</summary>
+    /// <param name="action">the action to be invoked on the main processing thread.</param>
+    public static void Invoke (Action action)
+    {
+        MainLoop?.AddIdle (
+                           () =>
+                           {
+                               action ();
+
+                               return false;
+                           }
+                          );
+    }
+
+    // TODO: Determine if this is really needed. The only code that calls WakeUp I can find
+    // is ProgressBarStyles and it's not clear it needs to.
+    /// <summary>Wakes up the running application that might be waiting on input.</summary>
+    public static void Wakeup () { MainLoop?.Wakeup (); }
+
+    /// <summary>Triggers a refresh of the entire display.</summary>
+    public static void Refresh ()
+    {
+        // TODO: Figure out how to remove this call to ClearContents. Refresh should just repaint damaged areas, not clear
+        Driver.ClearContents ();
+        View last = null;
+
+        foreach (Toplevel v in _topLevels.Reverse ())
+        {
+            if (v.Visible)
+            {
+                v.SetNeedsDisplay ();
+                v.SetSubViewNeedsDisplay ();
+                v.Draw ();
+            }
+
+            last = v;
+        }
+
+        Driver.Refresh ();
+    }
+
+    /// <summary>This event is raised on each iteration of the main loop.</summary>
+    /// <remarks>See also <see cref="Timeout"/></remarks>
+    public static event EventHandler<IterationEventArgs> Iteration;
+
+    /// <summary>The <see cref="MainLoop"/> driver for the application</summary>
+    /// <value>The main loop.</value>
+    internal static MainLoop MainLoop { get; private set; }
+
+    /// <summary>
+    ///     Set to true to cause <see cref="End"/> to be called after the first iteration. Set to false (the default) to
+    ///     cause the application to continue running until Application.RequestStop () is called.
+    /// </summary>
+    public static bool EndAfterFirstIteration { get; set; }
+
+    /// <summary>Building block API: Runs the main loop for the created <see cref="Toplevel"/>.</summary>
+    /// <param name="state">The state returned by the <see cref="Begin(Toplevel)"/> method.</param>
+    public static void RunLoop (RunState state)
+    {
+        ArgumentNullException.ThrowIfNull (state);
+        ObjectDisposedException.ThrowIf (state.Toplevel is null, "state");
+
+        var firstIteration = true;
+
+        for (state.Toplevel.Running = true; state.Toplevel?.Running == true;)
+        {
+            MainLoop.Running = true;
+
+            if (EndAfterFirstIteration && !firstIteration)
+            {
+                return;
+            }
+
+            RunIteration (ref state, ref firstIteration);
+        }
+
+        MainLoop.Running = false;
+
+        // Run one last iteration to consume any outstanding input events from Driver
+        // This is important for remaining OnKeyUp events.
+        RunIteration (ref state, ref firstIteration);
+    }
+
+    /// <summary>Run one application iteration.</summary>
+    /// <param name="state">The state returned by <see cref="Begin(Toplevel)"/>.</param>
+    /// <param name="firstIteration">
+    ///     Set to <see langword="true"/> if this is the first run loop iteration. Upon return, it
+    ///     will be set to <see langword="false"/> if at least one iteration happened.
+    /// </param>
+    public static void RunIteration (ref RunState state, ref bool firstIteration)
+    {
+        if (MainLoop.Running && MainLoop.EventsPending ())
+        {
+            // Notify Toplevel it's ready
+            if (firstIteration)
+            {
+                state.Toplevel.OnReady ();
+            }
+
+            MainLoop.RunIteration ();
+            Iteration?.Invoke (null, new ());
+            EnsureModalOrVisibleAlwaysOnTop (state.Toplevel);
+
+            if (state.Toplevel != Current)
+            {
+                OverlappedTop?.OnDeactivate (state.Toplevel);
+                state.Toplevel = Current;
+                OverlappedTop?.OnActivate (state.Toplevel);
+                Top.SetSubViewNeedsDisplay ();
+                Refresh ();
+            }
+        }
+
+        firstIteration = false;
+
+        if (Current == null)
+        {
+            return;
+        }
+
+        if (state.Toplevel != Top && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded))
+        {
+            state.Toplevel.SetNeedsDisplay (state.Toplevel.Frame);
+            Top.Draw ();
+
+            foreach (Toplevel top in _topLevels.Reverse ())
+            {
+                if (top != Top && top != state.Toplevel)
+                {
+                    top.SetNeedsDisplay ();
+                    top.SetSubViewNeedsDisplay ();
+                    top.Draw ();
+                }
+            }
+        }
+
+        if (_topLevels.Count == 1
+            && state.Toplevel == Top
+            && (Driver.Cols != state.Toplevel.Frame.Width
+                || Driver.Rows != state.Toplevel.Frame.Height)
+            && (state.Toplevel.NeedsDisplay
+                || state.Toplevel.SubViewNeedsDisplay
+                || state.Toplevel.LayoutNeeded))
+        {
+            Driver.ClearContents ();
+        }
+
+        if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ())
+        {
+            state.Toplevel.SetNeedsDisplay ();
+            state.Toplevel.Draw ();
+            Driver.UpdateScreen ();
+
+            //Driver.UpdateCursor ();
+        }
+
+        if (PositionCursor (state.Toplevel))
+        {
+            Driver.UpdateCursor ();
+        }
+
+        //        else
+        {
+            //if (PositionCursor (state.Toplevel))
+            //{
+            //    Driver.Refresh ();
+            //}
+            //Driver.UpdateCursor ();
+        }
+
+        if (state.Toplevel != Top && !state.Toplevel.Modal && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded))
+        {
+            Top.Draw ();
+        }
+    }
+
+    /// <summary>Stops the provided <see cref="Toplevel"/>, causing or the <paramref name="top"/> if provided.</summary>
+    /// <param name="top">The <see cref="Toplevel"/> to stop.</param>
+    /// <remarks>
+    ///     <para>This will cause <see cref="Application.Run(Toplevel, Func{Exception, bool})"/> to return.</para>
+    ///     <para>
+    ///         Calling <see cref="Application.RequestStop"/> is equivalent to setting the <see cref="Toplevel.Running"/>
+    ///         property on the currently running <see cref="Toplevel"/> to false.
+    ///     </para>
+    /// </remarks>
+    public static void RequestStop (Toplevel top = null)
+    {
+        if (OverlappedTop is null || top is null || (OverlappedTop is null && top is { }))
+        {
+            top = Current;
+        }
+
+        if (OverlappedTop != null
+            && top.IsOverlappedContainer
+            && top?.Running == true
+            && (Current?.Modal == false || (Current?.Modal == true && Current?.Running == false)))
+        {
+            OverlappedTop.RequestStop ();
+        }
+        else if (OverlappedTop != null
+                 && top != Current
+                 && Current?.Running == true
+                 && Current?.Modal == true
+                 && top.Modal
+                 && top.Running)
+        {
+            var ev = new ToplevelClosingEventArgs (Current);
+            Current.OnClosing (ev);
+
+            if (ev.Cancel)
+            {
+                return;
+            }
+
+            ev = new (top);
+            top.OnClosing (ev);
+
+            if (ev.Cancel)
+            {
+                return;
+            }
+
+            Current.Running = false;
+            OnNotifyStopRunState (Current);
+            top.Running = false;
+            OnNotifyStopRunState (top);
+        }
+        else if ((OverlappedTop != null
+                  && top != OverlappedTop
+                  && top != Current
+                  && Current?.Modal == false
+                  && Current?.Running == true
+                  && !top.Running)
+                 || (OverlappedTop != null
+                     && top != OverlappedTop
+                     && top != Current
+                     && Current?.Modal == false
+                     && Current?.Running == false
+                     && !top.Running
+                     && _topLevels.ToArray () [1].Running))
+        {
+            MoveCurrent (top);
+        }
+        else if (OverlappedTop != null
+                 && Current != top
+                 && Current?.Running == true
+                 && !top.Running
+                 && Current?.Modal == true
+                 && top.Modal)
+        {
+            // The Current and the top are both modal so needed to set the Current.Running to false too.
+            Current.Running = false;
+            OnNotifyStopRunState (Current);
+        }
+        else if (OverlappedTop != null
+                 && Current == top
+                 && OverlappedTop?.Running == true
+                 && Current?.Running == true
+                 && top.Running
+                 && Current?.Modal == true
+                 && top.Modal)
+        {
+            // The OverlappedTop was requested to stop inside a modal Toplevel which is the Current and top,
+            // both are the same, so needed to set the Current.Running to false too.
+            Current.Running = false;
+            OnNotifyStopRunState (Current);
+        }
+        else
+        {
+            Toplevel currentTop;
+
+            if (top == Current || (Current?.Modal == true && !top.Modal))
+            {
+                currentTop = Current;
+            }
+            else
+            {
+                currentTop = top;
+            }
+
+            if (!currentTop.Running)
+            {
+                return;
+            }
+
+            var ev = new ToplevelClosingEventArgs (currentTop);
+            currentTop.OnClosing (ev);
+
+            if (ev.Cancel)
+            {
+                return;
+            }
+
+            currentTop.Running = false;
+            OnNotifyStopRunState (currentTop);
+        }
+    }
+
+    private static void OnNotifyStopRunState (Toplevel top)
+    {
+        if (EndAfterFirstIteration)
+        {
+            NotifyStopRunState?.Invoke (top, new (top));
+        }
+    }
+
+    /// <summary>
+    ///     Building block API: completes the execution of a <see cref="Toplevel"/> that was started with
+    ///     <see cref="Begin(Toplevel)"/> .
+    /// </summary>
+    /// <param name="runState">The <see cref="RunState"/> returned by the <see cref="Begin(Toplevel)"/> method.</param>
+    public static void End (RunState runState)
+    {
+        ArgumentNullException.ThrowIfNull (runState);
+
+        if (OverlappedTop is { })
+        {
+            OverlappedTop.OnChildUnloaded (runState.Toplevel);
+        }
+        else
+        {
+            runState.Toplevel.OnUnloaded ();
+        }
+
+        // End the RunState.Toplevel 
+        // First, take it off the Toplevel Stack
+        if (_topLevels.Count > 0)
+        {
+            if (_topLevels.Peek () != runState.Toplevel)
+            {
+                // If there the top of the stack is not the RunState.Toplevel then
+                // this call to End is not balanced with the call to Begin that started the RunState
+                throw new ArgumentException ("End must be balanced with calls to Begin");
+            }
+
+            _topLevels.Pop ();
+        }
+
+        // Notify that it is closing
+        runState.Toplevel?.OnClosed (runState.Toplevel);
+
+        // If there is a OverlappedTop that is not the RunState.Toplevel then runstate.TopLevel 
+        // is a child of MidTop and we should notify the OverlappedTop that it is closing
+        if (OverlappedTop is { } && !runState.Toplevel.Modal && runState.Toplevel != OverlappedTop)
+        {
+            OverlappedTop.OnChildClosed (runState.Toplevel);
+        }
+
+        // Set Current and Top to the next TopLevel on the stack
+        if (_topLevels.Count == 0)
+        {
+            Current = null;
+        }
+        else
+        {
+            if (_topLevels.Count > 1 && _topLevels.Peek () == OverlappedTop && OverlappedChildren.Any (t => t.Visible) is { })
+            {
+                OverlappedMoveNext ();
+            }
+
+            Current = _topLevels.Peek ();
+
+            if (_topLevels.Count == 1 && Current == OverlappedTop)
+            {
+                OverlappedTop.OnAllChildClosed ();
+            }
+            else
+            {
+                SetCurrentOverlappedAsTop ();
+                runState.Toplevel.OnLeave (Current);
+                Current.OnEnter (runState.Toplevel);
+            }
+
+            Refresh ();
+        }
+
+        // Don't dispose runState.Toplevel. It's up to caller dispose it
+        // If it's not the same as the current in the RunIteration,
+        // it will be fixed later in the next RunIteration.
+        if (OverlappedTop is { } && !_topLevels.Contains (OverlappedTop))
+        {
+            _cachedRunStateToplevel = OverlappedTop;
+        }
+        else
+        {
+            _cachedRunStateToplevel = runState.Toplevel;
+        }
+
+        runState.Toplevel = null;
+        runState.Dispose ();
+    }
+
+    #endregion Run (Begin, Run, End)
+
+    #region Toplevel handling
+
+    /// <summary>Holds the stack of TopLevel views.</summary>
+
+    // BUGBUG: Techncally, this is not the full lst of TopLevels. THere be dragons hwre. E.g. see how Toplevel.Id is used. What
+    // about TopLevels that are just a SubView of another View?
+    internal static readonly Stack<Toplevel> _topLevels = new ();
+
+    /// <summary>The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Application.Top"/>)</summary>
+    /// <value>The top.</value>
+    public static Toplevel Top { get; private set; }
+
+    /// <summary>
+    ///     The current <see cref="Toplevel"/> object. This is updated in <see cref="Application.Begin"/> enters and leaves to
+    ///     point to the current
+    ///     <see cref="Toplevel"/> .
+    /// </summary>
+    /// <remarks>
+    ///     Only relevant in scenarios where <see cref="Toplevel.IsOverlappedContainer"/> is <see langword="true"/>.
+    /// </remarks>
+    /// <value>The current.</value>
+    public static Toplevel Current { get; private set; }
+
+    private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel topLevel)
+    {
+        if (!topLevel.Running
+            || (topLevel == Current && topLevel.Visible)
+            || OverlappedTop == null
+            || _topLevels.Peek ().Modal)
+        {
+            return;
+        }
+
+        foreach (Toplevel top in _topLevels.Reverse ())
+        {
+            if (top.Modal && top != Current)
+            {
+                MoveCurrent (top);
+
+                return;
+            }
+        }
+
+        if (!topLevel.Visible && topLevel == Current)
+        {
+            OverlappedMoveNext ();
+        }
+    }
+
+#nullable enable
+    private static Toplevel? FindDeepestTop (Toplevel start, in Point location)
+    {
+        if (!start.Frame.Contains (location))
+        {
+            return null;
+        }
+
+        if (_topLevels is { Count: > 0 })
+        {
+            int rx = location.X - start.Frame.X;
+            int ry = location.Y - start.Frame.Y;
+
+            foreach (Toplevel t in _topLevels)
+            {
+                if (t != Current)
+                {
+                    if (t != start && t.Visible && t.Frame.Contains (rx, ry))
+                    {
+                        start = t;
+
+                        break;
+                    }
+                }
+            }
+        }
+
+        return start;
+    }
+#nullable restore
+
+    private static View FindTopFromView (View view)
+    {
+        View top = view?.SuperView is { } && view?.SuperView != Top
+                       ? view.SuperView
+                       : view;
+
+        while (top?.SuperView is { } && top?.SuperView != Top)
+        {
+            top = top.SuperView;
+        }
+
+        return top;
+    }
+
+#nullable enable
+
+    // Only return true if the Current has changed.
+    private static bool MoveCurrent (Toplevel? top)
+    {
+        // The Current is modal and the top is not modal Toplevel then
+        // the Current must be moved above the first not modal Toplevel.
+        if (OverlappedTop is { }
+            && top != OverlappedTop
+            && top != Current
+            && Current?.Modal == true
+            && !_topLevels.Peek ().Modal)
+        {
+            lock (_topLevels)
+            {
+                _topLevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
+            }
+
+            var index = 0;
+            Toplevel [] savedToplevels = _topLevels.ToArray ();
+
+            foreach (Toplevel t in savedToplevels)
+            {
+                if (!t.Modal && t != Current && t != top && t != savedToplevels [index])
+                {
+                    lock (_topLevels)
+                    {
+                        _topLevels.MoveTo (top, index, new ToplevelEqualityComparer ());
+                    }
+                }
+
+                index++;
+            }
+
+            return false;
+        }
+
+        // The Current and the top are both not running Toplevel then
+        // the top must be moved above the first not running Toplevel.
+        if (OverlappedTop is { }
+            && top != OverlappedTop
+            && top != Current
+            && Current?.Running == false
+            && top?.Running == false)
+        {
+            lock (_topLevels)
+            {
+                _topLevels.MoveTo (Current, 0, new ToplevelEqualityComparer ());
+            }
+
+            var index = 0;
+
+            foreach (Toplevel t in _topLevels.ToArray ())
+            {
+                if (!t.Running && t != Current && index > 0)
+                {
+                    lock (_topLevels)
+                    {
+                        _topLevels.MoveTo (top, index - 1, new ToplevelEqualityComparer ());
+                    }
+                }
+
+                index++;
+            }
+
+            return false;
+        }
+
+        if ((OverlappedTop is { } && top?.Modal == true && _topLevels.Peek () != top)
+            || (OverlappedTop is { } && Current != OverlappedTop && Current?.Modal == false && top == OverlappedTop)
+            || (OverlappedTop is { } && Current?.Modal == false && top != Current)
+            || (OverlappedTop is { } && Current?.Modal == true && top == OverlappedTop))
+        {
+            lock (_topLevels)
+            {
+                _topLevels.MoveTo (top, 0, new ToplevelEqualityComparer ());
+                Current = top;
+            }
+        }
+
+        return true;
+    }
+#nullable restore
+
+    /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
+    /// <remarks>
+    ///     Event handlers can set <see cref="SizeChangedEventArgs.Cancel"/> to <see langword="true"/> to prevent
+    ///     <see cref="Application"/> from changing it's size to match the new terminal size.
+    /// </remarks>
+    public static event EventHandler<SizeChangedEventArgs> SizeChanging;
+
+    /// <summary>
+    ///     Called when the application's size changes. Sets the size of all <see cref="Toplevel"/>s and fires the
+    ///     <see cref="SizeChanging"/> event.
+    /// </summary>
+    /// <param name="args">The new size.</param>
+    /// <returns><see lanword="true"/>if the size was changed.</returns>
+    public static bool OnSizeChanging (SizeChangedEventArgs args)
+    {
+        SizeChanging?.Invoke (null, args);
+
+        if (args.Cancel || args.Size is null)
+        {
+            return false;
+        }
+
+        foreach (Toplevel t in _topLevels)
+        {
+            t.SetRelativeLayout (args.Size.Value);
+            t.LayoutSubviews ();
+            t.PositionToplevels ();
+            t.OnSizeChanging (new (args.Size));
+
+            if (PositionCursor (t))
+            {
+                Driver.UpdateCursor ();
+            }
+        }
+
+        Refresh ();
+
+        return true;
+    }
+
+    #endregion Toplevel handling
+
+    /// <summary>
+    ///     Gets a string representation of the Application as rendered by <see cref="Driver"/>.
+    /// </summary>
+    /// <returns>A string representation of the Application </returns>
+    public new static string ToString ()
+    {
+        ConsoleDriver driver = Driver;
+
+        if (driver is null)
+        {
+            return string.Empty;
+        }
+
+        return ToString (driver);
+    }
+
+    /// <summary>
+    ///     Gets a string representation of the Application rendered by the provided <see cref="ConsoleDriver"/>.
+    /// </summary>
+    /// <param name="driver">The driver to use to render the contents.</param>
+    /// <returns>A string representation of the Application </returns>
+    public static string ToString (ConsoleDriver driver)
+    {
+        var sb = new StringBuilder ();
+
+        Cell [,] contents = driver.Contents;
+
+        for (var r = 0; r < driver.Rows; r++)
+        {
+            for (var c = 0; c < driver.Cols; c++)
+            {
+                Rune rune = contents [r, c].Rune;
+
+                if (rune.DecodeSurrogatePair (out char [] sp))
+                {
+                    sb.Append (sp);
+                }
+                else
+                {
+                    sb.Append ((char)rune.Value);
+                }
+
+                if (rune.GetColumns () > 1)
+                {
+                    c++;
+                }
+
+                // See Issue #2616
+                //foreach (var combMark in contents [r, c].CombiningMarks) {
+                //	sb.Append ((char)combMark.Value);
+                //}
+            }
+
+            sb.AppendLine ();
+        }
+        return sb.ToString ();
+    }
+}

+ 303 - 0
Terminal.Gui/Application/ApplicationKeyboard.cs

@@ -0,0 +1,303 @@
+using System.Text.Json.Serialization;
+
+namespace Terminal.Gui;
+
+partial class Application
+{
+    private static Key _alternateForwardKey = Key.Empty; // Defined in config.json
+
+    /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    [JsonConverter (typeof (KeyJsonConverter))]
+    public static Key AlternateForwardKey
+    {
+        get => _alternateForwardKey;
+        set
+        {
+            if (_alternateForwardKey != value)
+            {
+                Key oldKey = _alternateForwardKey;
+                _alternateForwardKey = value;
+                OnAlternateForwardKeyChanged (new (oldKey, value));
+            }
+        }
+    }
+
+    private static void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
+    {
+        foreach (Toplevel top in _topLevels.ToArray ())
+        {
+            top.OnAlternateForwardKeyChanged (e);
+        }
+    }
+
+    private static Key _alternateBackwardKey = Key.Empty; // Defined in config.json
+
+    /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    [JsonConverter (typeof (KeyJsonConverter))]
+    public static Key AlternateBackwardKey
+    {
+        get => _alternateBackwardKey;
+        set
+        {
+            if (_alternateBackwardKey != value)
+            {
+                Key oldKey = _alternateBackwardKey;
+                _alternateBackwardKey = value;
+                OnAlternateBackwardKeyChanged (new (oldKey, value));
+            }
+        }
+    }
+
+    private static void OnAlternateBackwardKeyChanged (KeyChangedEventArgs oldKey)
+    {
+        foreach (Toplevel top in _topLevels.ToArray ())
+        {
+            top.OnAlternateBackwardKeyChanged (oldKey);
+        }
+    }
+
+    private static Key _quitKey = Key.Empty; // Defined in config.json
+
+    /// <summary>Gets or sets the key to quit the application.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    [JsonConverter (typeof (KeyJsonConverter))]
+    public static Key QuitKey
+    {
+        get => _quitKey;
+        set
+        {
+            if (_quitKey != value)
+            {
+                Key oldKey = _quitKey;
+                _quitKey = value;
+                OnQuitKeyChanged (new (oldKey, value));
+            }
+        }
+    }
+
+    private static void OnQuitKeyChanged (KeyChangedEventArgs e)
+    {
+        // Duplicate the list so if it changes during enumeration we're safe
+        foreach (Toplevel top in _topLevels.ToArray ())
+        {
+            top.OnQuitKeyChanged (e);
+        }
+    }
+
+    /// <summary>
+    ///     Event fired when the user presses a key. Fired by <see cref="OnKeyDown"/>.
+    ///     <para>
+    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
+    ///         additional processing.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
+    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
+    ///     <para>Fired after <see cref="KeyDown"/> and before <see cref="KeyUp"/>.</para>
+    /// </remarks>
+    public static event EventHandler<Key> KeyDown;
+
+    /// <summary>
+    ///     Called by the <see cref="ConsoleDriver"/> when the user presses a key. Fires the <see cref="KeyDown"/> event
+    ///     then calls <see cref="View.NewKeyDownEvent"/> on all top level views. Called after <see cref="OnKeyDown"/> and
+    ///     before <see cref="OnKeyUp"/>.
+    /// </summary>
+    /// <remarks>Can be used to simulate key press events.</remarks>
+    /// <param name="keyEvent"></param>
+    /// <returns><see langword="true"/> if the key was handled.</returns>
+    public static bool OnKeyDown (Key keyEvent)
+    {
+        if (!_initialized)
+        {
+            return true;
+        }
+
+        KeyDown?.Invoke (null, keyEvent);
+
+        if (keyEvent.Handled)
+        {
+            return true;
+        }
+
+        foreach (Toplevel topLevel in _topLevels.ToList ())
+        {
+            if (topLevel.NewKeyDownEvent (keyEvent))
+            {
+                return true;
+            }
+
+            if (topLevel.Modal)
+            {
+                break;
+            }
+        }
+
+        // Invoke any global (Application-scoped) KeyBindings.
+        // The first view that handles the key will stop the loop.
+        foreach (KeyValuePair<Key, List<View>> binding in _keyBindings.Where (b => b.Key == keyEvent.KeyCode))
+        {
+            foreach (View view in binding.Value)
+            {
+                if (view is {} && view.KeyBindings.TryGet (binding.Key, (KeyBindingScope)0xFFFF, out KeyBinding kb))
+                {
+                    //bool? handled = view.InvokeCommands (kb.Commands, binding.Key, kb);
+                    bool? handled = view?.OnInvokingKeyBindings (keyEvent, kb.Scope);
+
+                    if (handled != null && (bool)handled)
+                    {
+                        return true;
+                    }
+
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    ///     Event fired when the user releases a key. Fired by <see cref="OnKeyUp"/>.
+    ///     <para>
+    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
+    ///         additional processing.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
+    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
+    ///     <para>Fired after <see cref="KeyDown"/>.</para>
+    /// </remarks>
+    public static event EventHandler<Key> KeyUp;
+
+    /// <summary>
+    ///     Called by the <see cref="ConsoleDriver"/> when the user releases a key. Fires the <see cref="KeyUp"/> event
+    ///     then calls <see cref="View.NewKeyUpEvent"/> on all top level views. Called after <see cref="OnKeyDown"/>.
+    /// </summary>
+    /// <remarks>Can be used to simulate key press events.</remarks>
+    /// <param name="a"></param>
+    /// <returns><see langword="true"/> if the key was handled.</returns>
+    public static bool OnKeyUp (Key a)
+    {
+        if (!_initialized)
+        {
+            return true;
+        }
+
+        KeyUp?.Invoke (null, a);
+
+        if (a.Handled)
+        {
+            return true;
+        }
+
+        foreach (Toplevel topLevel in _topLevels.ToList ())
+        {
+            if (topLevel.NewKeyUpEvent (a))
+            {
+                return true;
+            }
+
+            if (topLevel.Modal)
+            {
+                break;
+            }
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    ///     The <see cref="KeyBindingScope.Application"/> key bindings.
+    /// </summary>
+    private static readonly Dictionary<Key, List<View>> _keyBindings = new ();
+
+    /// <summary>
+    /// Gets the list of <see cref="KeyBindingScope.Application"/> key bindings.
+    /// </summary>
+    public static Dictionary<Key, List<View>> GetKeyBindings () { return _keyBindings; }
+
+    /// <summary>
+    ///     Adds an  <see cref="KeyBindingScope.Application"/> scoped key binding.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
+    /// </remarks>
+    /// <param name="key">The key being bound.</param>
+    /// <param name="view">The view that is bound to the key.</param>
+    internal static void AddKeyBinding (Key key, View view)
+    {
+        if (!_keyBindings.ContainsKey (key))
+        {
+            _keyBindings [key] = [];
+        }
+
+        _keyBindings [key].Add (view);
+    }
+
+    /// <summary>
+    ///     Gets the list of Views that have <see cref="KeyBindingScope.Application"/> key bindings.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
+    /// </remarks>
+    /// <returns>The list of Views that have Application-scoped key bindings.</returns>
+    internal static List<View> GetViewsWithKeyBindings () { return _keyBindings.Values.SelectMany (v => v).ToList (); }
+
+    /// <summary>
+    ///     Gets the list of Views that have <see cref="KeyBindingScope.Application"/> key bindings for the specified key.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
+    /// </remarks>
+    /// <param name="key">The key to check.</param>
+    /// <param name="views">Outputs the list of views bound to <paramref name="key"/></param>
+    /// <returns><see langword="True"/> if successful.</returns>
+    internal static bool TryGetKeyBindings (Key key, out List<View> views) { return _keyBindings.TryGetValue (key, out views); }
+
+    /// <summary>
+    ///     Removes an <see cref="KeyBindingScope.Application"/> scoped key binding.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
+    /// </remarks>
+    /// <param name="key">The key that was bound.</param>
+    /// <param name="view">The view that is bound to the key.</param>
+    internal static void RemoveKeyBinding (Key key, View view)
+    {
+        if (_keyBindings.TryGetValue (key, out List<View> views))
+        {
+            views.Remove (view);
+
+            if (views.Count == 0)
+            {
+                _keyBindings.Remove (key);
+            }
+        }
+    }
+
+    /// <summary>
+    ///     Removes all <see cref="KeyBindingScope.Application"/> scoped key bindings for the specified view.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
+    /// </remarks>
+    /// <param name="view">The view that is bound to the key.</param>
+    internal static void ClearKeyBindings (View view)
+    {
+        foreach (Key key in _keyBindings.Keys)
+        {
+            _keyBindings [key].Remove (view);
+        }
+    }
+
+    /// <summary>
+    ///     Removes all <see cref="KeyBindingScope.Application"/> scoped key bindings for the specified view.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
+    /// </remarks>
+    internal static void ClearKeyBindings () { _keyBindings.Clear (); }
+}

+ 302 - 0
Terminal.Gui/Application/ApplicationMouse.cs

@@ -0,0 +1,302 @@
+namespace Terminal.Gui;
+
+partial class Application
+{
+    #region Mouse handling
+
+    /// <summary>Disable or enable the mouse. The mouse is enabled by default.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static bool IsMouseDisabled { get; set; }
+
+    /// <summary>The current <see cref="View"/> object that wants continuous mouse button pressed events.</summary>
+    public static View WantContinuousButtonPressedView { get; private set; }
+
+    /// <summary>
+    ///     Gets the view that grabbed the mouse (e.g. for dragging). When this is set, all mouse events will be routed to
+    ///     this view until the view calls <see cref="UngrabMouse"/> or the mouse is released.
+    /// </summary>
+    public static View MouseGrabView { get; private set; }
+
+    /// <summary>Invoked when a view wants to grab the mouse; can be canceled.</summary>
+    public static event EventHandler<GrabMouseEventArgs> GrabbingMouse;
+
+    /// <summary>Invoked when a view wants un-grab the mouse; can be canceled.</summary>
+    public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
+
+    /// <summary>Invoked after a view has grabbed the mouse.</summary>
+    public static event EventHandler<ViewEventArgs> GrabbedMouse;
+
+    /// <summary>Invoked after a view has un-grabbed the mouse.</summary>
+    public static event EventHandler<ViewEventArgs> UnGrabbedMouse;
+
+    /// <summary>
+    ///     Grabs the mouse, forcing all mouse events to be routed to the specified view until <see cref="UngrabMouse"/>
+    ///     is called.
+    /// </summary>
+    /// <param name="view">View that will receive all mouse events until <see cref="UngrabMouse"/> is invoked.</param>
+    public static void GrabMouse (View view)
+    {
+        if (view is null)
+        {
+            return;
+        }
+
+        if (!OnGrabbingMouse (view))
+        {
+            OnGrabbedMouse (view);
+            MouseGrabView = view;
+        }
+    }
+
+    /// <summary>Releases the mouse grab, so mouse events will be routed to the view on which the mouse is.</summary>
+    public static void UngrabMouse ()
+    {
+        if (MouseGrabView is null)
+        {
+            return;
+        }
+
+        if (!OnUnGrabbingMouse (MouseGrabView))
+        {
+            View view = MouseGrabView;
+            MouseGrabView = null;
+            OnUnGrabbedMouse (view);
+        }
+    }
+
+    private static bool OnGrabbingMouse (View view)
+    {
+        if (view is null)
+        {
+            return false;
+        }
+
+        var evArgs = new GrabMouseEventArgs (view);
+        GrabbingMouse?.Invoke (view, evArgs);
+
+        return evArgs.Cancel;
+    }
+
+    private static bool OnUnGrabbingMouse (View view)
+    {
+        if (view is null)
+        {
+            return false;
+        }
+
+        var evArgs = new GrabMouseEventArgs (view);
+        UnGrabbingMouse?.Invoke (view, evArgs);
+
+        return evArgs.Cancel;
+    }
+
+    private static void OnGrabbedMouse (View view)
+    {
+        if (view is null)
+        {
+            return;
+        }
+
+        GrabbedMouse?.Invoke (view, new (view));
+    }
+
+    private static void OnUnGrabbedMouse (View view)
+    {
+        if (view is null)
+        {
+            return;
+        }
+
+        UnGrabbedMouse?.Invoke (view, new (view));
+    }
+
+#nullable enable
+
+    // Used by OnMouseEvent to track the last view that was clicked on.
+    internal static View? _mouseEnteredView;
+
+    /// <summary>Event fired when a mouse move or click occurs. Coordinates are screen relative.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         Use this event to receive mouse events in screen coordinates. Use <see cref="MouseEvent"/> to
+    ///         receive mouse events relative to a <see cref="View.Viewport"/>.
+    ///     </para>
+    ///     <para>The <see cref="MouseEvent.View"/> will contain the <see cref="View"/> that contains the mouse coordinates.</para>
+    /// </remarks>
+    public static event EventHandler<MouseEvent>? MouseEvent;
+
+    /// <summary>Called when a mouse event occurs. Raises the <see cref="MouseEvent"/> event.</summary>
+    /// <remarks>This method can be used to simulate a mouse event, e.g. in unit tests.</remarks>
+    /// <param name="mouseEvent">The mouse event with coordinates relative to the screen.</param>
+    internal static void OnMouseEvent (MouseEvent mouseEvent)
+    {
+        if (IsMouseDisabled)
+        {
+            return;
+        }
+
+        var view = View.FindDeepestView (Current, mouseEvent.Position);
+
+        if (view is { })
+        {
+            mouseEvent.View = view;
+        }
+
+        MouseEvent?.Invoke (null, mouseEvent);
+
+        if (mouseEvent.Handled)
+        {
+            return;
+        }
+
+        if (MouseGrabView is { })
+        {
+            // If the mouse is grabbed, send the event to the view that grabbed it.
+            // The coordinates are relative to the Bounds of the view that grabbed the mouse.
+            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.Position);
+
+            var viewRelativeMouseEvent = new MouseEvent
+            {
+                Position = frameLoc,
+                Flags = mouseEvent.Flags,
+                ScreenPosition = mouseEvent.Position,
+                View = MouseGrabView
+            };
+
+            if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.Position) is false)
+            {
+                // The mouse has moved outside the bounds of the view that grabbed the mouse
+                _mouseEnteredView?.NewMouseLeaveEvent (mouseEvent);
+            }
+
+            //System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
+            if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) == true)
+            {
+                return;
+            }
+        }
+
+        if (view is { WantContinuousButtonPressed: true })
+        {
+            WantContinuousButtonPressedView = view;
+        }
+        else
+        {
+            WantContinuousButtonPressedView = null;
+        }
+
+        if (view is not Adornment)
+        {
+            if ((view is null || view == OverlappedTop)
+                && Current is { Modal: false }
+                && OverlappedTop != null
+                && mouseEvent.Flags != MouseFlags.ReportMousePosition
+                && mouseEvent.Flags != 0)
+            {
+                // This occurs when there are multiple overlapped "tops"
+                // E.g. "Mdi" - in the Background Worker Scenario
+                View? top = FindDeepestTop (Top, mouseEvent.Position);
+                view = View.FindDeepestView (top, mouseEvent.Position);
+
+                if (view is { } && view != OverlappedTop && top != Current && top is { })
+                {
+                    MoveCurrent ((Toplevel)top);
+                }
+            }
+        }
+
+        if (view is null)
+        {
+            return;
+        }
+
+        MouseEvent? me = null;
+
+        if (view is Adornment adornment)
+        {
+            Point frameLoc = adornment.ScreenToFrame (mouseEvent.Position);
+
+            me = new ()
+            {
+                Position = frameLoc,
+                Flags = mouseEvent.Flags,
+                ScreenPosition = mouseEvent.Position,
+                View = view
+            };
+        }
+        else if (view.ViewportToScreen (Rectangle.Empty with { Size = view.Viewport.Size }).Contains (mouseEvent.Position))
+        {
+            Point viewportLocation = view.ScreenToViewport (mouseEvent.Position);
+
+            me = new ()
+            {
+                Position = viewportLocation,
+                Flags = mouseEvent.Flags,
+                ScreenPosition = mouseEvent.Position,
+                View = view
+            };
+        }
+
+        if (me is null)
+        {
+            return;
+        }
+
+        if (_mouseEnteredView is null)
+        {
+            _mouseEnteredView = view;
+            view.NewMouseEnterEvent (me);
+        }
+        else if (_mouseEnteredView != view)
+        {
+            _mouseEnteredView.NewMouseLeaveEvent (me);
+            view.NewMouseEnterEvent (me);
+            _mouseEnteredView = view;
+        }
+
+        if (!view.WantMousePositionReports && mouseEvent.Flags == MouseFlags.ReportMousePosition)
+        {
+            return;
+        }
+
+        WantContinuousButtonPressedView = view.WantContinuousButtonPressed ? view : null;
+
+        //Debug.WriteLine ($"OnMouseEvent: ({a.MouseEvent.X},{a.MouseEvent.Y}) - {a.MouseEvent.Flags}");
+
+        while (view.NewMouseEvent (me) != true)
+        {
+            if (MouseGrabView is { })
+            {
+                break;
+            }
+
+            if (view is Adornment adornmentView)
+            {
+                view = adornmentView.Parent.SuperView;
+            }
+            else
+            {
+                view = view.SuperView;
+            }
+
+            if (view is null)
+            {
+                break;
+            }
+
+            Point boundsPoint = view.ScreenToViewport (mouseEvent.Position);
+
+            me = new ()
+            {
+                Position = boundsPoint,
+                Flags = mouseEvent.Flags,
+                ScreenPosition = mouseEvent.Position,
+                View = view
+            };
+        }
+
+        BringOverlappedTopToFront ();
+    }
+
+    #endregion Mouse handling
+}

+ 5 - 0
Terminal.Gui/Application/IterationEventArgs.cs

@@ -0,0 +1,5 @@
+namespace Terminal.Gui;
+
+/// <summary>Event arguments for the <see cref="Application.Iteration"/> event.</summary>
+public class IterationEventArgs : EventArgs
+{ }

+ 392 - 0
Terminal.Gui/Application/MainLoop.cs

@@ -0,0 +1,392 @@
+//
+// MainLoop.cs: IMainLoopDriver and MainLoop for Terminal.Gui
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+
+using System.Collections.ObjectModel;
+
+namespace Terminal.Gui;
+
+/// <summary>Interface to create a platform specific <see cref="MainLoop"/> driver.</summary>
+internal interface IMainLoopDriver
+{
+    /// <summary>Must report whether there are any events pending, or even block waiting for events.</summary>
+    /// <returns><c>true</c>, if there were pending events, <c>false</c> otherwise.</returns>
+    bool EventsPending ();
+
+    /// <summary>The iteration function.</summary>
+    void Iteration ();
+
+    /// <summary>Initializes the <see cref="MainLoop"/>, gets the calling main loop for the initialization.</summary>
+    /// <remarks>Call <see cref="TearDown"/> to release resources.</remarks>
+    /// <param name="mainLoop">Main loop.</param>
+    void Setup (MainLoop mainLoop);
+
+    /// <summary>Tears down the <see cref="MainLoop"/> driver. Releases resources created in <see cref="Setup"/>.</summary>
+    void TearDown ();
+
+    /// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input, must be thread safe.</summary>
+    void Wakeup ();
+}
+
+/// <summary>The MainLoop monitors timers and idle handlers.</summary>
+/// <remarks>
+///     Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
+///     on Windows.
+/// </remarks>
+internal class MainLoop : IDisposable
+{
+    internal List<Func<bool>> _idleHandlers = new ();
+    internal SortedList<long, Timeout> _timeouts = new ();
+
+    /// <summary>The idle handlers and lock that must be held while manipulating them</summary>
+    private readonly object _idleHandlersLock = new ();
+
+    private readonly object _timeoutsLockToken = new ();
+
+    /// <summary>Creates a new MainLoop.</summary>
+    /// <remarks>Use <see cref="Dispose"/> to release resources.</remarks>
+    /// <param name="driver">
+    ///     The <see cref="ConsoleDriver"/> instance (one of the implementations FakeMainLoop, UnixMainLoop,
+    ///     NetMainLoop or WindowsMainLoop).
+    /// </param>
+    internal MainLoop (IMainLoopDriver driver)
+    {
+        MainLoopDriver = driver;
+        driver.Setup (this);
+    }
+
+    /// <summary>Gets a copy of the list of all idle handlers.</summary>
+    internal ReadOnlyCollection<Func<bool>> IdleHandlers
+    {
+        get
+        {
+            lock (_idleHandlersLock)
+            {
+                return new List<Func<bool>> (_idleHandlers).AsReadOnly ();
+            }
+        }
+    }
+
+    /// <summary>The current <see cref="IMainLoopDriver"/> in use.</summary>
+    /// <value>The main loop driver.</value>
+    internal IMainLoopDriver MainLoopDriver { get; private set; }
+
+    /// <summary>Used for unit tests.</summary>
+    internal bool Running { get; set; }
+
+    /// <summary>
+    ///     Gets the list of all timeouts sorted by the <see cref="TimeSpan"/> time ticks. A shorter limit time can be
+    ///     added at the end, but it will be called before an earlier addition that has a longer limit time.
+    /// </summary>
+    internal SortedList<long, Timeout> Timeouts => _timeouts;
+
+    /// <inheritdoc/>
+    public void Dispose ()
+    {
+        GC.SuppressFinalize (this);
+        Stop ();
+        Running = false;
+        MainLoopDriver?.TearDown ();
+        MainLoopDriver = null;
+    }
+
+    /// <summary>
+    ///     Adds specified idle handler function to <see cref="MainLoop"/> processing. The handler function will be called
+    ///     once per iteration of the main loop after other events have been handled.
+    /// </summary>
+    /// <remarks>
+    ///     <para>Remove an idle handler by calling <see cref="RemoveIdle(Func{bool})"/> with the token this method returns.</para>
+    ///     <para>
+    ///         If the <paramref name="idleHandler"/> returns  <see langword="false"/> it will be removed and not called
+    ///         subsequently.
+    ///     </para>
+    /// </remarks>
+    /// <param name="idleHandler">Token that can be used to remove the idle handler with <see cref="RemoveIdle(Func{bool})"/> .</param>
+    // QUESTION: Why are we re-inventing the event wheel here?
+    // PERF: This is heavy.
+    // CONCURRENCY: Race conditions exist here.
+    // CONCURRENCY: null delegates will hose this.
+    // 
+    internal Func<bool> AddIdle (Func<bool> idleHandler)
+    {
+        lock (_idleHandlersLock)
+        {
+            _idleHandlers.Add (idleHandler);
+        }
+
+        MainLoopDriver.Wakeup ();
+
+        return idleHandler;
+    }
+
+    /// <summary>Adds a timeout to the <see cref="MainLoop"/>.</summary>
+    /// <remarks>
+    ///     When time specified passes, the callback will be invoked. If the callback returns true, the timeout will be
+    ///     reset, repeating the invocation. If it returns false, the timeout will stop and be removed. The returned value is a
+    ///     token that can be used to stop the timeout by calling <see cref="RemoveTimeout(object)"/>.
+    /// </remarks>
+    internal object AddTimeout (TimeSpan time, Func<bool> callback)
+    {
+        if (callback is null)
+        {
+            throw new ArgumentNullException (nameof (callback));
+        }
+
+        var timeout = new Timeout { Span = time, Callback = callback };
+        AddTimeout (time, timeout);
+
+        return timeout;
+    }
+
+    /// <summary>
+    ///     Called from <see cref="IMainLoopDriver.EventsPending"/> to check if there are any outstanding timers or idle
+    ///     handlers.
+    /// </summary>
+    /// <param name="waitTimeout">
+    ///     Returns the number of milliseconds remaining in the current timer (if any). Will be -1 if
+    ///     there are no active timers.
+    /// </param>
+    /// <returns><see langword="true"/> if there is a timer or idle handler active.</returns>
+    internal bool CheckTimersAndIdleHandlers (out int waitTimeout)
+    {
+        long now = DateTime.UtcNow.Ticks;
+
+        waitTimeout = 0;
+
+        lock (_timeouts)
+        {
+            if (_timeouts.Count > 0)
+            {
+                waitTimeout = (int)((_timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
+
+                if (waitTimeout < 0)
+                {
+                    // This avoids 'poll' waiting infinitely if 'waitTimeout < 0' until some action is detected
+                    // This can occur after IMainLoopDriver.Wakeup is executed where the pollTimeout is less than 0
+                    // and no event occurred in elapsed time when the 'poll' is start running again.
+                    waitTimeout = 0;
+                }
+
+                return true;
+            }
+
+            // ManualResetEventSlim.Wait, which is called by IMainLoopDriver.EventsPending, will wait indefinitely if
+            // the timeout is -1.
+            waitTimeout = -1;
+        }
+
+        // There are no timers set, check if there are any idle handlers
+
+        lock (_idleHandlers)
+        {
+            return _idleHandlers.Count > 0;
+        }
+    }
+
+    /// <summary>Determines whether there are pending events to be processed.</summary>
+    /// <remarks>
+    ///     You can use this method if you want to probe if events are pending. Typically used if you need to flush the
+    ///     input queue while still running some of your own code in your main thread.
+    /// </remarks>
+    internal bool EventsPending () { return MainLoopDriver.EventsPending (); }
+
+    /// <summary>Removes an idle handler added with <see cref="AddIdle(Func{bool})"/> from processing.</summary>
+    /// <param name="token">A token returned by <see cref="AddIdle(Func{bool})"/></param>
+    /// Returns
+    /// <c>true</c>
+    /// if the idle handler is successfully removed; otherwise,
+    /// <c>false</c>
+    /// .
+    /// This method also returns
+    /// <c>false</c>
+    /// if the idle handler is not found.
+    internal bool RemoveIdle (Func<bool> token)
+    {
+        lock (_idleHandlersLock)
+        {
+            return _idleHandlers.Remove (token);
+        }
+    }
+
+    /// <summary>Removes a previously scheduled timeout</summary>
+    /// <remarks>The token parameter is the value returned by AddTimeout.</remarks>
+    /// Returns
+    /// <c>true</c>
+    /// if the timeout is successfully removed; otherwise,
+    /// <c>false</c>
+    /// .
+    /// This method also returns
+    /// <c>false</c>
+    /// if the timeout is not found.
+    internal bool RemoveTimeout (object token)
+    {
+        lock (_timeoutsLockToken)
+        {
+            int idx = _timeouts.IndexOfValue (token as Timeout);
+
+            if (idx == -1)
+            {
+                return false;
+            }
+
+            _timeouts.RemoveAt (idx);
+        }
+
+        return true;
+    }
+
+    /// <summary>Runs the <see cref="MainLoop"/>. Used only for unit tests.</summary>
+    internal void Run ()
+    {
+        bool prev = Running;
+        Running = true;
+
+        while (Running)
+        {
+            EventsPending ();
+            RunIteration ();
+        }
+
+        Running = prev;
+    }
+
+    /// <summary>Runs one iteration of timers and file watches</summary>
+    /// <remarks>
+    ///     Use this to process all pending events (timers, idle handlers and file watches).
+    ///     <code>
+    ///     while (main.EventsPending ()) RunIteration ();
+    ///   </code>
+    /// </remarks>
+    internal void RunIteration ()
+    {
+        lock (_timeouts)
+        {
+            if (_timeouts.Count > 0)
+            {
+                RunTimers ();
+            }
+        }
+
+        MainLoopDriver.Iteration ();
+
+        var runIdle = false;
+
+        lock (_idleHandlersLock)
+        {
+            runIdle = _idleHandlers.Count > 0;
+        }
+
+        if (runIdle)
+        {
+            RunIdle ();
+        }
+    }
+
+    /// <summary>Stops the main loop driver and calls <see cref="IMainLoopDriver.Wakeup"/>. Used only for unit tests.</summary>
+    internal void Stop ()
+    {
+        Running = false;
+        Wakeup ();
+    }
+
+    /// <summary>
+    ///     Invoked when a new timeout is added. To be used in the case when
+    ///     <see cref="Application.EndAfterFirstIteration"/> is <see langword="true"/>.
+    /// </summary>
+    internal event EventHandler<TimeoutEventArgs> TimeoutAdded;
+
+    /// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input.</summary>
+    internal void Wakeup () { MainLoopDriver?.Wakeup (); }
+
+    private void AddTimeout (TimeSpan time, Timeout timeout)
+    {
+        lock (_timeoutsLockToken)
+        {
+            long k = (DateTime.UtcNow + time).Ticks;
+            _timeouts.Add (NudgeToUniqueKey (k), timeout);
+            TimeoutAdded?.Invoke (this, new TimeoutEventArgs (timeout, k));
+        }
+    }
+
+    /// <summary>
+    ///     Finds the closest number to <paramref name="k"/> that is not present in <see cref="_timeouts"/>
+    ///     (incrementally).
+    /// </summary>
+    /// <param name="k"></param>
+    /// <returns></returns>
+    private long NudgeToUniqueKey (long k)
+    {
+        lock (_timeoutsLockToken)
+        {
+            while (_timeouts.ContainsKey (k))
+            {
+                k++;
+            }
+        }
+
+        return k;
+    }
+
+    // PERF: This is heavier than it looks.
+    // CONCURRENCY: Potential deadlock city here.
+    // CONCURRENCY: Multiple concurrency pitfalls on the delegates themselves.
+    // INTENT: It looks like the general architecture here is trying to be a form of publisher/consumer pattern.
+    private void RunIdle ()
+    {
+        List<Func<bool>> iterate;
+
+        lock (_idleHandlersLock)
+        {
+            iterate = _idleHandlers;
+            _idleHandlers = new List<Func<bool>> ();
+        }
+
+        foreach (Func<bool> idle in iterate)
+        {
+            if (idle ())
+            {
+                lock (_idleHandlersLock)
+                {
+                    _idleHandlers.Add (idle);
+                }
+            }
+        }
+    }
+
+    private void RunTimers ()
+    {
+        long now = DateTime.UtcNow.Ticks;
+        SortedList<long, Timeout> copy;
+
+        // lock prevents new timeouts being added
+        // after we have taken the copy but before
+        // we have allocated a new list (which would
+        // result in lost timeouts or errors during enumeration)
+        lock (_timeoutsLockToken)
+        {
+            copy = _timeouts;
+            _timeouts = new SortedList<long, Timeout> ();
+        }
+
+        foreach ((long k, Timeout timeout) in copy)
+        {
+            if (k < now)
+            {
+                if (timeout.Callback ())
+                {
+                    AddTimeout (timeout.Span, timeout);
+                }
+            }
+            else
+            {
+                lock (_timeoutsLockToken)
+                {
+                    _timeouts.Add (NudgeToUniqueKey (k), timeout);
+                }
+            }
+        }
+    }
+}

+ 48 - 0
Terminal.Gui/Application/MainLoopSyncContext.cs

@@ -0,0 +1,48 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     provides the sync context set while executing code in Terminal.Gui, to let
+///     users use async/await on their code
+/// </summary>
+internal sealed class MainLoopSyncContext : SynchronizationContext
+{
+    public override SynchronizationContext CreateCopy () { return new MainLoopSyncContext (); }
+
+    public override void Post (SendOrPostCallback d, object state)
+    {
+        Application.MainLoop?.AddIdle (
+                                       () =>
+                                       {
+                                           d (state);
+
+                                           return false;
+                                       }
+                                      );
+    }
+
+    //_mainLoop.Driver.Wakeup ();
+    public override void Send (SendOrPostCallback d, object state)
+    {
+        if (Thread.CurrentThread.ManagedThreadId == Application._mainThreadId)
+        {
+            d (state);
+        }
+        else
+        {
+            var wasExecuted = false;
+
+            Application.Invoke (
+                                () =>
+                                {
+                                    d (state);
+                                    wasExecuted = true;
+                                }
+                               );
+
+            while (!wasExecuted)
+            {
+                Thread.Sleep (15);
+            }
+        }
+    }
+}

+ 57 - 0
Terminal.Gui/Application/RunState.cs

@@ -0,0 +1,57 @@
+namespace Terminal.Gui;
+
+/// <summary>The execution state for a <see cref="Toplevel"/> view.</summary>
+public class RunState : IDisposable
+{
+    /// <summary>Initializes a new <see cref="RunState"/> class.</summary>
+    /// <param name="view"></param>
+    public RunState (Toplevel view) { Toplevel = view; }
+
+    /// <summary>The <see cref="Toplevel"/> belonging to this <see cref="RunState"/>.</summary>
+    public Toplevel Toplevel { get; internal set; }
+
+    /// <summary>Releases all resource used by the <see cref="RunState"/> object.</summary>
+    /// <remarks>Call <see cref="Dispose()"/> when you are finished using the <see cref="RunState"/>.</remarks>
+    /// <remarks>
+    ///     <see cref="Dispose()"/> method leaves the <see cref="RunState"/> in an unusable state. After calling
+    ///     <see cref="Dispose()"/>, you must release all references to the <see cref="RunState"/> so the garbage collector can
+    ///     reclaim the memory that the <see cref="RunState"/> was occupying.
+    /// </remarks>
+    public void Dispose ()
+    {
+        Dispose (true);
+        GC.SuppressFinalize (this);
+#if DEBUG_IDISPOSABLE
+        WasDisposed = true;
+#endif
+    }
+
+    /// <summary>Releases all resource used by the <see cref="RunState"/> object.</summary>
+    /// <param name="disposing">If set to <see langword="true"/> we are disposing and should dispose held objects.</param>
+    protected virtual void Dispose (bool disposing)
+    {
+        if (Toplevel is { } && disposing)
+        {
+            // Previously we were requiring Toplevel be disposed here.
+            // But that is not correct becaue `Begin` didn't create the TopLevel, `Init` did; thus
+            // disposing should be done by `Shutdown`, not `End`.
+            throw new InvalidOperationException (
+                                                 "Toplevel must be null before calling Application.RunState.Dispose"
+                                                );
+        }
+    }
+
+#if DEBUG_IDISPOSABLE
+    /// <summary>For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly</summary>
+    public bool WasDisposed;
+
+    /// <summary>For debug (see DEBUG_IDISPOSABLE define) purposes to verify objects are being disposed properly</summary>
+    public int DisposedCount = 0;
+
+    /// <summary>For debug (see DEBUG_IDISPOSABLE define) purposes; the runstate instances that have been created</summary>
+    public static List<RunState> Instances = new ();
+
+    /// <summary>Creates a new RunState object.</summary>
+    public RunState () { Instances.Add (this); }
+#endif
+}

+ 12 - 0
Terminal.Gui/Application/RunStateEventArgs.cs

@@ -0,0 +1,12 @@
+namespace Terminal.Gui;
+
+/// <summary>Event arguments for events about <see cref="RunState"/></summary>
+public class RunStateEventArgs : EventArgs
+{
+    /// <summary>Creates a new instance of the <see cref="RunStateEventArgs"/> class</summary>
+    /// <param name="state"></param>
+    public RunStateEventArgs (RunState state) { State = state; }
+
+    /// <summary>The state being reported on by the event</summary>
+    public RunState State { get; }
+}

+ 18 - 0
Terminal.Gui/Application/Timeout.cs

@@ -0,0 +1,18 @@
+//
+// MainLoop.cs: IMainLoopDriver and MainLoop for Terminal.Gui
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+
+namespace Terminal.Gui;
+
+/// <summary>Provides data for timers running manipulation.</summary>
+public sealed class Timeout
+{
+    /// <summary>The function that will be invoked.</summary>
+    public Func<bool> Callback;
+
+    /// <summary>Time to wait before invoke the callback.</summary>
+    public TimeSpan Span;
+}

部分文件因为文件数量过多而无法显示