diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index b2c998fad..7b51e65dc 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -32,7 +32,7 @@ jobs: - name: Setup Pages if: github.ref_name == 'main' || github.ref_name == 'develop' - uses: actions/configure-pages@v4 + uses: actions/configure-pages@v5 - name: Upload artifact if: github.ref_name == 'main' || github.ref_name == 'develop' @@ -49,7 +49,7 @@ jobs: - name: v2_develop Repository Dispatch ${{ github.ref_name }} if: github.ref_name == 'v2_develop' - uses: peter-evans/repository-dispatch@v2 + uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.V2DOCS_TOKEN }} repository: gui-cs/Terminal.GuiV2Docs diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index faf867527..64a37dc0a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: fetch-depth: 0 # fetch-depth is needed for GitVersion - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v0 + uses: gittools/actions/gitversion/setup@v1 with: versionSpec: '5.x' includePrerelease: true @@ -43,7 +43,6 @@ jobs: - name: Build Release run: | dotnet-gitversion /updateprojectfiles - dotnet build ./Analyzers/Terminal.Gui.Analyzers.Internal --no-incremental --nologo --force --configuration Release dotnet build --no-incremental --nologo --force --configuration Release - name: Pack diff --git a/.gitignore b/.gitignore index bbfa8e16e..cca1f4801 100644 --- a/.gitignore +++ b/.gitignore @@ -50,9 +50,9 @@ UnitTests/TestResults TestResults # git merge files -.orig -.theirs -.ours +*.orig +*.theirs +*.ours demo.* diff --git a/Analyzers.slnf b/Analyzers.slnf deleted file mode 100644 index 974c5a965..000000000 --- a/Analyzers.slnf +++ /dev/null @@ -1,10 +0,0 @@ -{ - "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", - ] - } -} \ No newline at end of file diff --git a/Analyzers/Directory.Build.props b/Analyzers/Directory.Build.props deleted file mode 100644 index 6a6ec1589..000000000 --- a/Analyzers/Directory.Build.props +++ /dev/null @@ -1,23 +0,0 @@ - - - enable - latest-recommended - 8 - UTF-8 - true - true - $(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS - True - True - - - - - - - - - - - - \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Program.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Program.cs deleted file mode 100644 index 559424a1b..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Program.cs +++ /dev/null @@ -1,23 +0,0 @@ -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 -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj b/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj deleted file mode 100644 index 3cad5995b..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - Exe - net8.0 - enable - - - - - - - - - - - - - all - Analyzer - true - - - - diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/EnumMemberValues.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/EnumMemberValues.cs deleted file mode 100644 index 0846f8e90..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/EnumMemberValues.cs +++ /dev/null @@ -1,42 +0,0 @@ -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; -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum.cs deleted file mode 100644 index 0fb09b8d9..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with applied. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt.cs deleted file mode 100644 index 535f0448f..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with applied. -/// -[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 -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt_NoFastIsDefined.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt_NoFastIsDefined.cs deleted file mode 100644 index 3b193b54c..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitInt_NoFastIsDefined.cs +++ /dev/null @@ -1,52 +0,0 @@ -// ReSharper disable EnumUnderlyingTypeIsInt -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with = . -/// -[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, -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt.cs deleted file mode 100644 index ca24165ef..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with applied. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt_NoFastIsDefined.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt_NoFastIsDefined.cs deleted file mode 100644 index 01edea7a5..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_ExplicitUInt_NoFastIsDefined.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with = . -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_NoFastIsDefined.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_NoFastIsDefined.cs deleted file mode 100644 index 04f6580ad..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterEnum_NoFastIsDefined.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with = . -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum.cs deleted file mode 100644 index 2e468941c..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with applied. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitInt.cs deleted file mode 100644 index 00b1b9487..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitInt.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// -/// Same as , but with applied. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitUInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitUInt.cs deleted file mode 100644 index 9edb067d8..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithGenerator/BetterFlagsEnum_ExplicitUInt.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Same as , but with applied. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum.cs deleted file mode 100644 index bfb743df6..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Basic enum without explicitly-defined backing type and no attributes on the enum or any of its members. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitInt.cs deleted file mode 100644 index 8a400ab14..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitInt.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Basic enum with explicitly-defined backing type of int and no attributes on the enum or any of its members. -/// -[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), -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitUint.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitUint.cs deleted file mode 100644 index 911e64c9c..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/BasicEnum_ExplicitUint.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Basic enum with explicitly-defined backing type of uint and no attributes on the enum or any of its members. -/// -[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, -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum.cs deleted file mode 100644 index b69fcd057..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Flags enum without explicitly-defined backing type and only a on the enum declaration No other attributes on the enum or its members.. -/// -[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 -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitInt.cs deleted file mode 100644 index a01174e71..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitInt.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Flags enum with explicitly-defined backing type of int and only a on the enum declaration No other attributes on the enum or its members.. -/// -[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 -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitUInt.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitUInt.cs deleted file mode 100644 index 39285e26d..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumDefinitions/WithoutGenerator/FlagsEnum_ExplicitUInt.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions; - -/// -/// Flags enum with explicitly-defined backing type of uint and only a on the enum declaration No other attributes on the enum or its members.. -/// -[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 -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGeneratorTests.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGeneratorTests.cs deleted file mode 100644 index c134ab9fa..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGeneratorTests.cs +++ /dev/null @@ -1,306 +0,0 @@ -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; - - /// All enum types declared in the test assembly. - private static readonly ObservableCollection _allEnumTypes = []; - - /// - /// All enum types without a , - /// - private static readonly HashSet _boringEnumTypes = []; - - /// All extension classes generated for enums with our attribute. - private static readonly ObservableCollection _enumExtensionClasses = []; - - private static readonly ConcurrentDictionary _extendedEnumTypeMappings = []; - private static IEnumerable ExtendedEnumTypes => _extendedEnumTypeMappings.Keys; - - private static readonly ReaderWriterLockSlim _initializationLock = new (); - - private static IEnumerable GetAssemblyExtendedEnumTypeAttributes () => - Assembly.GetExecutingAssembly () - .GetCustomAttributes (); - - private static IEnumerable 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 ()); - } - - [Test] - public void BoringEnum_DoesNotHaveExtensions ([ValueSource (nameof (_boringEnumTypes))] Type enumType) - { - Assume.That (enumType.IsEnum); - - Assert.That (enumType, Has.No.Attribute ()); - } - - [Test] - public void ExtendedEnum_FastIsDefinedFalse_DoesNotHaveFastIsDefined ([ValueSource (nameof (GetExtendedEnumTypes_FastIsDefinedFalse))] EnumData enumData) - { - Assume.That (enumData.EnumType.IsEnum); - Assume.That (enumData.EnumType, Has.Attribute ()); - Assume.That (enumData.GeneratorAttribute, Is.Not.Null); - Assume.That (enumData.GeneratorAttribute, Is.EqualTo (enumData.EnumType.GetCustomAttribute ())); - 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 ()); - Assume.That (enumType, Has.Attribute ()); - } - - [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 ()); - 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 ())); - 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 ()); - extensionClassTypeInfo.GetMethodsWithAttribute (false); - - - } - - private static IEnumerable GetExtendedEnum_EnumData () - { - _initializationLock.EnterUpgradeableReadLock (); - - try - { - if (!_isInitialized) - { - Initialize (); - } - - return _extendedEnumTypeMappings.Values; - } - finally - { - _initializationLock.ExitUpgradeableReadLock (); - } - } - - private static IEnumerable 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 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 ()) - { - if (enumType.GetCustomAttribute () 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 ()) - { - 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; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/GlobalSuppressions.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/GlobalSuppressions.cs deleted file mode 100644 index aba37def0..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/GlobalSuppressions.cs +++ /dev/null @@ -1,3 +0,0 @@ -[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.")] diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/IndentedTextWriterExtensionsTests.cs b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/IndentedTextWriterExtensionsTests.cs deleted file mode 100644 index 250971d58..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/IndentedTextWriterExtensionsTests.cs +++ /dev/null @@ -1,111 +0,0 @@ -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} - - """)); - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj deleted file mode 100644 index e4e88bd61..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj +++ /dev/null @@ -1,48 +0,0 @@ - - - - net8.0 - enable - 12 - false - true - true - portable - $(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS - enable - true - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - all - Analyzer - true - - - - - - - - - - - - diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj.DotSettings b/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj.DotSettings deleted file mode 100644 index cd5ef68b8..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj.DotSettings +++ /dev/null @@ -1,3 +0,0 @@ - - True - True \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/AccessibilityExtensions.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/AccessibilityExtensions.cs deleted file mode 100644 index fb80ebe87..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/AccessibilityExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 - }; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Shipped.md b/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Shipped.md deleted file mode 100644 index 9316c42e0..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Shipped.md +++ /dev/null @@ -1,8 +0,0 @@ -## Release 1.0 - -### New Rules - -Rule ID | Category | Severity | Notes ---------|----------|----------|-------------------- -TG0001 | Usage | Error | TG0001_GlobalNamespaceNotSupported -TG0002 | Usage | Error | TG0002_UnderlyingTypeNotSupported \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Unshipped.md b/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Unshipped.md deleted file mode 100644 index cb4c8a8b9..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/AnalyzerReleases.Unshipped.md +++ /dev/null @@ -1,4 +0,0 @@ -### New Rules - -Rule ID | Category | Severity | Notes ---------|----------|----------|-------------------- diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Analyzers/GenerateEnumExtensionMethodsAttributeAnalyzer.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Analyzers/GenerateEnumExtensionMethodsAttributeAnalyzer.cs deleted file mode 100644 index d49fd37d1..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Analyzers/GenerateEnumExtensionMethodsAttributeAnalyzer.cs +++ /dev/null @@ -1,117 +0,0 @@ -#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; - -/// -/// Design-time analyzer that checks for proper use of . -/// -[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); - - /// - public override ImmutableArray SupportedDiagnostics { get; } = - [ - TG0001_GlobalNamespaceNotSupported, - TG0002_UnderlyingTypeNotSupported - ]; - - /// - 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) - ) - ); - } - } - } - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/ApiCompatExcludedAttributes.txt b/Analyzers/Terminal.Gui.Analyzers.Internal/ApiCompatExcludedAttributes.txt deleted file mode 100644 index 503f1f0bb..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/ApiCompatExcludedAttributes.txt +++ /dev/null @@ -1,3 +0,0 @@ -N:System.Runtime.CompilerServices -N:System.Diagnostics.CodeAnalysis -N:System.Numerics \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs deleted file mode 100644 index da340e075..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable once RedundantNullableDirective -#nullable enable - -namespace Terminal.Gui.Analyzers.Internal.Attributes; - -/// Assembly attribute declaring a known pairing of an type to an extension class. -/// This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported. -[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)] -internal sealed class AssemblyExtendedEnumTypeAttribute : System.Attribute -{ - /// Creates a new instance of from the provided parameters. - /// The of an decorated with a . - /// The of the decorated with an referring to the same type as . - public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass) - { - EnumType = enumType; - ExtensionClass = extensionClass; - } - ///An type that has been extended by Terminal.Gui source generators. - public System.Type EnumType { get; init; } - ///A class containing extension methods for . - public System.Type ExtensionClass { get; init; } - - /// - public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}"; -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/ExtensionsForEnumTypeAttribute.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/ExtensionsForEnumTypeAttribute.cs deleted file mode 100644 index be4b6eef4..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/ExtensionsForEnumTypeAttribute.cs +++ /dev/null @@ -1,37 +0,0 @@ -// ReSharper disable RedundantNameQualifier -// ReSharper disable RedundantNullableDirective -// ReSharper disable UnusedType.Global -#pragma warning disable IDE0001, IDE0240 -#nullable enable - -namespace Terminal.Gui.Analyzers.Internal.Attributes; - -/// -/// Attribute written by the source generator for extension classes, for easier analysis and reflection. -/// -/// -/// Properties are just convenient shortcuts to properties of . -/// -[System.AttributeUsage (System.AttributeTargets.Class | System.AttributeTargets.Interface)] -internal sealed class ExtensionsForEnumTypeAttribute: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, System.Enum -{ - /// - /// The namespace-qualified name of . - /// - public string EnumFullName => EnumType.FullName!; - - /// - /// The unqualified name of . - /// - public string EnumName => EnumType.Name; - - /// - /// The namespace containing . - /// - public string EnumNamespace => EnumType.Namespace!; - - /// - /// The given by (). - /// - public System.Type EnumType => typeof (TEnum); -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumExtensionMethodsAttribute.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumExtensionMethodsAttribute.cs deleted file mode 100644 index 507c45102..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumExtensionMethodsAttribute.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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; - -/// -/// Used to enable source generation of a common set of extension methods for enum types. -/// -[AttributeUsage (AttributeTargets.Enum)] -internal sealed class GenerateEnumExtensionMethodsAttribute : Attribute -{ - /// - /// The name of the generated static class. - /// - /// - /// If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".
- /// No other validation is performed, so illegal values will simply result in compiler errors. - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - ///
- public string? ClassName { get; set; } - - /// - /// The namespace in which to place the generated static class containing the extension methods. - /// - /// - /// If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.
- /// No other validation is performed, so illegal values will simply result in compiler errors. - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - ///
- public string? ClassNamespace { get; set; } - - /// - /// Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in - /// method. - /// - /// - /// - /// Default: false - /// - /// - /// If the enum is not decorated with , this option has no effect. - /// - /// - /// 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. - /// - /// - /// 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. - /// - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - /// - public bool FastHasFlags { get; set; } - - /// - /// Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in - /// method, - /// using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members. - /// - /// - /// - /// Default: true - /// - /// - /// 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. - /// - /// - /// As with the source generator only considers explicitly-named members.
- /// Generation of values which represent valid bitwise combinations of members of enums decorated with - /// is not affected by this property. - ///
- ///
- public bool FastIsDefined { get; init; } = true; - - /// - /// Gets a value indicating if this instance - /// contains default values only. See remarks of this method or documentation on properties of this type for details. - /// - /// - /// A value indicating if all property values are default for this - /// instance. - /// - /// - /// Default values that will result in a return value are:
- /// && ! && - /// && - /// - ///
- public override bool IsDefaultAttribute () - { - return FastIsDefined - && !FastHasFlags - && ClassName is null - && ClassNamespace is null; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/IExtensionsForEnumTypeAttribute.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/IExtensionsForEnumTypeAttribute.cs deleted file mode 100644 index 4ae8875b7..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/IExtensionsForEnumTypeAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -// ReSharper disable All - -using System; - -namespace Terminal.Gui.Analyzers.Internal.Attributes; - -/// -/// Interface to simplify general enumeration of constructed generic types for -/// -/// -internal interface IExtensionsForEnumTypeAttributes -{ - Type EnumType { get; } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IEqualityOperators.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IEqualityOperators.cs deleted file mode 100644 index 63493a738..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IEqualityOperators.cs +++ /dev/null @@ -1,11 +0,0 @@ -// ReSharper disable once CheckNamespace -namespace System.Numerics; -/// -/// Included for compatibility with .net7+, but has no members. -/// Thus it cannot be explicitly used in generator code. -/// Use it for static analysis only. -/// -/// The left operand type. -/// The right operand type. -/// The return type. -internal interface IEqualityOperators; \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IntrinsicAttribute.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IntrinsicAttribute.cs deleted file mode 100644 index 06cd5b3d5..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IntrinsicAttribute.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace System.Runtime.CompilerServices; - -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] -public sealed class IntrinsicAttribute : Attribute -{ -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NumericExtensions.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NumericExtensions.cs deleted file mode 100644 index 8a6df7be9..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NumericExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -// ReSharper disable once CheckNamespace -namespace Terminal.Gui.Analyzers.Internal.Compatibility; - -/// -/// Extension methods for and types. -/// -/// -/// This is mostly just for backward compatibility with netstandard2.0. -/// -public static class NumericExtensions -{ - /// - /// Gets the population count (number of bits set to 1) of this 32-bit value. - /// - /// The value to get the population count of. - /// - /// The algorithm is the well-known SWAR (SIMD Within A Register) method for population count.
- /// 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.
- /// It performs the operation simultaneously on 4 bytes at a time, rather than the naive method of testing all 32 bits - /// individually.
- /// Most compilers can recognize this and turn it into a single platform-specific instruction, when available. - ///
- /// - /// An unsigned 32-bit integer value containing the population count of . - /// - [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; - } - } - - /// - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static uint GetPopCount (this int value) { return GetPopCount (Unsafe.As (ref value)); } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs deleted file mode 100644 index 3ffb234a6..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs +++ /dev/null @@ -1,204 +0,0 @@ -// 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; - -/// String constants for frequently-used boilerplate. -/// These are for performance, instead of using Roslyn to build it all during execution of analyzers. -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"; - - /// - /// Names of dotnet namespaces and types. Included as compile-time constants to avoid unnecessary work for the Roslyn - /// source generators. - /// - /// Implemented as nested static types because XmlDoc doesn't work on namespaces. - internal static class DotnetNames - { - /// Fully-qualified attribute type names. Specific applications (uses) are in . - internal static class Attributes - { - /// - internal const string CompilerGenerated = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (CompilerGeneratedAttribute)}"; - - /// - internal const string DebuggerNonUserCode = $"{Namespaces.System_Diagnostics}.{nameof (DebuggerNonUserCodeAttribute)}"; - - /// - 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)}"; - - /// - /// Use of this attribute should be carefully evaluated. - internal const string MethodImpl = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (MethodImplAttribute)}"; - - /// Attributes formatted for use in code, including square brackets. - internal static class Applications - { - // ReSharper disable MemberHidesStaticFromOuterClass - internal const string Flags = $"[{Attributes.Flags}]"; - - /// - internal const string GeneratedCode = $"""[{Attributes.GeneratedCode}("{InternalAnalyzersNamespace}","1.0")]"""; - - /// - /// Use of this attribute should be carefully evaluated. - internal const string AggressiveInlining = $"[{MethodImpl}({Types.MethodImplOptions}.{nameof (MethodImplOptions.AggressiveInlining)})]"; - - /// - internal const string DebuggerNonUserCode = $"[{Attributes.DebuggerNonUserCode}]"; - - /// - internal const string CompilerGenerated = $"[{Attributes.CompilerGenerated}]"; - - /// - internal const string ExcludeFromCodeCoverage = $"[{Attributes.ExcludeFromCodeCoverage}]"; - - // ReSharper restore MemberHidesStaticFromOuterClass - } - } - - /// Names of dotnet namespaces. - 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 = $""" - //------------------------------------------------------------------------------ - // - // 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. - // - //------------------------------------------------------------------------------ - """; - - /// - /// A set of explicit type aliases to work around Terminal.Gui having name collisions with types like - /// . - /// - internal const string DotnetExplicitTypeAliasUsingDirectives = $""" - using Attribute = {DotnetNames.Types.Attribute}; - using AttributeUsageAttribute = {DotnetNames.Types.AttributeUsageAttribute}; - using GeneratedCode = {DotnetNames.Attributes.GeneratedCode}; - """; - - /// Using directives for common namespaces in generated code. - 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}; - """; - - /// - /// 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. - /// - 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} - """; - - /// - /// 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. - /// - 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} - """; - - /// - /// Preprocessor directive to enable nullability context for generated code.
- /// This should always be emitted, as it applies only to generated code.
- /// As such, generated code MUST be properly annotated. - ///
- internal const string NullableContextDirective = "#nullable enable"; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs deleted file mode 100644 index f35e20d88..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs +++ /dev/null @@ -1,235 +0,0 @@ -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; - -/// -/// The class responsible for turning an -/// into actual C# code. -/// -/// Try to use this type as infrequently as possible. -/// -/// A reference to an 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. -/// -[SuppressMessage ("CodeQuality", "IDE0079", Justification = "Suppressions here are intentional and the warnings they disable are just noise.")] -internal sealed class CodeWriter (in EnumExtensionMethodsGenerationInfo metadata) : IStandardCSharpCodeGenerator -{ - // 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!; - - /// - public EnumExtensionMethodsGenerationInfo Metadata - { - [MethodImpl (MethodImplOptions.AggressiveInlining)] - [return: NotNull] - get; - [param: DisallowNull] - set; - } = metadata; - - /// - public ref readonly SourceText GenerateSourceText (Encoding? encoding = null) - { - encoding ??= Encoding.UTF8; - _sourceText = SourceText.From (GetFullSourceText (), encoding); - - return ref _sourceText; - } - - /// - /// 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. - /// - 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 - }; - - /// Gets the class declaration line. - private string ExtensionClassDeclarationLine => $"public static partial class {Metadata.GeneratedTypeName}"; - - // ReSharper disable once HeapView.ObjectAllocation - /// Gets the XmlDoc for the extension class declaration. - private string ExtensionClassDeclarationXmlDoc => - $"/// Extension methods for the type."; - - // ReSharper disable once HeapView.ObjectAllocation - /// Gets the extension class file-scoped namespace directive. - private string ExtensionClassNamespaceDirective => $"namespace {Metadata.GeneratedTypeNamespace};"; - - /// - /// An attribute to decorate the extension class with for easy mapping back to the target enum type, for reflection and - /// analysis. - /// - private string ExtensionsForTypeAttributeLine => $"[ExtensionsForEnumType<{Metadata.TargetTypeFullName}>]"; - - /// - /// Creates the code for the FastHasFlags method. - /// - /// - /// Since the generator already only writes code for enums backed by and , - /// this method is safe, as we'll always be using a DWORD. - /// - /// An instance of an to write to. - private void GetFastHasFlagsMethods (IndentedTextWriter w) - { - // The version taking the same enum type as the check value. - w.WriteLine ( - $"/// Determines if the specified flags are set in the current value of this ."); - w.WriteLine ("/// NO VALIDATION IS PERFORMED!"); - - w.WriteLine ( - $"/// True, if all flags present in are also present in the current value of the .
Otherwise false.
"); - 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 ( - $"/// Determines if the specified mask bits are set in the current value of this ."); - - w.WriteLine ( - $"/// The value to check against the value."); - w.WriteLine ("/// A mask to apply to the current value."); - - w.WriteLine ( - $"/// True, if all bits set to 1 in the mask are also set to 1 in the current value of the .
Otherwise false.
"); - w.WriteLine ("/// NO VALIDATION IS PERFORMED!"); - 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 (); - } - - /// - /// Creates the code for the FastIsDefined method. - /// - [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 ( - $"/// Determines if the specified value is explicitly defined as a named value of the type."); - - w.WriteLine ( - "/// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are not explicitly named will return false."); - - 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 ( - $"/// Directly converts this value to an value with the same binary representation."); - w.WriteLine ("/// NO VALIDATION IS PERFORMED!"); - 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 ( - $"/// Directly converts this value to a value with the same binary representation."); - w.WriteLine ("/// NO VALIDATION IS PERFORMED!"); - 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 (); - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs deleted file mode 100644 index cab633cbf..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs +++ /dev/null @@ -1,443 +0,0 @@ -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; - -/// -/// 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. -/// -/// -/// Minimal validation is performed by this type.
-/// Errors in analyzed source code will result in generation failure or broken output.
-/// This type is not intended for use outside of Terminal.Gui library development. -///
-internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetadata, - IEqualityOperators -{ - 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; - - /// - /// 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. - /// - /// The fully-qualified namespace of the enum type, without assembly name. - /// - /// The name of the enum type, as would be given by on the enum's type - /// declaration. - /// - /// - /// The fully-qualified namespace in which to place the generated code, without assembly name. If omitted or explicitly - /// null, uses the value provided in . - /// - /// - /// The name of the generated class. If omitted or explicitly null, appends "Extensions" to the value of - /// . - /// - /// The backing type of the enum. Defaults to . - /// - /// Whether to generate a fast HasFlag alternative. (Default: true) Ignored if the enum does not also have - /// . - /// - /// Whether to generate a fast IsDefined alternative. (Default: true) - /// - /// Minimal validation is performed by this type.
- /// Errors in analyzed source code will result in generation failure or broken output.
- /// This type is not intended for use outside of Terminal.Gui library development. - ///
- 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); - - /// The name of the extension class. - public string? GeneratedTypeName - { - get => _generatedTypeName ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix); - set => _generatedTypeName = value ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix); - } - - /// The namespace for the extension class. - /// - /// Value is not validated by the set accessor.
- /// Get accessor will never return null and is thus marked [NotNull] for static analysis, even though the property is - /// declared as a nullable .
If the backing field for this property is null, the get - /// accessor will return instead. - ///
- public string? GeneratedTypeNamespace - { - get => _generatedTypeNamespace ?? TargetTypeNamespace; - set => _generatedTypeNamespace = value ?? TargetTypeNamespace; - } - - /// - public string TargetTypeFullName => string.Concat (TargetTypeNamespace, ".", TargetTypeName); - - /// - public Accessibility Accessibility - { - get; - [UsedImplicitly] - internal set; - } = Accessibility.Public; - - /// - public TypeKind TypeKind => TypeKind.Class; - - /// - public bool IsRecord => false; - - /// - public bool IsClass => true; - - /// - public bool IsStruct => false; - - /// - public bool IsByRefLike => false; - - /// - public bool IsSealed => false; - - /// - public bool IsAbstract => false; - - /// - public bool IsEnum => false; - - /// - public bool IsStatic => true; - - /// - public bool IncludeInterface => false; - - public string GeneratedTypeFullName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}"; - - /// Whether to generate the extension class as partial (Default: true) - public bool IsPartial => true; - - /// The fully-qualified namespace of the source enum type. - public string TargetTypeNamespace - { - get; - [UsedImplicitly] - set; - } - - /// The UNQUALIFIED name of the source enum type. - public string TargetTypeName - { - get; - [UsedImplicitly] - set; - } - - /// - /// The backing type for the enum. - /// - /// For simplicity and formality, only System.Int32 and System.UInt32 are supported at this time. - 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; - } - } - - /// - /// Whether a fast alternative to the built-in Enum.HasFlag method will be generated (Default: false) - /// - public bool GenerateFastHasFlags { [UsedImplicitly] get; set; } - - /// Whether a switch-based IsDefined replacement will be generated (Default: true) - public bool GenerateFastIsDefined { [UsedImplicitly]get; set; } = true; - - internal ImmutableHashSet? _intMembers; - internal ImmutableHashSet? _uIntMembers; - - /// - /// Fully-qualified name of the extension class - /// - internal string FullyQualifiedClassName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}"; - - /// - /// Whether a Flags was found on the enum type. - /// - 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 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 enumMembers = enumSymbol.GetMembers (); - IEnumerable fieldSymbols = enumMembers.OfType (); - _intMembers = fieldSymbols.Select (static m => m.HasConstantValue ? (int)m.ConstantValue : 0).ToImmutableHashSet (); - } - private void PopulateUIntMembersHashSet (INamedTypeSymbol enumSymbol) - { - _uIntMembers = enumSymbol.GetMembers ().OfType ().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 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); - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs deleted file mode 100644 index 7629fd8c2..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs +++ /dev/null @@ -1,452 +0,0 @@ -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; - -/// -/// Incremental code generator for enums decorated with . -/// -[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); - - /// Fully-qualified symbol name format without the "global::" prefix. - private static readonly SymbolDisplayFormat _fullyQualifiedSymbolDisplayFormatWithoutGlobal = - SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle (SymbolDisplayGlobalNamespaceStyle.Omitted); - - /// - /// - /// - /// Basically, this method is called once by the compiler, and is responsible for wiring up - /// everything important about how source generation works. - /// - /// - /// See in-line comments for specifics of what's going on. - /// - /// - /// Note that is everything in the compilation, - /// except for code generated by this generator or generators which have not yet executed.
- /// The methods registered to perform generation get called on-demand by the host (the IDE, - /// compiler, etc), sometimes as often as every single keystroke. - ///
- ///
- 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 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 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 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}}; - - /// - /// Interface to simplify general enumeration of constructed generic types for - /// - /// - {{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}}; - - /// Assembly attribute declaring a known pairing of an type to an extension class. - /// This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported. - {{Strings.Templates.AttributesForGeneratedTypes}} - [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class {{nameof(AssemblyExtendedEnumTypeAttribute)}} : System.Attribute - { - /// Creates a new instance of from the provided parameters. - /// The of an decorated with a . - /// The of the decorated with an referring to the same type as . - public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass) - { - EnumType = enumType; - ExtensionClass = extensionClass; - } - /// An type that has been extended by Terminal.Gui source generators. - public System.Type EnumType { get; init; } - /// A class containing extension methods for . - public System.Type ExtensionClass { get; init; } - /// - public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}"; - } - - """, - Encoding.UTF8)); - - postInitializationContext - .AddSource ( - $"{GeneratorAttributeFullyQualifiedName}.g.cs", - SourceText.From ( - $$""" - {{Strings.Templates.StandardHeader}} - - namespace {{Strings.AnalyzersAttributesNamespace}}; - - /// - /// Used to enable source generation of a common set of extension methods for enum types. - /// - {{Strings.Templates.AttributesForGeneratedTypes}} - [{{Strings.DotnetNames.Types.AttributeUsageAttribute}} ({{Strings.DotnetNames.Types.AttributeTargets}}.Enum)] - public sealed class {{GeneratorAttributeName}} : {{Strings.DotnetNames.Types.Attribute}} - { - /// - /// The name of the generated static class. - /// - /// - /// If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".
- /// No other validation is performed, so illegal values will simply result in compiler errors. - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - ///
- public string? ClassName { get; set; } - - /// - /// The namespace in which to place the generated static class containing the extension methods. - /// - /// - /// If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.
- /// No other validation is performed, so illegal values will simply result in compiler errors. - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - ///
- public string? ClassNamespace { get; set; } - - /// - /// Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in - /// method. - /// - /// - /// - /// Default: false - /// - /// - /// If the enum is not decorated with , this option has no effect. - /// - /// - /// 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. - /// - /// - /// 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. - /// - /// - /// Explicitly specifying a default value is unnecessary and will result in unnecessary processing. - /// - /// - public bool FastHasFlags { get; set; } - - /// - /// Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in - /// method, - /// using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members. - /// - /// - /// - /// Default: true - /// - /// - /// 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. - /// - /// - /// As with the source generator only considers explicitly-named members.
- /// Generation of values which represent valid bitwise combinations of members of enums decorated with - /// is not affected by this property. - ///
- ///
- public bool FastIsDefined { get; init; } = true; - - /// - /// Gets a value indicating if this instance - /// contains default values only. See remarks of this method or documentation on properties of this type for details. - /// - /// - /// A value indicating if all property values are default for this - /// instance. - /// - /// - /// Default values that will result in a return value are:
- /// && ! && - /// && - /// - ///
- 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}}; - - /// - /// Attribute written by the source generator for enum extension classes, for easier analysis and reflection. - /// - /// - /// Properties are just convenient shortcuts to properties of . - /// - {{Strings.Templates.AttributesForGeneratedTypes}} - [System.AttributeUsageAttribute (System.AttributeTargets.Class | System.AttributeTargets.Interface)] - public sealed class {{ExtensionsForEnumTypeAttributeName}}: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, Enum - { - /// - /// The namespace-qualified name of . - /// - public string EnumFullName => EnumType.FullName!; - - /// - /// The unqualified name of . - /// - public string EnumName => EnumType.Name; - - /// - /// The namespace containing . - /// - public string EnumNamespace => EnumType.Namespace!; - - /// - /// The given by (). - /// - 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 ()); - } - - /// - /// Returns true if is an EnumDeclarationSyntax - /// whose parent is a NamespaceDeclarationSyntax, FileScopedNamespaceDeclarationSyntax, or a - /// (Class|Struct)DeclarationSyntax.
- /// Additional filtering is performed in later stages. - ///
- 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 - }; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/GlobalSuppressions.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/GlobalSuppressions.cs deleted file mode 100644 index ce2fa970b..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/GlobalSuppressions.cs +++ /dev/null @@ -1,3 +0,0 @@ -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.")] diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/IGeneratedTypeMetadata.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/IGeneratedTypeMetadata.cs deleted file mode 100644 index c72a8cc44..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/IGeneratedTypeMetadata.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.CodeAnalysis; - -namespace Terminal.Gui.Analyzers.Internal; - -/// -/// Interface for all generators to use for their metadata classes. -/// -/// The type implementing this interface. -internal interface IGeneratedTypeMetadata where TSelf : IGeneratedTypeMetadata -{ - [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; } -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/IStandardCSharpCodeGenerator.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/IStandardCSharpCodeGenerator.cs deleted file mode 100644 index a0e3d584d..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/IStandardCSharpCodeGenerator.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Text; -using JetBrains.Annotations; -using Microsoft.CodeAnalysis.Text; - -namespace Terminal.Gui.Analyzers.Internal; - -internal interface IStandardCSharpCodeGenerator where T : IGeneratedTypeMetadata -{ - /// - /// Generates and returns the full source text corresponding to , - /// in the requested or if not provided. - /// - /// - /// The of the generated source text or if not - /// provided. - /// - /// - [UsedImplicitly] - [SkipLocalsInit] - ref readonly SourceText GenerateSourceText (Encoding? encoding = null); - - /// - /// A type implementing which - /// will be used for source generation. - /// - [UsedImplicitly] - T Metadata { get; set; } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/IndentedTextWriterExtensions.cs b/Analyzers/Terminal.Gui.Analyzers.Internal/IndentedTextWriterExtensions.cs deleted file mode 100644 index 90105d582..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/IndentedTextWriterExtensions.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.CodeDom.Compiler; - -namespace Terminal.Gui.Analyzers.Internal; - -/// -/// Just a simple set of extension methods to increment and decrement the indentation -/// level of an via push and pop terms, and to avoid having -/// explicit values all over the place. -/// -public static class IndentedTextWriterExtensions -{ - /// - /// Decrements by 1, but only if it is greater than 0. - /// - /// - /// The resulting indentation level of the . - /// - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static int Pop (this IndentedTextWriter w, string endScopeDelimiter = "}") - { - if (w.Indent > 0) - { - w.Indent--; - w.WriteLine (endScopeDelimiter); - } - return w.Indent; - } - - /// - /// Decrements by 1 and then writes a closing curly brace. - /// - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static void PopCurly (this IndentedTextWriter w, bool withSemicolon = false) - { - w.Indent--; - - if (withSemicolon) - { - w.WriteLine ("};"); - } - else - { - w.WriteLine ('}'); - } - } - - /// - /// Increments by 1, with optional parameters to customize the scope push. - /// - /// An instance of an . - /// - /// The first line to be written before indenting and before the optional line or - /// null if not needed. - /// - /// - /// An opening delimiter to write. Written before the indentation and after (if provided). Default is an opening curly brace. - /// - /// Calling with no parameters will write an opening curly brace and a line break at the current indentation and then increment. - [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++; - } -} diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Properties/launchSettings.json b/Analyzers/Terminal.Gui.Analyzers.Internal/Properties/launchSettings.json deleted file mode 100644 index 639272733..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "InternalAnalyzers Debug": { - "commandName": "DebugRoslynComponent", - "targetProject": "..\\Terminal.Gui.Analyzers.Internal.Debugging\\Terminal.Gui.Analyzers.Internal.Debugging.csproj" - } - } -} \ No newline at end of file diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj b/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj deleted file mode 100644 index 80d788ac3..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - netstandard2.0 - - - - Library - 12 - Terminal.Gui.Analyzers.Internal - disable - true - true - True - true - true - true - True - true - true - - - - - - - - - - - - - $(NoWarn);nullable;CA1067 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj.DotSettings b/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj.DotSettings deleted file mode 100644 index 6c2c0e27d..000000000 --- a/Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj.DotSettings +++ /dev/null @@ -1,4 +0,0 @@ - - CSharp120 - InternalsOnly - False \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d75e8f486..e92d17f10 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,8 +10,8 @@ We welcome contributions from the community. See [Issues](https://github.com/gui Terminal.Gui uses the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branching model. -* The `main` branch is always stable, and always matches the most recently released Nuget package. -* The `develop` branch is where new development and bug-fixes happen. It is the default branch. +* The `v1_release_` and `v2_release` branches are always stable, and always matches the most recently released Nuget package. +* The `v1__develop` and `v2_develop` branches are where new development and bug-fixes happen. `v2_develop` is the default Github branch. ### Forking Terminal.Gui @@ -33,11 +33,11 @@ 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` (for v1) or `v2_develop` (for v2) branch is up-to-date with `upstream` (`github.com/gui-cs/Terminal.Gui`): +Ensure your local `v1_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 -git pull upstream develop +git checkout v2_develop +git pull upstream v2_develop ``` Create a new local branch: diff --git a/CommunityToolkitExample/CommunityToolkitExample.csproj b/CommunityToolkitExample/CommunityToolkitExample.csproj index fdb41dfcd..8a25e7c31 100644 --- a/CommunityToolkitExample/CommunityToolkitExample.csproj +++ b/CommunityToolkitExample/CommunityToolkitExample.csproj @@ -8,11 +8,8 @@ - - - - - + + diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index e89be9369..000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 79faf752f..000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,5 +0,0 @@ - - - $(DefineConstants);DIMAUTO - - \ No newline at end of file diff --git a/Example/Example.cs b/Example/Example.cs index 630e6560f..13c7b9138 100644 --- a/Example/Example.cs +++ b/Example/Example.cs @@ -6,19 +6,19 @@ using System; using Terminal.Gui; -var app = Application.Run (); - -Console.WriteLine ($"Username: {app.UserNameText.Text}"); - -app.Dispose (); +Application.Run ().Dispose (); // Before the application exits, reset Terminal.Gui for clean shutdown Application.Shutdown (); +// To see this output on the screen it must be done after shutdown, +// which restores the previous screen. +Console.WriteLine ($@"Username: {ExampleWindow.UserName}"); + // Defines a top-level window with border and title public class ExampleWindow : Window { - public TextField UserNameText; + public static string UserName; public ExampleWindow () { @@ -27,7 +27,7 @@ public class ExampleWindow : Window // Create input components and labels var usernameLabel = new Label { Text = "Username:" }; - UserNameText = new TextField + var userNameText = new TextField { // Position text field adjacent to the label X = Pos.Right (usernameLabel) + 1, @@ -46,7 +46,7 @@ public class ExampleWindow : Window Secret = true, // align with the text box above - X = Pos.Left (UserNameText), + X = Pos.Left (userNameText), Y = Pos.Top (passwordLabel), Width = Dim.Fill () }; @@ -64,19 +64,20 @@ public class ExampleWindow : Window // When login button is clicked display a message popup btnLogin.Accept += (s, e) => - { - if (UserNameText.Text == "admin" && passwordText.Text == "password") - { - MessageBox.Query ("Logging In", "Login Successful", "Ok"); - Application.RequestStop (); - } - else - { - MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok"); - } - }; + { + if (userNameText.Text == "admin" && passwordText.Text == "password") + { + MessageBox.Query ("Logging In", "Login Successful", "Ok"); + UserName = userNameText.Text; + Application.RequestStop (); + } + else + { + MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok"); + } + }; // Add the views to the Window - Add (usernameLabel, UserNameText, passwordLabel, passwordText, btnLogin); + Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin); } } diff --git a/FSharpExample/FSharpExample.fsproj b/FSharpExample/FSharpExample.fsproj index 9effec9fd..82b2802e5 100644 --- a/FSharpExample/FSharpExample.fsproj +++ b/FSharpExample/FSharpExample.fsproj @@ -1,7 +1,7 @@  Exe - net6.0 + net8.0 1.6.2.0 1.6.2.0 1.6.2+Branch.main.Sha.b6eeb6321685af474ffc17b1390ff1d4894a90c5 @@ -14,6 +14,6 @@ - + \ No newline at end of file diff --git a/FSharpExample/Program.fs b/FSharpExample/Program.fs index bfeaef2ed..88d801f04 100644 --- a/FSharpExample/Program.fs +++ b/FSharpExample/Program.fs @@ -1,454 +1,48 @@ -open System -open System.Diagnostics -open System.Globalization -open System.IO -open NStack -open Terminal.Gui +open Terminal.Gui -let ustr (x: string) = ustring.Make(x) -let mutable ml2 = Unchecked.defaultof
+ [RequiresUnreferencedCode ("AOT")] internal static void Initialize () { _allConfigProperties = new (); @@ -585,16 +599,20 @@ public static class ConfigurationManager /// Creates a JSON document with the configuration specified. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static string ToJson () { //Debug.WriteLine ("ConfigurationManager.ToJson()"); - return JsonSerializer.Serialize (Settings!, _serializerOptions); + return JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] internal static Stream ToStream () { - string json = JsonSerializer.Serialize (Settings!, _serializerOptions); + string json = JsonSerializer.Serialize (Settings!, typeof (SettingsScope), _serializerContext); // turn it into a stream var stream = new MemoryStream (); diff --git a/Terminal.Gui/Configuration/DictionaryJsonConverter.cs b/Terminal.Gui/Configuration/DictionaryJsonConverter.cs index 29963c56b..bed7f874b 100644 --- a/Terminal.Gui/Configuration/DictionaryJsonConverter.cs +++ b/Terminal.Gui/Configuration/DictionaryJsonConverter.cs @@ -28,8 +28,8 @@ internal class DictionaryJsonConverter : JsonConverter> { string key = reader.GetString (); reader.Read (); - var value = JsonSerializer.Deserialize (ref reader, options); - dictionary.Add (key, value); + var value = JsonSerializer.Deserialize (ref reader, typeof (T), _serializerContext); + dictionary.Add (key, (T)value); } } else if (reader.TokenType == JsonTokenType.EndArray) @@ -51,7 +51,7 @@ internal class DictionaryJsonConverter : JsonConverter> //writer.WriteString (item.Key, item.Key); writer.WritePropertyName (item.Key); - JsonSerializer.Serialize (writer, item.Value, options); + JsonSerializer.Serialize (writer, item.Value, typeof (T), _serializerContext); writer.WriteEndObject (); } diff --git a/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs b/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs index c7b705311..9b24c7d0a 100644 --- a/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs +++ b/Terminal.Gui/Configuration/KeyCodeJsonConverter.cs @@ -42,7 +42,7 @@ internal class KeyCodeJsonConverter : JsonConverter } // The enum uses "D0..D9" for the number keys - if (Enum.TryParse (reader.GetString ().TrimStart ('D', 'd'), false, out key)) + if (Enum.TryParse (reader.GetString ()!.TrimStart ('D', 'd'), false, out key)) { break; } diff --git a/Terminal.Gui/Configuration/ScopeJsonConverter.cs b/Terminal.Gui/Configuration/ScopeJsonConverter.cs index 5419619e2..a23216ea0 100644 --- a/Terminal.Gui/Configuration/ScopeJsonConverter.cs +++ b/Terminal.Gui/Configuration/ScopeJsonConverter.cs @@ -1,5 +1,6 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -11,9 +12,12 @@ namespace Terminal.Gui; /// data to/from JSON documents. /// /// -internal class ScopeJsonConverter : JsonConverter where scopeT : Scope +internal class ScopeJsonConverter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] scopeT> : JsonConverter where scopeT : Scope { + [RequiresDynamicCode ("Calls System.Type.MakeGenericType(params Type[])")] +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public override scopeT Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. { if (reader.TokenType != JsonTokenType.StartObject) { @@ -85,7 +89,7 @@ internal class ScopeJsonConverter : JsonConverter where scopeT : try { scope! [propertyName].PropertyValue = - JsonSerializer.Deserialize (ref reader, propertyType!, options); + JsonSerializer.Deserialize (ref reader, propertyType!, _serializerContext); } catch (Exception ex) { @@ -133,7 +137,7 @@ internal class ScopeJsonConverter : JsonConverter where scopeT : if (property is { }) { PropertyInfo prop = scope.GetType ().GetProperty (propertyName!)!; - prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, options)); + prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, _serializerContext)); } else { @@ -160,7 +164,8 @@ internal class ScopeJsonConverter : JsonConverter where scopeT : foreach (PropertyInfo p in properties) { writer.WritePropertyName (ConfigProperty.GetJsonPropertyName (p)); - JsonSerializer.Serialize (writer, scope.GetType ().GetProperty (p.Name)?.GetValue (scope), options); + object? prop = scope.GetType ().GetProperty (p.Name)?.GetValue (scope); + JsonSerializer.Serialize (writer, prop, prop!.GetType (), _serializerContext); } foreach (KeyValuePair p in from p in scope @@ -205,7 +210,8 @@ internal class ScopeJsonConverter : JsonConverter where scopeT : } else { - JsonSerializer.Serialize (writer, p.Value.PropertyValue, options); + object? prop = p.Value.PropertyValue; + JsonSerializer.Serialize (writer, prop, prop!.GetType (), _serializerContext); } } @@ -221,6 +227,8 @@ internal class ScopeJsonConverter : JsonConverter where scopeT : internal class ReadHelper : ReadHelper { private readonly ReadDelegate _readDelegate; + + [RequiresUnreferencedCode ("Calls System.Delegate.CreateDelegate(Type, Object, String)")] public ReadHelper (object converter) { _readDelegate = (ReadDelegate)Delegate.CreateDelegate (typeof (ReadDelegate), converter, "Read"); } public override object? Read (ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) diff --git a/Terminal.Gui/Configuration/SettingsScope.cs b/Terminal.Gui/Configuration/SettingsScope.cs index 145ad3cdc..8ce37bbbc 100644 --- a/Terminal.Gui/Configuration/SettingsScope.cs +++ b/Terminal.Gui/Configuration/SettingsScope.cs @@ -1,5 +1,6 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -37,12 +38,14 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON string. /// Json document to update the settings with. /// The source (filename/resource name) the Json document was read from. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (Stream stream, string source) { // Update the existing settings with the new settings. try { - Update (JsonSerializer.Deserialize (stream, _serializerOptions)!); + Update ((SettingsScope)JsonSerializer.Deserialize (stream, typeof (SettingsScope), _serializerOptions)!); OnUpdated (); Debug.WriteLine ($"ConfigurationManager: Read configuration from \"{source}\""); if (!Sources.Contains (source)) @@ -67,6 +70,8 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON file. /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (string filePath) { string realPath = filePath.Replace ("~", Environment.GetFolderPath (Environment.SpecialFolder.UserProfile)); @@ -93,6 +98,8 @@ public class SettingsScope : Scope /// Updates the with the settings in a JSON string. /// Json document to update the settings with. /// The source (filename/resource name) the Json document was read from. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? Update (string json, string source) { var stream = new MemoryStream (); @@ -107,6 +114,8 @@ public class SettingsScope : Scope /// Updates the with the settings from a Json resource. /// /// + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] public SettingsScope? UpdateFromResource (Assembly assembly, string resourceName) { if (resourceName is null || string.IsNullOrEmpty (resourceName)) diff --git a/Terminal.Gui/Configuration/SourceGenerationContext.cs b/Terminal.Gui/Configuration/SourceGenerationContext.cs new file mode 100644 index 000000000..ed93b68ca --- /dev/null +++ b/Terminal.Gui/Configuration/SourceGenerationContext.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace Terminal.Gui; + +/// +/// Allow AOT and self-contained single file applications with the +/// +[JsonSerializable (typeof (Attribute))] +[JsonSerializable (typeof (Color))] +[JsonSerializable (typeof (ThemeScope))] +[JsonSerializable (typeof (ColorScheme))] +[JsonSerializable (typeof (SettingsScope))] +[JsonSerializable (typeof (AppScope))] +[JsonSerializable (typeof (Key))] +[JsonSerializable (typeof (GlyphDefinitions))] +[JsonSerializable (typeof (ConfigProperty))] +[JsonSerializable (typeof (ShadowStyle))] +[JsonSerializable (typeof (string))] +[JsonSerializable (typeof (bool))] +[JsonSerializable (typeof (bool?))] +[JsonSerializable (typeof (Dictionary))] +internal partial class SourceGenerationContext : JsonSerializerContext +{ } diff --git a/Terminal.Gui/Configuration/ThemeManager.cs b/Terminal.Gui/Configuration/ThemeManager.cs index 9787daa8d..e6efe32e0 100644 --- a/Terminal.Gui/Configuration/ThemeManager.cs +++ b/Terminal.Gui/Configuration/ThemeManager.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace Terminal.Gui; @@ -64,6 +65,9 @@ public class ThemeManager : IDictionary public string Theme { get => SelectedTheme; + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] set => SelectedTheme = value; } @@ -73,9 +77,14 @@ public class ThemeManager : IDictionary [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)] public static Dictionary? Themes { + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] get => Settings? ["Themes"] ?.PropertyValue as Dictionary; // themes ?? new Dictionary (); + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] set => //if (themes is null || value is null) { @@ -93,6 +102,9 @@ public class ThemeManager : IDictionary internal static string SelectedTheme { get => _theme; + + [RequiresUnreferencedCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] + [RequiresDynamicCode ("Calls Terminal.Gui.ConfigurationManager.Settings")] set { string oldTheme = _theme; @@ -109,6 +121,8 @@ public class ThemeManager : IDictionary /// Event fired he selected theme has changed. application. public event EventHandler? ThemeChanged; + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void GetHardCodedDefaults () { //Debug.WriteLine ("Themes.GetHardCodedDefaults()"); @@ -129,6 +143,8 @@ public class ThemeManager : IDictionary ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme)); } + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] internal static void Reset () { Debug.WriteLine ("Themes.Reset()"); @@ -140,33 +156,130 @@ public class ThemeManager : IDictionary #region IDictionary #pragma warning disable 1591 + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Keys => ((IDictionary)Themes!).Keys; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public ICollection Values => ((IDictionary)Themes!).Values; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public int Count => ((ICollection>)Themes!).Count; + + [UnconditionalSuppressMessage ("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public bool IsReadOnly => ((ICollection>)Themes!).IsReadOnly; public ThemeScope this [string key] { + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. get => ((IDictionary)Themes!) [key]; +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. set => ((IDictionary)Themes!) [key] = value; +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Add (string key, ThemeScope value) { ((IDictionary)Themes!).Add (key, value); } - public bool ContainsKey (string key) { return ((IDictionary)Themes!).ContainsKey (key); } - public bool Remove (string key) { return ((IDictionary)Themes!).Remove (key); } - public bool TryGetValue (string key, out ThemeScope value) { return ((IDictionary)Themes!).TryGetValue (key, out value!); } - public void Add (KeyValuePair item) { ((ICollection>)Themes!).Add (item); } - public void Clear () { ((ICollection>)Themes!).Clear (); } - public bool Contains (KeyValuePair item) { return ((ICollection>)Themes!).Contains (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public bool ContainsKey (string key) { return ((IDictionary)Themes!).ContainsKey (key); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public bool Remove (string key) { return ((IDictionary)Themes!).Remove (key); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public bool TryGetValue (string key, out ThemeScope value) { return ((IDictionary)Themes!).TryGetValue (key, out value!); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public void Add (KeyValuePair item) { ((ICollection>)Themes!).Add (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public void Clear () { ((ICollection>)Themes!).Clear (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + public bool Contains (KeyValuePair item) { return ((ICollection>)Themes!).Contains (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void CopyTo (KeyValuePair [] array, int arrayIndex) +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. { ((ICollection>)Themes!).CopyTo (array, arrayIndex); } + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public bool Remove (KeyValuePair item) { return ((ICollection>)Themes!).Remove (item); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("AOT")] + [RequiresDynamicCode ("AOT")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public IEnumerator> GetEnumerator () { return ((IEnumerable>)Themes!).GetEnumerator (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + [RequiresUnreferencedCode ("Calls Terminal.Gui.ThemeManager.Themes")] + [RequiresDynamicCode ("Calls Terminal.Gui.ThemeManager.Themes")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable)Themes!).GetEnumerator (); } +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. #pragma warning restore 1591 #endregion diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs index 6aef4230f..7400214ec 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs @@ -13,6 +13,7 @@ // limitations under the License. #define GUICS +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Unix.Terminal; @@ -69,6 +70,7 @@ internal class UnmanagedLibrary } } + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] static UnmanagedLibrary () { PlatformID platform = Environment.OSVersion.Platform; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 0dd0e9038..86ef13466 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -3,6 +3,7 @@ // using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping; using static Terminal.Gui.NetEvents; @@ -452,6 +453,7 @@ internal class NetEvents : IDisposable HandleKeyboardEvent (newConsoleKeyInfo); } + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private MouseButtonState MapMouseFlags (MouseFlags mouseFlags) { MouseButtonState mbs = default; @@ -1249,6 +1251,7 @@ internal class NetDriver : ConsoleDriver #region Color Handling // Cache the list of ConsoleColor values. + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private static readonly HashSet ConsoleColorValues = new ( Enum.GetValues (typeof (ConsoleColor)) .OfType () diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 3c9ba9261..89c82dd58 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -116,7 +116,7 @@ internal class WindowsConsole var s = _stringBuilder.ToString (); - result = WriteConsole (_screenBuffer, s, (uint)s.Length, out uint _, null); + result = WriteConsole (_screenBuffer, s, (uint)s.Length, out uint _, nint.Zero); } if (!result) @@ -134,7 +134,7 @@ internal class WindowsConsole public bool WriteANSI (string ansi) { - return WriteConsole (_screenBuffer, ansi, (uint)ansi.Length, out uint _, null); + return WriteConsole (_screenBuffer, ansi, (uint)ansi.Length, out uint _, nint.Zero); } public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window) @@ -804,7 +804,7 @@ internal class WindowsConsole string lpbufer, uint NumberOfCharsToWriten, out uint lpNumberOfCharsWritten, - object lpReserved + nint lpReserved ); [DllImport ("kernel32.dll")] diff --git a/Terminal.Gui/Drawing/Alignment.cs b/Terminal.Gui/Drawing/Alignment.cs index 40061a8c1..6a160096f 100644 --- a/Terminal.Gui/Drawing/Alignment.cs +++ b/Terminal.Gui/Drawing/Alignment.cs @@ -1,12 +1,10 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; /// /// Determines the position of items when arranged in a container. /// -[GenerateEnumExtensionMethods (FastHasFlags = true)] - public enum Alignment { /// diff --git a/Terminal.Gui/Drawing/AlignmentModes.cs b/Terminal.Gui/Drawing/AlignmentModes.cs index 4de4d5c98..b7e0bb87e 100644 --- a/Terminal.Gui/Drawing/AlignmentModes.cs +++ b/Terminal.Gui/Drawing/AlignmentModes.cs @@ -1,4 +1,4 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; @@ -6,7 +6,6 @@ namespace Terminal.Gui; /// Determines alignment modes for . /// [Flags] -[GenerateEnumExtensionMethods (FastHasFlags = true)] public enum AlignmentModes { /// diff --git a/Terminal.Gui/Drawing/FillPair.cs b/Terminal.Gui/Drawing/FillPair.cs new file mode 100644 index 000000000..d0ea12608 --- /dev/null +++ b/Terminal.Gui/Drawing/FillPair.cs @@ -0,0 +1,41 @@ +namespace Terminal.Gui; + +/// +/// Describes a pair of which cooperate in creating +/// . One gives foreground color while other gives background. +/// +public class FillPair +{ + /// + /// Creates a new instance using the provided fills for foreground and background + /// color when assembling . + /// + /// + /// + public FillPair (IFill fore, IFill back) + { + Foreground = fore; + Background = back; + } + + /// + /// The fill which provides point based foreground color. + /// + public IFill Foreground { get; init; } + + /// + /// The fill which provides point based background color. + /// + public IFill Background { get; init; } + + /// + /// Returns the color pair (foreground+background) to use when rendering + /// a rune at the given . + /// + /// + /// + public Attribute GetAttribute (Point point) + { + return new (Foreground.GetColor (point), Background.GetColor (point)); + } +} diff --git a/Terminal.Gui/Drawing/Gradient.cs b/Terminal.Gui/Drawing/Gradient.cs new file mode 100644 index 000000000..3b41e3e49 --- /dev/null +++ b/Terminal.Gui/Drawing/Gradient.cs @@ -0,0 +1,255 @@ +// This code is a C# port from python library Terminal Text Effects https://github.com/ChrisBuilds/terminaltexteffects/ + +namespace Terminal.Gui; + +/// +/// Describes the pattern that a results in e.g. , +/// etc +/// +public enum GradientDirection +{ + /// + /// Color varies along Y axis but is constant on X axis. + /// + Vertical, + + /// + /// Color varies along X axis but is constant on Y axis. + /// + Horizontal, + + /// + /// Color varies by distance from center (i.e. in circular ripples) + /// + Radial, + + /// + /// Color varies by X and Y axis (i.e. a slanted gradient) + /// + Diagonal +} + +/// +/// Describes a of colors that can be combined +/// to make a color gradient. Use +/// to create into gradient fill area maps. +/// +public class Gradient +{ + /// + /// The discrete colors that will make up the . + /// + public List Spectrum { get; } + + private readonly bool _loop; + private readonly List _stops; + private readonly List _steps; + + /// + /// Creates a new instance of the class which hosts a + /// of colors including all and interpolated colors + /// between each corresponding pair. + /// + /// The colors to use in the spectrum (N) + /// + /// The number of colors to generate between each pair (must be N-1 numbers). + /// If only one step is passed then it is assumed to be the same distance for all pairs. + /// + /// True to duplicate the first stop and step so that the gradient repeats itself + /// + public Gradient (IEnumerable stops, IEnumerable steps, bool loop = false) + { + _stops = stops.ToList (); + + if (_stops.Count < 1) + { + throw new ArgumentException ("At least one color stop must be provided."); + } + + _steps = steps.ToList (); + + // If multiple colors and only 1 step assume same distance applies to all steps + if (_stops.Count > 2 && _steps.Count == 1) + { + _steps = Enumerable.Repeat (_steps.Single (), _stops.Count () - 1).ToList (); + } + + if (_steps.Any (step => step < 1)) + { + throw new ArgumentException ("Steps must be greater than 0."); + } + + if (_steps.Count != _stops.Count - 1) + { + throw new ArgumentException ("Number of steps must be N-1"); + } + + _loop = loop; + Spectrum = GenerateGradient (_steps); + } + + /// + /// Returns the color to use at the given part of the spectrum + /// + /// + /// Proportion of the way through the spectrum, must be between + /// 0 and 1 (inclusive). Returns the last color if is + /// . + /// + /// + /// + public Color GetColorAtFraction (double fraction) + { + if (double.IsNaN (fraction)) + { + return Spectrum.Last (); + } + + if (fraction is < 0 or > 1) + { + throw new ArgumentOutOfRangeException (nameof (fraction), @"Fraction must be between 0 and 1."); + } + + var index = (int)(fraction * (Spectrum.Count - 1)); + + return Spectrum [index]; + } + + private List GenerateGradient (IEnumerable steps) + { + List gradient = new (); + + if (_stops.Count == 1) + { + for (var i = 0; i < steps.Sum (); i++) + { + gradient.Add (_stops [0]); + } + + return gradient; + } + + List stopsToUse = _stops.ToList (); + List stepsToUse = _steps.ToList (); + + if (_loop) + { + stopsToUse.Add (_stops [0]); + stepsToUse.Add (_steps.First ()); + } + + var colorPairs = stopsToUse.Zip (stopsToUse.Skip (1), (start, end) => new { start, end }); + List stepsList = stepsToUse; + + foreach ((var colorPair, int thesteps) in colorPairs.Zip (stepsList, (pair, step) => (pair, step))) + { + gradient.AddRange (InterpolateColors (colorPair.start, colorPair.end, thesteps)); + } + + return gradient; + } + + private static IEnumerable InterpolateColors (Color start, Color end, int steps) + { + for (var step = 0; step < steps; step++) + { + double fraction = (double)step / steps; + var r = (int)(start.R + fraction * (end.R - start.R)); + var g = (int)(start.G + fraction * (end.G - start.G)); + var b = (int)(start.B + fraction * (end.B - start.B)); + + yield return new (r, g, b); + } + + yield return end; // Ensure the last color is included + } + + /// + /// + /// Creates a mapping starting at 0,0 and going to and + /// (inclusively) using the supplied . + /// + /// + /// Note that this method is inclusive i.e. passing 1/1 results in 4 mapped coordinates. + /// + /// + /// + /// + /// + /// + public Dictionary BuildCoordinateColorMapping (int maxRow, int maxColumn, GradientDirection direction) + { + Dictionary gradientMapping = new (); + + switch (direction) + { + case GradientDirection.Vertical: + for (var row = 0; row <= maxRow; row++) + { + double fraction = maxRow == 0 ? 1.0 : (double)row / maxRow; + Color color = GetColorAtFraction (fraction); + + for (var col = 0; col <= maxColumn; col++) + { + gradientMapping [new (col, row)] = color; + } + } + + break; + + case GradientDirection.Horizontal: + for (var col = 0; col <= maxColumn; col++) + { + double fraction = maxColumn == 0 ? 1.0 : (double)col / maxColumn; + Color color = GetColorAtFraction (fraction); + + for (var row = 0; row <= maxRow; row++) + { + gradientMapping [new (col, row)] = color; + } + } + + break; + + case GradientDirection.Radial: + for (var row = 0; row <= maxRow; row++) + { + for (var col = 0; col <= maxColumn; col++) + { + double distanceFromCenter = FindNormalizedDistanceFromCenter (maxRow, maxColumn, new (col, row)); + Color color = GetColorAtFraction (distanceFromCenter); + gradientMapping [new (col, row)] = color; + } + } + + break; + + case GradientDirection.Diagonal: + for (var row = 0; row <= maxRow; row++) + { + for (var col = 0; col <= maxColumn; col++) + { + double fraction = ((double)row * 2 + col) / (maxRow * 2 + maxColumn); + Color color = GetColorAtFraction (fraction); + gradientMapping [new (col, row)] = color; + } + } + + break; + } + + return gradientMapping; + } + + private static double FindNormalizedDistanceFromCenter (int maxRow, int maxColumn, Point coord) + { + double centerX = maxColumn / 2.0; + double centerY = maxRow / 2.0; + double dx = coord.X - centerX; + double dy = coord.Y - centerY; + double distance = Math.Sqrt (dx * dx + dy * dy); + double maxDistance = Math.Sqrt (centerX * centerX + centerY * centerY); + + return distance / maxDistance; + } +} diff --git a/Terminal.Gui/Drawing/GradientFill.cs b/Terminal.Gui/Drawing/GradientFill.cs new file mode 100644 index 000000000..6518d2dab --- /dev/null +++ b/Terminal.Gui/Drawing/GradientFill.cs @@ -0,0 +1,42 @@ +namespace Terminal.Gui; + +/// +/// Implementation of that uses a color gradient (including +/// radial, diagonal etc.). +/// +public class GradientFill : IFill +{ + private readonly Dictionary _map; + + /// + /// Creates a new instance of the class that can return + /// color for any point in the given using the provided + /// and . + /// + /// + /// + /// + public GradientFill (Rectangle area, Gradient gradient, GradientDirection direction) + { + _map = gradient.BuildCoordinateColorMapping (area.Height - 1, area.Width - 1, direction) + .ToDictionary ( + kvp => new Point (kvp.Key.X + area.X, kvp.Key.Y + area.Y), + kvp => kvp.Value); + } + + /// + /// Returns the color to use for the given or Black if it + /// lies outside the prepared gradient area (see constructor). + /// + /// + /// + public Color GetColor (Point point) + { + if (_map.TryGetValue (point, out Color color)) + { + return color; + } + + return new (0, 0); // Default to black if point not found + } +} diff --git a/Terminal.Gui/Drawing/IFill.cs b/Terminal.Gui/Drawing/IFill.cs new file mode 100644 index 000000000..7d1d19a68 --- /dev/null +++ b/Terminal.Gui/Drawing/IFill.cs @@ -0,0 +1,14 @@ +namespace Terminal.Gui; + +/// +/// Describes an area fill (e.g. solid color or gradient). +/// +public interface IFill +{ + /// + /// Returns the color that should be used at the given point + /// + /// + /// + Color GetColor (Point point); +} diff --git a/Terminal.Gui/Drawing/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas.cs index b1e0ced13..2bda9e5dd 100644 --- a/Terminal.Gui/Drawing/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas.cs @@ -4,6 +4,13 @@ namespace Terminal.Gui; /// Facilitates box drawing and line intersection detection and rendering. Does not support diagonal lines. public class LineCanvas : IDisposable { + /// + /// Optional which when present overrides the + /// (colors) of lines in the canvas. This can be used e.g. to apply a global + /// across all lines. + /// + public FillPair? Fill { get; set; } + private readonly List _lines = []; private readonly Dictionary _runeResolvers = new () @@ -85,7 +92,7 @@ public class LineCanvas : IDisposable viewport = Rectangle.Union (viewport, _lines [i].Viewport); } - if (viewport is {Width: 0} or {Height: 0}) + if (viewport is { Width: 0 } or { Height: 0 }) { viewport = viewport with { @@ -135,7 +142,7 @@ public class LineCanvas : IDisposable ) { _cachedViewport = Rectangle.Empty; - _lines.Add (new StraightLine (start, length, orientation, style, attribute)); + _lines.Add (new (start, length, orientation, style, attribute)); } /// Adds a new line to the canvas @@ -183,7 +190,7 @@ public class LineCanvas : IDisposable if (cell is { }) { - map.Add (new Point (x, y), cell); + map.Add (new (x, y), cell); } } } @@ -218,7 +225,7 @@ public class LineCanvas : IDisposable if (rune is { }) { - map.Add (new Point (x, y), rune.Value); + map.Add (new (x, y), rune.Value); } } } @@ -324,7 +331,10 @@ public class LineCanvas : IDisposable /// private bool Exactly (HashSet intersects, params IntersectionType [] types) { return intersects.SetEquals (types); } - private Attribute? GetAttributeForIntersects (IntersectionDefinition? [] intersects) { return intersects [0]!.Line.Attribute; } + private Attribute? GetAttributeForIntersects (IntersectionDefinition? [] intersects) + { + return Fill != null ? Fill.GetAttribute (intersects [0]!.Point) : intersects [0]!.Line.Attribute; + } private Cell? GetCellForIntersects (ConsoleDriver driver, IntersectionDefinition? [] intersects) { @@ -428,12 +438,12 @@ public class LineCanvas : IDisposable useThickDotted ? Glyphs.VLineHvDa4 : Glyphs.VLine; default: - throw new Exception ( - "Could not find resolver or switch case for " - + nameof (runeType) - + ":" - + runeType - ); + throw new ( + "Could not find resolver or switch case for " + + nameof (runeType) + + ":" + + runeType + ); } } @@ -843,4 +853,4 @@ public class LineCanvas : IDisposable _normal = Glyphs.URCorner; } } -} \ No newline at end of file +} diff --git a/Terminal.Gui/Drawing/SolidFill.cs b/Terminal.Gui/Drawing/SolidFill.cs new file mode 100644 index 000000000..2619f67ea --- /dev/null +++ b/Terminal.Gui/Drawing/SolidFill.cs @@ -0,0 +1,24 @@ +namespace Terminal.Gui; + +/// +/// implementation that uses a solid color for all points +/// +public class SolidFill : IFill +{ + private readonly Color _color; + + /// + /// Creates a new instance of the class which will return + /// the provided regardless of which point is requested. + /// + /// + public SolidFill (Color color) { _color = color; } + + /// + /// Returns the color this instance was constructed with regardless of + /// which is being colored. + /// + /// + /// + public Color GetColor (Point point) { return _color; } +} diff --git a/Terminal.Gui/Drawing/StraightLine.cs b/Terminal.Gui/Drawing/StraightLine.cs index 9a2785f0f..2f36995df 100644 --- a/Terminal.Gui/Drawing/StraightLine.cs +++ b/Terminal.Gui/Drawing/StraightLine.cs @@ -45,6 +45,7 @@ public class StraightLine /// Gets the rectangle that describes the bounds of the canvas. Location is the coordinates of the line that is /// furthest left/top and Size is defined by the line that extends the furthest right/bottom. /// + // PERF: Probably better to store the rectangle rather than make a new one on every single access to Viewport. internal Rectangle Viewport { @@ -111,26 +112,28 @@ public class StraightLine return null; } + var p = new Point (x, y); + if (StartsAt (x, y)) { - return new IntersectionDefinition ( - Start, - GetTypeByLength ( - IntersectionType.StartLeft, - IntersectionType.PassOverHorizontal, - IntersectionType.StartRight - ), - this - ); + return new ( + p, + GetTypeByLength ( + IntersectionType.StartLeft, + IntersectionType.PassOverHorizontal, + IntersectionType.StartRight + ), + this + ); } if (EndsAt (x, y)) { - return new IntersectionDefinition ( - Start, - Length < 0 ? IntersectionType.StartRight : IntersectionType.StartLeft, - this - ); + return new ( + p, + Length < 0 ? IntersectionType.StartRight : IntersectionType.StartLeft, + this + ); } int xmin = Math.Min (Start.X, Start.X + Length); @@ -138,11 +141,11 @@ public class StraightLine if (xmin < x && xmax > x) { - return new IntersectionDefinition ( - new Point (x, y), - IntersectionType.PassOverHorizontal, - this - ); + return new ( + p, + IntersectionType.PassOverHorizontal, + this + ); } return null; @@ -155,26 +158,28 @@ public class StraightLine return null; } + var p = new Point (x, y); + if (StartsAt (x, y)) { - return new IntersectionDefinition ( - Start, - GetTypeByLength ( - IntersectionType.StartUp, - IntersectionType.PassOverVertical, - IntersectionType.StartDown - ), - this - ); + return new ( + p, + GetTypeByLength ( + IntersectionType.StartUp, + IntersectionType.PassOverVertical, + IntersectionType.StartDown + ), + this + ); } if (EndsAt (x, y)) { - return new IntersectionDefinition ( - Start, - Length < 0 ? IntersectionType.StartDown : IntersectionType.StartUp, - this - ); + return new ( + p, + Length < 0 ? IntersectionType.StartDown : IntersectionType.StartUp, + this + ); } int ymin = Math.Min (Start.Y, Start.Y + Length); @@ -182,11 +187,11 @@ public class StraightLine if (ymin < y && ymax > y) { - return new IntersectionDefinition ( - new Point (x, y), - IntersectionType.PassOverVertical, - this - ); + return new ( + p, + IntersectionType.PassOverVertical, + this + ); } return null; diff --git a/Terminal.Gui/EnumExtensions/AddOrSubtractExtensions.cs b/Terminal.Gui/EnumExtensions/AddOrSubtractExtensions.cs new file mode 100644 index 000000000..8fb98d81c --- /dev/null +++ b/Terminal.Gui/EnumExtensions/AddOrSubtractExtensions.cs @@ -0,0 +1,51 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class AddOrSubtractExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this AddOrSubtract e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this AddOrSubtract e) => Unsafe.As (ref e); + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this AddOrSubtract _, int value) + { + return value switch + { + 0 => true, + 1 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/AlignmentExtensions.cs b/Terminal.Gui/EnumExtensions/AlignmentExtensions.cs new file mode 100644 index 000000000..3666d2de5 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/AlignmentExtensions.cs @@ -0,0 +1,53 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class AlignmentExtensions +{ + /// + /// Directly converts this value to an value with the same + /// binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this Alignment e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the same + /// binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this Alignment e) => Unsafe.As (ref e); + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this Alignment _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + 3 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/AlignmentModesExtensions.cs b/Terminal.Gui/EnumExtensions/AlignmentModesExtensions.cs new file mode 100644 index 000000000..3babe81b6 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/AlignmentModesExtensions.cs @@ -0,0 +1,90 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class AlignmentModesExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this AlignmentModes e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this AlignmentModes e) => Unsafe.As (ref e); + + /// + /// Determines if the specified flags are set in the current value of this + /// . + /// + /// NO VALIDATION IS PERFORMED! + /// + /// True, if all flags present in are also present in the current value of the + /// .
Otherwise false. + ///
+ [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this AlignmentModes e, AlignmentModes checkFlags) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); + + return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; + } + + /// + /// Determines if the specified mask bits are set in the current value of this + /// . + /// + /// The value to check against the value. + /// A mask to apply to the current value. + /// + /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the + /// .
Otherwise false. + ///
+ /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this AlignmentModes e, int mask) + { + ref int enumCurrentValueRef = ref Unsafe.As (ref e); + + return (enumCurrentValueRef & mask) == mask; + } + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this AlignmentModes _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + 4 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/BorderSettingsExtensions.cs b/Terminal.Gui/EnumExtensions/BorderSettingsExtensions.cs new file mode 100644 index 000000000..074a45976 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/BorderSettingsExtensions.cs @@ -0,0 +1,89 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class BorderSettingsExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this BorderSettings e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this BorderSettings e) => Unsafe.As (ref e); + + /// + /// Determines if the specified flags are set in the current value of this + /// . + /// + /// NO VALIDATION IS PERFORMED! + /// + /// True, if all flags present in are also present in the current value of the + /// .
Otherwise false. + ///
+ [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this BorderSettings e, BorderSettings checkFlags) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); + + return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; + } + + /// + /// Determines if the specified mask bits are set in the current value of this + /// . + /// + /// The value to check against the value. + /// A mask to apply to the current value. + /// + /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the + /// .
Otherwise false. + ///
+ /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this BorderSettings e, int mask) + { + ref int enumCurrentValueRef = ref Unsafe.As (ref e); + + return (enumCurrentValueRef & mask) == mask; + } + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this BorderSettings _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/DimAutoStyleExtensions.cs b/Terminal.Gui/EnumExtensions/DimAutoStyleExtensions.cs new file mode 100644 index 000000000..6c0813df8 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/DimAutoStyleExtensions.cs @@ -0,0 +1,89 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class DimAutoStyleExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this DimAutoStyle e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this DimAutoStyle e) => Unsafe.As (ref e); + + /// + /// Determines if the specified flags are set in the current value of this + /// . + /// + /// NO VALIDATION IS PERFORMED! + /// + /// True, if all flags present in are also present in the current value of the + /// .
Otherwise false. + ///
+ [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this DimAutoStyle e, DimAutoStyle checkFlags) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); + + return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; + } + + /// + /// Determines if the specified mask bits are set in the current value of this + /// . + /// + /// The value to check against the value. + /// A mask to apply to the current value. + /// + /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the + /// .
Otherwise false. + ///
+ /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this DimAutoStyle e, int mask) + { + ref int enumCurrentValueRef = ref Unsafe.As (ref e); + + return (enumCurrentValueRef & mask) == mask; + } + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this DimAutoStyle _, int value) + { + return value switch + { + 1 => true, + 2 => true, + 3 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/DimPercentModeExtensions.cs b/Terminal.Gui/EnumExtensions/DimPercentModeExtensions.cs new file mode 100644 index 000000000..2fc943f17 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/DimPercentModeExtensions.cs @@ -0,0 +1,51 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class DimPercentModeExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this DimPercentMode e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this DimPercentMode e) => Unsafe.As (ref e); + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this DimPercentMode _, int value) + { + return value switch + { + 0 => true, + 1 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/DimensionExtensions.cs b/Terminal.Gui/EnumExtensions/DimensionExtensions.cs new file mode 100644 index 000000000..ccbfbf5ed --- /dev/null +++ b/Terminal.Gui/EnumExtensions/DimensionExtensions.cs @@ -0,0 +1,51 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +public static class DimensionExtensions +{ + /// + /// Directly converts this value to an value with the same + /// binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this Dimension e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the same + /// binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this Dimension e) => Unsafe.As (ref e); + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this Dimension _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs b/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs new file mode 100644 index 000000000..6f42f4c82 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs @@ -0,0 +1,93 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class KeyBindingScopeExtensions +{ + /// + /// Directly converts this value to an value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this KeyBindingScope e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the + /// same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this KeyBindingScope e) => Unsafe.As (ref e); + + /// + /// Determines if the specified flags are set in the current value of this + /// . + /// + /// NO VALIDATION IS PERFORMED! + /// + /// True, if all flags present in are also present in the current value of the + /// .
Otherwise false. + ///
+ [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this KeyBindingScope e, KeyBindingScope checkFlags) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); + + return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; + } + + /// + /// Determines if the specified mask bits are set in the current value of this + /// . + /// + /// + /// The value to check against the + /// value. + /// + /// A mask to apply to the current value. + /// + /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the + /// .
Otherwise false. + ///
+ /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this KeyBindingScope e, int mask) + { + ref int enumCurrentValueRef = ref Unsafe.As (ref e); + + return (enumCurrentValueRef & mask) == mask; + } + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this KeyBindingScope _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + 4 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/SideExtensions.cs b/Terminal.Gui/EnumExtensions/SideExtensions.cs new file mode 100644 index 000000000..b50e12bdc --- /dev/null +++ b/Terminal.Gui/EnumExtensions/SideExtensions.cs @@ -0,0 +1,53 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class SideExtensions +{ + /// + /// Directly converts this value to an value with the same binary + /// representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this Side e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with the same binary + /// representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this Side e) => Unsafe.As (ref e); + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this Side _, int value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + 3 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/EnumExtensions/ViewDiagnosticFlagsExtensions.cs b/Terminal.Gui/EnumExtensions/ViewDiagnosticFlagsExtensions.cs new file mode 100644 index 000000000..1aa18fe72 --- /dev/null +++ b/Terminal.Gui/EnumExtensions/ViewDiagnosticFlagsExtensions.cs @@ -0,0 +1,93 @@ +#nullable enable + +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Terminal.Gui.EnumExtensions; + +/// Extension methods for the type. +[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] +[CompilerGenerated] +[DebuggerNonUserCode] +[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] +[PublicAPI] +public static class ViewDiagnosticFlagsExtensions +{ + /// + /// Directly converts this value to an value with + /// the same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static int AsInt32 (this ViewDiagnosticFlags e) => Unsafe.As (ref e); + + /// + /// Directly converts this value to a value with + /// the same binary representation. + /// + /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static uint AsUInt32 (this ViewDiagnosticFlags e) => Unsafe.As (ref e); + + /// + /// Determines if the specified flags are set in the current value of this + /// . + /// + /// NO VALIDATION IS PERFORMED! + /// + /// True, if all flags present in are also present in the current value of the + /// .
Otherwise false. + ///
+ [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this ViewDiagnosticFlags e, ViewDiagnosticFlags checkFlags) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); + + return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; + } + + /// + /// Determines if the specified mask bits are set in the current value of this + /// . + /// + /// + /// The value to check against the + /// value. + /// + /// A mask to apply to the current value. + /// + /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the + /// .
Otherwise false. + ///
+ /// NO VALIDATION IS PERFORMED! + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public static bool FastHasFlags (this ViewDiagnosticFlags e, uint mask) + { + ref uint enumCurrentValueRef = ref Unsafe.As (ref e); + + return (enumCurrentValueRef & mask) == mask; + } + + /// + /// Determines if the specified value is explicitly defined as a named value of the + /// type. + /// + /// + /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are + /// not explicitly named will return false. + /// + public static bool FastIsDefined (this ViewDiagnosticFlags _, uint value) + { + return value switch + { + 0 => true, + 1 => true, + 2 => true, + 4 => true, + _ => false + }; + } +} diff --git a/Terminal.Gui/FileServices/FileDialogStyle.cs b/Terminal.Gui/FileServices/FileDialogStyle.cs index 83adb448c..9cc6557f1 100644 --- a/Terminal.Gui/FileServices/FileDialogStyle.cs +++ b/Terminal.Gui/FileServices/FileDialogStyle.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO.Abstractions; using Terminal.Gui.Resources; using static System.Environment; @@ -143,6 +144,7 @@ public class FileDialogStyle /// public string WrongFileTypeFeedback { get; set; } = Strings.fdWrongFileTypeFeedback; + [UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] private Dictionary DefaultTreeRootGetter () { Dictionary roots = new (); diff --git a/Terminal.Gui/Input/KeyBindingScope.cs b/Terminal.Gui/Input/KeyBindingScope.cs index 3b6c53ebc..0c75299c7 100644 --- a/Terminal.Gui/Input/KeyBindingScope.cs +++ b/Terminal.Gui/Input/KeyBindingScope.cs @@ -1,4 +1,4 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; @@ -10,7 +10,7 @@ namespace Terminal.Gui; /// Key bindings are scoped to the most-focused view () by default. /// [Flags] -[GenerateEnumExtensionMethods (FastHasFlags = true)] + public enum KeyBindingScope { /// The key binding is disabled. diff --git a/Terminal.Gui/README.md b/Terminal.Gui/README.md index fb380d4c0..5c22df0ac 100644 --- a/Terminal.Gui/README.md +++ b/Terminal.Gui/README.md @@ -6,9 +6,7 @@ All files required to build the **Terminal.Gui** library (and NuGet package). - `\` - The root folder contains the source code for the library. - `Terminal.Gui.sln` - The Visual Studio solution - - `Application.cs` - A `static` class that provides the base 'application driver'. Given it defines a **Terminal.Gui** application it is both logically and literally (because `static`) a singleton. It has direct dependencies on `MainLoop`, `Events.cs` `NetDriver`, `CursesDriver`, `WindowsDriver`, `Responder`, `View`, and `TopLevel` (and nothing else). - - `MainLoop.cs` - Defines `IMainLoopDriver` and implements the `MainLoop` class. - - A few supporting class files + - `Application\` - The core `Application` logic, including `Application.cs`, which is is a `static` class that provides the base 'application engine', `RunState`, and `MainLoop`. - `ConsoleDrivers\` - `ConsoleDriver.cs` - Definition for the Console Driver API. @@ -38,7 +36,7 @@ All files required to build the **Terminal.Gui** library (and NuGet package). - `Dialog` - - etc... -- `Types/` - A folder (not namespace) containing implementations of `Point`, `Rect`, and `Size` which are ancient versions of the modern `System.Drawing.Point`, `System.Drawing.Size`, and `System.Drawning.Rectangle`. +- `FileServcies/` - File services classes. ## Version numbers diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 1959d51d3..4feaf3ae5 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -1,4 +1,4 @@ - + @@ -19,16 +19,19 @@ - net8.0 + net8.0 12 $(AssemblyName) true true portable - $(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS + $(DefineConstants);CONTRACTS_FULL;CODE_ANALYSIS enable true true + false + true + true true @@ -49,21 +52,16 @@ - - - - - + + + + + - - - - - - all - Analyzer - false - + + + + @@ -73,6 +71,7 @@ + diff --git a/Terminal.Gui/View/Adornment/Border.cs b/Terminal.Gui/View/Adornment/Border.cs index 39d98f635..2931cd9ad 100644 --- a/Terminal.Gui/View/Adornment/Border.cs +++ b/Terminal.Gui/View/Adornment/Border.cs @@ -78,7 +78,7 @@ public class Border : Adornment if ((Parent?.Arrangement & ViewArrangement.Movable) != 0) { HighlightStyle |= HighlightStyle.Hover; - } + } #endif base.BeginInit (); @@ -149,31 +149,32 @@ public class Border : Adornment } } - Rectangle GetBorderRectangle (Rectangle screenRect) + private Rectangle GetBorderRectangle (Rectangle screenRect) { return new ( - screenRect.X + Math.Max (0, Thickness.Left - 1), - screenRect.Y + Math.Max (0, Thickness.Top - 1), - Math.Max ( - 0, - screenRect.Width - - Math.Max ( - 0, - Math.Max (0, Thickness.Left - 1) - + Math.Max (0, Thickness.Right - 1) - ) - ), - Math.Max ( - 0, - screenRect.Height - - Math.Max ( - 0, - Math.Max (0, Thickness.Top - 1) - + Math.Max (0, Thickness.Bottom - 1) - ) - ) - ); + screenRect.X + Math.Max (0, Thickness.Left - 1), + screenRect.Y + Math.Max (0, Thickness.Top - 1), + Math.Max ( + 0, + screenRect.Width + - Math.Max ( + 0, + Math.Max (0, Thickness.Left - 1) + + Math.Max (0, Thickness.Right - 1) + ) + ), + Math.Max ( + 0, + screenRect.Height + - Math.Max ( + 0, + Math.Max (0, Thickness.Top - 1) + + Math.Max (0, Thickness.Bottom - 1) + ) + ) + ); } + /// /// Sets the style of the border by changing the . This is a helper API for setting the /// to (1,1,1,1) and setting the line style of the views that comprise the border. If @@ -196,21 +197,22 @@ public class Border : Adornment set => _lineStyle = value; } - private bool _showTitle = true; + private BorderSettings _settings = BorderSettings.Title; /// - /// Gets or sets whether the title should be shown. The default is . + /// Gets or sets the settings for the border. /// - public bool ShowTitle + public BorderSettings Settings { - get => _showTitle; + get => _settings; set { - if (value == _showTitle) + if (value == _settings) { return; } - _showTitle = value; + + _settings = value; Parent?.SetNeedsDisplay (); } @@ -225,6 +227,7 @@ public class Border : Adornment if (!Parent.Arrangement.HasFlag (ViewArrangement.Movable)) { e.Cancel = true; + return; } @@ -235,9 +238,9 @@ public class Border : Adornment _savedForeColor = ColorScheme.Normal.Foreground; } - ColorScheme cs = new ColorScheme (ColorScheme) + var cs = new ColorScheme (ColorScheme) { - Normal = new Attribute (ColorScheme.Normal.Foreground.GetHighlightColor (), ColorScheme.Normal.Background) + Normal = new (ColorScheme.Normal.Foreground.GetHighlightColor (), ColorScheme.Normal.Background) }; ColorScheme = cs; } @@ -254,12 +257,13 @@ public class Border : Adornment if (e.NewValue == HighlightStyle.None && _savedForeColor.HasValue) { - ColorScheme cs = new ColorScheme (ColorScheme) + var cs = new ColorScheme (ColorScheme) { - Normal = new Attribute (_savedForeColor.Value, ColorScheme.Normal.Background) + Normal = new (_savedForeColor.Value, ColorScheme.Normal.Background) }; ColorScheme = cs; } + Parent?.SetNeedsDisplay (); e.Cancel = true; } @@ -267,7 +271,7 @@ public class Border : Adornment private Point? _dragPosition; private Point _startGrabPoint; - /// + /// protected internal override bool OnMouseEvent (MouseEvent mouseEvent) { if (base.OnMouseEvent (mouseEvent)) @@ -322,16 +326,17 @@ public class Border : Adornment _dragPosition = mouseEvent.Position; - Point parentLoc = Parent.SuperView?.ScreenToViewport (new (mouseEvent.ScreenPosition.X, mouseEvent.ScreenPosition.Y)) ?? mouseEvent.ScreenPosition; + Point parentLoc = Parent.SuperView?.ScreenToViewport (new (mouseEvent.ScreenPosition.X, mouseEvent.ScreenPosition.Y)) + ?? mouseEvent.ScreenPosition; GetLocationEnsuringFullVisibility ( - Parent, - parentLoc.X - _startGrabPoint.X, - parentLoc.Y - _startGrabPoint.Y, - out int nx, - out int ny, - out _ - ); + Parent, + parentLoc.X - _startGrabPoint.X, + parentLoc.Y - _startGrabPoint.Y, + out int nx, + out int ny, + out _ + ); Parent.X = nx; Parent.Y = ny; @@ -352,7 +357,6 @@ public class Border : Adornment return false; } - /// protected override void Dispose (bool disposing) { @@ -403,7 +407,7 @@ public class Border : Adornment // ...thickness extends outward (border/title is always as far in as possible) // PERF: How about a call to Rectangle.Offset? - var borderBounds = GetBorderRectangle (screenBounds); + Rectangle borderBounds = GetBorderRectangle (screenBounds); int topTitleLineY = borderBounds.Y; int titleY = borderBounds.Y; var titleBarsLength = 0; // the little vertical thingies @@ -421,7 +425,7 @@ public class Border : Adornment int sideLineLength = borderBounds.Height; bool canDrawBorder = borderBounds is { Width: > 0, Height: > 0 }; - if (ShowTitle) + if (Settings.FastHasFlags (BorderSettings.Title)) { if (Thickness.Top == 2) { @@ -453,9 +457,10 @@ public class Border : Adornment } } - if (canDrawBorder && Thickness.Top > 0 && maxTitleWidth > 0 && ShowTitle && !string.IsNullOrEmpty (Parent?.Title)) + if (canDrawBorder && Thickness.Top > 0 && maxTitleWidth > 0 && Settings.FastHasFlags (BorderSettings.Title) && !string.IsNullOrEmpty (Parent?.Title)) { - var focus = Parent.GetNormalColor (); + Attribute focus = Parent.GetNormalColor (); + if (Parent.SuperView is { } && Parent.SuperView?.Subviews!.Count (s => s.CanFocus) > 1) { // Only use focus color if there are multiple focusable views @@ -492,7 +497,7 @@ public class Border : Adornment { // ╔╡Title╞═════╗ // ╔╡╞═════╗ - if (borderBounds.Width < 4 || !ShowTitle || string.IsNullOrEmpty (Parent?.Title)) + if (borderBounds.Width < 4 || !Settings.FastHasFlags (BorderSettings.Title) || string.IsNullOrEmpty (Parent?.Title)) { // ╔╡╞╗ should be ╔══╗ lc.AddLine ( @@ -631,7 +636,7 @@ public class Border : Adornment Driver.SetAttribute (prevAttr); // TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler - if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.Ruler)) + if (Diagnostics.HasFlag (ViewDiagnosticFlags.Ruler)) { // Top var hruler = new Ruler { Length = screenBounds.Width, Orientation = Orientation.Horizontal }; @@ -642,7 +647,7 @@ public class Border : Adornment } // Redraw title - if (drawTop && maxTitleWidth > 0 && ShowTitle) + if (drawTop && maxTitleWidth > 0 && Settings.FastHasFlags (BorderSettings.Title)) { Parent.TitleTextFormatter.Draw ( new (borderBounds.X + 2, titleY, maxTitleWidth, 1), @@ -670,6 +675,45 @@ public class Border : Adornment vruler.Draw (new (screenBounds.X + screenBounds.Width - 1, screenBounds.Y + 1), 1); } } + + // TODO: This should not be done on each draw? + if (Settings.FastHasFlags (BorderSettings.Gradient)) + { + SetupGradientLineCanvas (lc, screenBounds); + } + else + { + lc.Fill = null; + } } } + + private void SetupGradientLineCanvas (LineCanvas lc, Rectangle rect) + { + GetAppealingGradientColors (out List stops, out List steps); + + var g = new Gradient (stops, steps); + + var fore = new GradientFill (rect, g, GradientDirection.Diagonal); + var back = new SolidFill (GetNormalColor ().Background); + + lc.Fill = new (fore, back); + } + + private static void GetAppealingGradientColors (out List stops, out List steps) + { + // Define the colors of the gradient stops with more appealing colors + stops = new() + { + new (0, 128, 255), // Bright Blue + new (0, 255, 128), // Bright Green + new (255, 255), // Bright Yellow + new (255, 128), // Bright Orange + new (255, 0, 128) // Bright Pink + }; + + // Define the number of steps between each color for smoother transitions + // If we pass only a single value then it will assume equal steps between all pairs + steps = new() { 15 }; + } } diff --git a/Terminal.Gui/View/Adornment/BorderSettings.cs b/Terminal.Gui/View/Adornment/BorderSettings.cs new file mode 100644 index 000000000..7b4846d34 --- /dev/null +++ b/Terminal.Gui/View/Adornment/BorderSettings.cs @@ -0,0 +1,26 @@ + + +namespace Terminal.Gui; + +/// +/// Determines the settings for . +/// +[Flags] + +public enum BorderSettings +{ + /// + /// No settings. + /// + None = 0, + + /// + /// Show the title. + /// + Title = 1, + + /// + /// Use to draw the border. + /// + Gradient = 2, +} diff --git a/Terminal.Gui/View/Adornment/Margin.cs b/Terminal.Gui/View/Adornment/Margin.cs index 2e1ea5760..046965e32 100644 --- a/Terminal.Gui/View/Adornment/Margin.cs +++ b/Terminal.Gui/View/Adornment/Margin.cs @@ -223,7 +223,7 @@ public class Margin : Adornment if (ShadowStyle != ShadowStyle.None && _rightShadow is { } && _bottomShadow is { }) { _rightShadow.Y = Parent.Border.Thickness.Top > 0 - ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.ShowTitle ? 1 : 0) + ? Parent.Border.Thickness.Top - (Parent.Border.Thickness.Top > 2 && Parent.Border.Settings.FastHasFlags (BorderSettings.Title) ? 1 : 0) : 1; _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? Parent.Border.Thickness.Left : 1; } diff --git a/Terminal.Gui/View/Layout/AddOrSubtract.cs b/Terminal.Gui/View/Layout/AddOrSubtract.cs index e03cfbcfd..83d1dd12c 100644 --- a/Terminal.Gui/View/Layout/AddOrSubtract.cs +++ b/Terminal.Gui/View/Layout/AddOrSubtract.cs @@ -1,11 +1,8 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; - -namespace Terminal.Gui; +namespace Terminal.Gui; /// /// Describes whether an operation should add or subtract values. /// -[GenerateEnumExtensionMethods] public enum AddOrSubtract { /// diff --git a/Terminal.Gui/View/Layout/DimAutoStyle.cs b/Terminal.Gui/View/Layout/DimAutoStyle.cs index f350e8045..ee712f0fb 100644 --- a/Terminal.Gui/View/Layout/DimAutoStyle.cs +++ b/Terminal.Gui/View/Layout/DimAutoStyle.cs @@ -1,4 +1,4 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; @@ -6,7 +6,7 @@ namespace Terminal.Gui; /// Specifies how will compute the dimension. /// [Flags] -[GenerateEnumExtensionMethods (FastHasFlags = true)] + public enum DimAutoStyle { /// diff --git a/Terminal.Gui/View/Layout/DimPercentMode.cs b/Terminal.Gui/View/Layout/DimPercentMode.cs index 60a7da056..10077848b 100644 --- a/Terminal.Gui/View/Layout/DimPercentMode.cs +++ b/Terminal.Gui/View/Layout/DimPercentMode.cs @@ -1,12 +1,10 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; /// /// Indicates the mode for a object. /// -[GenerateEnumExtensionMethods] - public enum DimPercentMode { /// diff --git a/Terminal.Gui/View/Layout/Dimension.cs b/Terminal.Gui/View/Layout/Dimension.cs index cc56ffd4b..8cfb3f7f0 100644 --- a/Terminal.Gui/View/Layout/Dimension.cs +++ b/Terminal.Gui/View/Layout/Dimension.cs @@ -1,12 +1,10 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; /// /// Indicates the dimension for operations. /// - -[GenerateEnumExtensionMethods] public enum Dimension { /// diff --git a/Terminal.Gui/View/Layout/Side.cs b/Terminal.Gui/View/Layout/Side.cs index 6708904da..afdc5640e 100644 --- a/Terminal.Gui/View/Layout/Side.cs +++ b/Terminal.Gui/View/Layout/Side.cs @@ -1,4 +1,4 @@ -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; @@ -6,7 +6,6 @@ namespace Terminal.Gui; /// Indicates the side for operations. /// /// -[GenerateEnumExtensionMethods] public enum Side { /// diff --git a/Terminal.Gui/View/ViewDiagnostics.cs b/Terminal.Gui/View/ViewDiagnostics.cs index 20899cfd0..c7ac7b851 100644 --- a/Terminal.Gui/View/ViewDiagnostics.cs +++ b/Terminal.Gui/View/ViewDiagnostics.cs @@ -1,11 +1,10 @@  -using Terminal.Gui.Analyzers.Internal.Attributes; + namespace Terminal.Gui; /// Enables diagnostic functions for . [Flags] -[GenerateEnumExtensionMethods(FastHasFlags = true)] public enum ViewDiagnosticFlags : uint { /// All diagnostics off diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index f6acd3338..81d70ba9f 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -39,7 +39,7 @@ public class Button : View, IDesignable /// Gets or sets whether s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; diff --git a/Terminal.Gui/Views/Dialog.cs b/Terminal.Gui/Views/Dialog.cs index 7e6d82ffd..bcdca4fa8 100644 --- a/Terminal.Gui/Views/Dialog.cs +++ b/Terminal.Gui/Views/Dialog.cs @@ -19,13 +19,13 @@ public class Dialog : Window /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static Alignment DefaultButtonAlignment { get; set; } = Alignment.End; /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static AlignmentModes DefaultButtonAlignmentModes { get; set; } = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems; /// @@ -47,7 +47,7 @@ public class Dialog : Window /// Gets or sets whether all s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public new static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; /// @@ -56,7 +56,7 @@ public class Dialog : Window /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single; private readonly List [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single; /// diff --git a/Terminal.Gui/Views/Shortcut.cs b/Terminal.Gui/Views/Shortcut.cs index 802631d52..7ddbe7c5a 100644 --- a/Terminal.Gui/Views/Shortcut.cs +++ b/Terminal.Gui/Views/Shortcut.cs @@ -104,7 +104,7 @@ public class Shortcut : View void OnInitialized (object sender, EventArgs e) { SuperViewRendersLineCanvas = true; - Border.ShowTitle = false; + Border.Settings &= ~BorderSettings.Title; ShowHide (); diff --git a/Terminal.Gui/Views/Window.cs b/Terminal.Gui/Views/Window.cs index 1b1cea2fc..1a4caa266 100644 --- a/Terminal.Gui/Views/Window.cs +++ b/Terminal.Gui/Views/Window.cs @@ -73,6 +73,6 @@ public class Window : Toplevel /// s. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] + [JsonConverter (typeof (JsonStringEnumConverter))] public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single; } diff --git a/Terminal.sln b/Terminal.sln index a63762780..550bbe4ed 100644 --- a/Terminal.sln +++ b/Terminal.sln @@ -14,14 +14,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example. EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E143FB1F-0B88-48CB-9086-72CDCECFCD22}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal", "Analyzers\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj", "{5DE91722-8765-4E2B-97E4-2A18010B5CED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal.Tests", "Analyzers\Terminal.Gui.Analyzers.Internal.Tests\Terminal.Gui.Analyzers.Internal.Tests.csproj", "{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal.Debugging", "Analyzers\Terminal.Gui.Analyzers.Internal.Debugging\Terminal.Gui.Analyzers.Internal.Debugging.csproj", "{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommunityToolkitExample", "CommunityToolkitExample\CommunityToolkitExample.csproj", "{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Settings", "Settings", "{B8F48EE8-34A6-43B7-B00E-CD91CDD93962}" @@ -51,6 +43,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C7A51224-5 README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelfContained", "SelfContained\SelfContained.csproj", "{524DEA78-7E7C-474D-B42D-52ED4C04FF14}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,14 +55,6 @@ Global {00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.Build.0 = Release|Any CPU - {5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.Build.0 = Release|Any CPU - {715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.Build.0 = Release|Any CPU {88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU {88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -85,22 +71,19 @@ Global {B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.Build.0 = Release|Any CPU - {C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.Build.0 = Release|Any CPU {58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Debug|Any CPU.Build.0 = Debug|Any CPU {58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.ActiveCfg = Release|Any CPU {58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.Build.0 = Release|Any CPU + {524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {524DEA78-7E7C-474D-B42D-52ED4C04FF14}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {5DE91722-8765-4E2B-97E4-2A18010B5CED} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D} - {715DB4BA-F989-4DF6-B46F-5ED26A32B2DD} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D} - {C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D} {B8F48EE8-34A6-43B7-B00E-CD91CDD93962} = {E143FB1F-0B88-48CB-9086-72CDCECFCD22} {13BB2C46-B324-4B9C-92EB-CE6184D4736E} = {E143FB1F-0B88-48CB-9086-72CDCECFCD22} {C7A51224-5E0F-4986-AB37-A6BF89966C12} = {E143FB1F-0B88-48CB-9086-72CDCECFCD22} diff --git a/UICatalog/Scenario.cs b/UICatalog/Scenario.cs index c5a724ba7..f9ecf029a 100644 --- a/UICatalog/Scenario.cs +++ b/UICatalog/Scenario.cs @@ -93,6 +93,10 @@ public class Scenario : IDisposable /// public string GetName () { return ScenarioMetadata.GetName (GetType ()); } + /// Helper to get the and the Name (defined in ) + /// + public string GetQuitKeyAndName () { return $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"; } + /// /// Returns a list of all instanaces defined in the project, sorted by /// . @@ -132,90 +136,12 @@ public class Scenario : IDisposable /// public virtual void Main () { - Init (); - Setup (); - Run (); } - /// - /// Helper that calls and creates the default - /// implementation with a frame and label - /// showing the name of the and logic to exit back to the Scenario picker UI. Override - /// to provide any behavior needed. - /// - /// - /// - /// The base implementation calls and creates a for - /// and adds it to . - /// - /// - /// Overrides that do not call the base., must call before - /// creating any views or calling other Terminal.Gui APIs. - /// - /// - [ObsoleteAttribute ("This method is obsolete and will be removed in v2. Use Main instead.", false)] - public virtual void Init () - { - Application.Init (); - - ConfigurationManager.Themes.Theme = Theme; - ConfigurationManager.Apply (); - - Top = new (); - - Win = new () - { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", - X = 0, - Y = 0, - Width = Dim.Fill (), - Height = Dim.Fill (), - ColorScheme = Colors.ColorSchemes [TopLevelColorScheme] - }; - Top.Add (Win); - } - - /// - /// Runs the . Override to start the using a - /// different than `Top`. - /// - /// - /// Overrides that do not call the base., must call before - /// returning. - /// - [ObsoleteAttribute ("This method is obsolete and will be removed in v2. Use Main instead.", false)] - public virtual void Run () - { - // Must explicitly call Application.Shutdown method to shutdown. - Application.Run (Top); - Top.Dispose (); - Application.Shutdown (); - } - - /// Override this to implement the setup logic (create controls, etc...). - /// This is typically the best place to put scenario logic code. - [ObsoleteAttribute ("This method is obsolete and will be removed in v2. Use Main instead.", false)] - public virtual void Setup () { } - - /// - /// The Toplevel for the . This should be set to . - /// - - //[ObsoleteAttribute ("This property is obsolete and will be removed in v2. Use Main instead.", false)] - public Toplevel Top { get; set; } - /// Gets the Scenario Name + Description with the Description padded based on the longest known Scenario name. /// public override string ToString () { return $"{GetName ().PadRight (_maxScenarioNameLen)}{GetDescription ()}"; } - /// - /// The Window for the . This should be set to in - /// most cases. - /// - - //[ObsoleteAttribute ("This property is obsolete and will be removed in v2. Use Main instead.", false)] - public Window Win { get; set; } - #region IDispose public void Dispose () @@ -231,8 +157,6 @@ public class Scenario : IDisposable { if (disposing) { - Top?.Dispose (); - Win?.Dispose (); } _disposedValue = true; diff --git a/UICatalog/Scenarios/ASCIICustomButton.cs b/UICatalog/Scenarios/ASCIICustomButton.cs index 59e8924f0..8d25f9470 100644 --- a/UICatalog/Scenarios/ASCIICustomButton.cs +++ b/UICatalog/Scenarios/ASCIICustomButton.cs @@ -149,7 +149,7 @@ public class ASCIICustomButtonTest : Scenario public ScrollViewTestWindow () { - Title = "ScrollViewTestWindow"; + Title = $"{Application.QuitKey} to Quit - Scenario: ScrollViewTestWindow"; Label titleLabel = null; diff --git a/UICatalog/Scenarios/Adornments.cs b/UICatalog/Scenarios/Adornments.cs index 8e19ecaaa..43d12a9a9 100644 --- a/UICatalog/Scenarios/Adornments.cs +++ b/UICatalog/Scenarios/Adornments.cs @@ -13,7 +13,7 @@ public class Adornments : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; var editor = new AdornmentsEditor diff --git a/UICatalog/Scenarios/AllViewsTester.cs b/UICatalog/Scenarios/AllViewsTester.cs index 5e0b8d45d..cc440b820 100644 --- a/UICatalog/Scenarios/AllViewsTester.cs +++ b/UICatalog/Scenarios/AllViewsTester.cs @@ -53,7 +53,7 @@ public class AllViewsTester : Scenario var app = new Window { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), ColorScheme = Colors.ColorSchemes ["TopLevel"] }; diff --git a/UICatalog/Scenarios/Animation.cs b/UICatalog/Scenarios/AnimationScenario.cs similarity index 98% rename from UICatalog/Scenarios/Animation.cs rename to UICatalog/Scenarios/AnimationScenario.cs index 42ad540c1..08add3f0a 100644 --- a/UICatalog/Scenarios/Animation.cs +++ b/UICatalog/Scenarios/AnimationScenario.cs @@ -13,7 +13,7 @@ namespace UICatalog.Scenarios; [ScenarioMetadata ("Animation", "Demonstration of how to render animated images with threading.")] [ScenarioCategory ("Threading")] [ScenarioCategory ("Drawing")] -public class Animation : Scenario +public class AnimationScenario : Scenario { private bool _isDisposed; @@ -23,7 +23,7 @@ public class Animation : Scenario var win = new Window { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), X = 0, Y = 0, Width = Dim.Fill (), diff --git a/UICatalog/Scenarios/Bars.cs b/UICatalog/Scenarios/Bars.cs index 995e55ceb..c2027d8ec 100644 --- a/UICatalog/Scenarios/Bars.cs +++ b/UICatalog/Scenarios/Bars.cs @@ -28,7 +28,7 @@ public class Bars : Scenario // QuitKey and it only sticks if changed after init private void App_Loaded (object sender, EventArgs e) { - Application.Top.Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"; + Application.Top.Title = GetQuitKeyAndName (); ObservableCollection eventSource = new (); ListView eventLog = new ListView () diff --git a/UICatalog/Scenarios/BasicColors.cs b/UICatalog/Scenarios/BasicColors.cs index b45cbec3c..0fc284621 100644 --- a/UICatalog/Scenarios/BasicColors.cs +++ b/UICatalog/Scenarios/BasicColors.cs @@ -14,7 +14,7 @@ public class BasicColors : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), }; var vx = 30; diff --git a/UICatalog/Scenarios/BorderEditor.cs b/UICatalog/Scenarios/BorderEditor.cs index a5ccae212..5e0a6e77a 100644 --- a/UICatalog/Scenarios/BorderEditor.cs +++ b/UICatalog/Scenarios/BorderEditor.cs @@ -9,29 +9,30 @@ public class BorderEditor : AdornmentEditor { private CheckBox _ckbTitle; private RadioGroup _rbBorderStyle; + private CheckBox _ckbGradient; public BorderEditor () { Title = "_Border"; Initialized += BorderEditor_Initialized; AdornmentChanged += BorderEditor_AdornmentChanged; - } private void BorderEditor_AdornmentChanged (object sender, EventArgs e) { - _ckbTitle.State = ((Border)AdornmentToEdit).ShowTitle ? CheckState.Checked : CheckState.UnChecked; + _ckbTitle.State = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Title) ? CheckState.Checked : CheckState.UnChecked; _rbBorderStyle.SelectedItem = (int)((Border)AdornmentToEdit).LineStyle; + _ckbGradient.State = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Gradient) ? CheckState.Checked : CheckState.UnChecked; } private void BorderEditor_Initialized (object sender, EventArgs e) { - List borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast ().ToList (); - _rbBorderStyle = new RadioGroup + _rbBorderStyle = new() { X = 0, + // BUGBUG: Hack until dimauto is working properly Y = Pos.Bottom (Subviews [^1]), Width = Dim.Width (Subviews [^2]) + Dim.Width (Subviews [^1]) - 1, @@ -46,21 +47,34 @@ public class BorderEditor : AdornmentEditor _rbBorderStyle.SelectedItemChanged += OnRbBorderStyleOnSelectedItemChanged; - _ckbTitle = new CheckBox + _ckbTitle = new() { X = 0, Y = Pos.Bottom (_rbBorderStyle), State = CheckState.Checked, SuperViewRendersLineCanvas = true, - Text = "Show Title", + Text = "Title", Enabled = AdornmentToEdit is { } }; - _ckbTitle.Toggle += OnCkbTitleOnToggle; Add (_ckbTitle); + _ckbGradient = new () + { + X = 0, + Y = Pos.Bottom (_ckbTitle), + + State = CheckState.Checked, + SuperViewRendersLineCanvas = true, + Text = "Gradient", + Enabled = AdornmentToEdit is { } + }; + + _ckbGradient.Toggle += OnCkbGradientOnToggle; + Add (_ckbGradient); + return; void OnRbBorderStyleOnSelectedItemChanged (object s, SelectedItemChangedArgs e) @@ -81,6 +95,32 @@ public class BorderEditor : AdornmentEditor LayoutSubviews (); } - void OnCkbTitleOnToggle (object sender, CancelEventArgs args) { ((Border)AdornmentToEdit).ShowTitle = args.NewValue == CheckState.Checked; } + void OnCkbTitleOnToggle (object sender, CancelEventArgs args) + { + if (args.NewValue == CheckState.Checked) + + { + ((Border)AdornmentToEdit).Settings |= BorderSettings.Title; + } + else + + { + ((Border)AdornmentToEdit).Settings &= ~BorderSettings.Title; + } + } + + void OnCkbGradientOnToggle (object sender, CancelEventArgs args) + { + if (args.NewValue == CheckState.Checked) + + { + ((Border)AdornmentToEdit).Settings |= BorderSettings.Gradient; + } + else + + { + ((Border)AdornmentToEdit).Settings &= ~BorderSettings.Gradient; + } + } } -} \ No newline at end of file +} diff --git a/UICatalog/Scenarios/Buttons.cs b/UICatalog/Scenarios/Buttons.cs index d719c9a45..aab815a96 100644 --- a/UICatalog/Scenarios/Buttons.cs +++ b/UICatalog/Scenarios/Buttons.cs @@ -18,7 +18,7 @@ public class Buttons : Scenario Window main = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; // Add a label & text field so we can demo IsDefault diff --git a/UICatalog/Scenarios/ChineseUI.cs b/UICatalog/Scenarios/ChineseUI.cs index 96c2ea56e..059b6143c 100644 --- a/UICatalog/Scenarios/ChineseUI.cs +++ b/UICatalog/Scenarios/ChineseUI.cs @@ -12,7 +12,7 @@ public class ChineseUI : Scenario var win = new Window { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), X = 0, Y = 0, Width = Dim.Fill (), diff --git a/UICatalog/Scenarios/ClassExplorer.cs b/UICatalog/Scenarios/ClassExplorer.cs index 7cc3537f2..204ef01b5 100644 --- a/UICatalog/Scenarios/ClassExplorer.cs +++ b/UICatalog/Scenarios/ClassExplorer.cs @@ -17,11 +17,15 @@ public class ClassExplorer : Scenario private TextView _textView; private TreeView _treeView; - public override void Setup () + public override void Main () { - Win.Title = GetName (); - Win.Y = 1; // menu - Win.Height = Dim.Fill (1); // status bar + Application.Init (); + var top = new Toplevel (); + + var win = new Window + { + Title = GetName () + }; var menu = new MenuBar { @@ -55,15 +59,15 @@ public class ClassExplorer : Scenario ) ] }; - Top.Add (menu); + top.Add (menu); _treeView = new TreeView { X = 0, Y = 1, Width = Dim.Percent (50), Height = Dim.Fill () }; var lblSearch = new Label { Text = "Search" }; var tfSearch = new TextField { Width = 20, X = Pos.Right (lblSearch) }; - Win.Add (lblSearch); - Win.Add (tfSearch); + win.Add (lblSearch); + win.Add (tfSearch); TreeViewTextFilter filter = new (_treeView); _treeView.Filter = filter; @@ -83,11 +87,17 @@ public class ClassExplorer : Scenario _treeView.TreeBuilder = new DelegateTreeBuilder (ChildGetter, CanExpand); _treeView.SelectionChanged += TreeView_SelectionChanged; - Win.Add (_treeView); + win.Add (_treeView); _textView = new TextView { X = Pos.Right (_treeView), Y = 0, Width = Dim.Fill (), Height = Dim.Fill () }; - Win.Add (_textView); + win.Add (_textView); + + top.Add (win); + + Application.Run (top); + top.Dispose (); + Application.Shutdown (); } private bool CanExpand (object arg) { return arg is Assembly || arg is Type || arg is ShowForType; } diff --git a/UICatalog/Scenarios/Clipping.cs b/UICatalog/Scenarios/Clipping.cs index 94cfc4751..58953f4da 100644 --- a/UICatalog/Scenarios/Clipping.cs +++ b/UICatalog/Scenarios/Clipping.cs @@ -8,24 +8,16 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Scrolling")] public class Clipping : Scenario { - public override void Init () + public override void Main () { Application.Init (); - Top = new (); - Top.ColorScheme = Colors.ColorSchemes ["Base"]; - } + var win = new Window { Title = GetQuitKeyAndName () }; - public override void Setup () - { - //Win.X = 1; - //Win.Y = 2; - //Win.Width = Dim.Fill () - 4; - //Win.Height = Dim.Fill () - 2; var label = new Label { X = 0, Y = 0, Text = "ScrollView (new Rectangle (3, 3, 50, 20)) with a 200, 100 GetContentSize ()..." }; - Top.Add (label); + win.Add (label); var scrollView = new ScrollView { X = 3, Y = 3, Width = 50, Height = 20 }; scrollView.ColorScheme = Colors.ColorSchemes ["Menu"]; @@ -84,6 +76,10 @@ public class Clipping : Scenario scrollView.Add (embedded1); - Top.Add (scrollView); + win.Add (scrollView); + + Application.Run (win); + win.Dispose (); + Application.Shutdown (); } } diff --git a/UICatalog/Scenarios/CollectionNavigatorTester.cs b/UICatalog/Scenarios/CollectionNavigatorTester.cs index abdb2c3e1..0ae7a7628 100644 --- a/UICatalog/Scenarios/CollectionNavigatorTester.cs +++ b/UICatalog/Scenarios/CollectionNavigatorTester.cs @@ -74,19 +74,16 @@ public class CollectionNavigatorTester : Scenario "quitter" }.ToList ()); + private Toplevel top; private ListView _listView; private TreeView _treeView; // Don't create a Window, just return the top-level view - public override void Init () + public override void Main () { Application.Init (); - Top = new (); - Top.ColorScheme = Colors.ColorSchemes ["Base"]; - } + top = new Toplevel { ColorScheme = Colors.ColorSchemes ["Base"] }; - public override void Setup () - { var allowMarking = new MenuItem ("Allow _Marking", "", null) { CheckType = MenuItemCheckStyle.Checked, Checked = false @@ -128,14 +125,18 @@ public class CollectionNavigatorTester : Scenario ] }; - Top.Add (menu); + top.Add (menu); _items = new (_items.OrderBy (i => i, StringComparer.OrdinalIgnoreCase)); CreateListView (); var vsep = new LineView (Orientation.Vertical) { X = Pos.Right (_listView), Y = 1, Height = Dim.Fill () }; - Top.Add (vsep); + top.Add (vsep); CreateTreeView (); + + Application.Run (top); + top.Dispose (); + Application.Shutdown (); } private void CreateListView () @@ -149,7 +150,7 @@ public class CollectionNavigatorTester : Scenario Width = Dim.Percent (50), Height = 1 }; - Top.Add (label); + top.Add (label); _listView = new ListView { @@ -160,7 +161,7 @@ public class CollectionNavigatorTester : Scenario AllowsMarking = false, AllowsMultipleSelection = false }; - Top.Add (_listView); + top.Add (_listView); _listView.SetSource (_items); @@ -178,14 +179,14 @@ public class CollectionNavigatorTester : Scenario Width = Dim.Percent (50), Height = 1 }; - Top.Add (label); + top.Add (label); _treeView = new TreeView { X = Pos.Right (_listView) + 1, Y = Pos.Bottom (label), Width = Dim.Fill (), Height = Dim.Fill () }; _treeView.Style.HighlightModelTextOnly = true; - Top.Add (_treeView); + top.Add (_treeView); var root = new TreeNode ("IsLetterOrDigit examples"); diff --git a/UICatalog/Scenarios/ColorPicker.cs b/UICatalog/Scenarios/ColorPicker.cs index 9a76085c1..ae70a8a0d 100644 --- a/UICatalog/Scenarios/ColorPicker.cs +++ b/UICatalog/Scenarios/ColorPicker.cs @@ -30,7 +30,7 @@ public class ColorPickers : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), }; // Foreground ColorPicker. diff --git a/UICatalog/Scenarios/CombiningMarks.cs b/UICatalog/Scenarios/CombiningMarks.cs index a6ee788da..b61ebb09f 100644 --- a/UICatalog/Scenarios/CombiningMarks.cs +++ b/UICatalog/Scenarios/CombiningMarks.cs @@ -6,33 +6,33 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Text and Formatting")] public class CombiningMarks : Scenario { - public override void Init () + public override void Main () { Application.Init (); - ConfigurationManager.Themes.Theme = Theme; + ConfigurationManager.Themes!.Theme = Theme; ConfigurationManager.Apply (); - Top = new (); - Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]; - } + var top = new Toplevel { ColorScheme = Colors.ColorSchemes [TopLevelColorScheme] }; - public override void Setup () - { - Top.DrawContentComplete += (s, e) => - { - Application.Driver.Move (0, 0); - Application.Driver.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); - Application.Driver.Move (0, 2); - Application.Driver.AddStr ("\u0301\u0301\u0328<- \"\\u301\\u301\\u328]\" using AddStr."); - Application.Driver.Move (0, 3); - Application.Driver.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u301\\u301\\u328]\" using AddStr."); - Application.Driver.Move (0, 4); - Application.Driver.AddRune ('['); - Application.Driver.AddRune ('a'); - Application.Driver.AddRune ('\u0301'); - Application.Driver.AddRune ('\u0301'); - Application.Driver.AddRune ('\u0328'); - Application.Driver.AddRune (']'); - Application.Driver.AddStr ("<- \"[a\\u301\\u301\\u328]\" using AddRune for each."); - }; + top.DrawContentComplete += (s, e) => + { + Application.Driver.Move (0, 0); + Application.Driver.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); + Application.Driver.Move (0, 2); + Application.Driver.AddStr ("\u0301\u0301\u0328<- \"\\u301\\u301\\u328]\" using AddStr."); + Application.Driver.Move (0, 3); + Application.Driver.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u301\\u301\\u328]\" using AddStr."); + Application.Driver.Move (0, 4); + Application.Driver.AddRune ('['); + Application.Driver.AddRune ('a'); + Application.Driver.AddRune ('\u0301'); + Application.Driver.AddRune ('\u0301'); + Application.Driver.AddRune ('\u0328'); + Application.Driver.AddRune (']'); + Application.Driver.AddStr ("<- \"[a\\u301\\u301\\u328]\" using AddRune for each."); + }; + + Application.Run (top); + top.Dispose (); + Application.Shutdown (); } } diff --git a/UICatalog/Scenarios/ComboBoxIteration.cs b/UICatalog/Scenarios/ComboBoxIteration.cs index 1d0cf9742..75d339681 100644 --- a/UICatalog/Scenarios/ComboBoxIteration.cs +++ b/UICatalog/Scenarios/ComboBoxIteration.cs @@ -9,18 +9,20 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("ComboBox")] public class ComboBoxIteration : Scenario { - public override void Setup () + public override void Main () { + Application.Init (); ObservableCollection items = ["one", "two", "three"]; + var win = new Window { Title = GetQuitKeyAndName () }; var lbListView = new Label { Width = 10, Height = 1 }; - Win.Add (lbListView); + win.Add (lbListView); var listview = new ListView { Y = Pos.Bottom (lbListView) + 1, Width = 10, Height = Dim.Fill (2), Source = new ListWrapper (items) }; - Win.Add (listview); + win.Add (listview); var lbComboBox = new Label { @@ -53,8 +55,8 @@ public class ComboBoxIteration : Scenario listview.SelectedItem = text.Item; } }; - Win.Add (lbComboBox, comboBox); - Win.Add (new TextField { X = Pos.Right (listview) + 1, Y = Pos.Top (comboBox) + 3, Height = 1, Width = 20 }); + win.Add (lbComboBox, comboBox); + win.Add (new TextField { X = Pos.Right (listview) + 1, Y = Pos.Top (comboBox) + 3, Height = 1, Width = 20 }); var btnTwo = new Button { X = Pos.Right (comboBox) + 1, Text = "Two" }; @@ -65,7 +67,7 @@ public class ComboBoxIteration : Scenario listview.SetSource (items); listview.SelectedItem = 0; }; - Win.Add (btnTwo); + win.Add (btnTwo); var btnThree = new Button { X = Pos.Right (comboBox) + 1, Y = Pos.Top (comboBox), Text = "Three" }; @@ -76,6 +78,10 @@ public class ComboBoxIteration : Scenario listview.SetSource (items); listview.SelectedItem = 0; }; - Win.Add (btnThree); + win.Add (btnThree); + + Application.Run (win); + win.Dispose (); + Application.Shutdown (); } } diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs index dd5e4c376..cf0564126 100644 --- a/UICatalog/Scenarios/ComputedLayout.cs +++ b/UICatalog/Scenarios/ComputedLayout.cs @@ -20,7 +20,7 @@ public class ComputedLayout : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), }; // Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width diff --git a/UICatalog/Scenarios/ContentScrolling.cs b/UICatalog/Scenarios/ContentScrolling.cs index 5c7a09826..5d4a1a3c2 100644 --- a/UICatalog/Scenarios/ContentScrolling.cs +++ b/UICatalog/Scenarios/ContentScrolling.cs @@ -104,7 +104,7 @@ public class ContentScrolling : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), // Use a different colorscheme so ViewSettings.ClearContentOnly is obvious ColorScheme = Colors.ColorSchemes ["Toplevel"] diff --git a/UICatalog/Scenarios/ContextMenus.cs b/UICatalog/Scenarios/ContextMenus.cs index 5ca442ee1..4e3b4dc34 100644 --- a/UICatalog/Scenarios/ContextMenus.cs +++ b/UICatalog/Scenarios/ContextMenus.cs @@ -25,7 +25,7 @@ public class ContextMenus : Scenario // Setup - Create a top-level application window and configure it. Window appWindow = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; var text = "Context Menu"; diff --git a/UICatalog/Scenarios/DatePickers.cs b/UICatalog/Scenarios/DatePickers.cs index 1790c7dbc..0028b80ca 100644 --- a/UICatalog/Scenarios/DatePickers.cs +++ b/UICatalog/Scenarios/DatePickers.cs @@ -13,7 +13,7 @@ public class DatePickers : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; var datePicker = new DatePicker { Y = Pos.Center (), X = Pos.Center () }; diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs index 082acb806..f67210417 100644 --- a/UICatalog/Scenarios/Dialogs.cs +++ b/UICatalog/Scenarios/Dialogs.cs @@ -17,7 +17,7 @@ public class Dialogs : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; var frame = new FrameView diff --git a/UICatalog/Scenarios/DimAutoDemo.cs b/UICatalog/Scenarios/DimAutoDemo.cs index 1ced9cf7d..124729744 100644 --- a/UICatalog/Scenarios/DimAutoDemo.cs +++ b/UICatalog/Scenarios/DimAutoDemo.cs @@ -15,7 +15,7 @@ public class DimAutoDemo : Scenario // Setup - Create a top-level application window and configure it. Window appWindow = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), }; // For diagnostics diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs index eda9d041b..4d39958a6 100644 --- a/UICatalog/Scenarios/DynamicMenuBar.cs +++ b/UICatalog/Scenarios/DynamicMenuBar.cs @@ -21,7 +21,7 @@ public class DynamicMenuBar : Scenario // Setup - Create a top-level application window and configure it. DynamicMenuBarSample appWindow = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; // Run - Start the application. diff --git a/UICatalog/Scenarios/DynamicStatusBar.cs b/UICatalog/Scenarios/DynamicStatusBar.cs index 3c93421ee..551e4ad36 100644 --- a/UICatalog/Scenarios/DynamicStatusBar.cs +++ b/UICatalog/Scenarios/DynamicStatusBar.cs @@ -317,7 +317,7 @@ public class DynamicStatusBar : Scenario { DataContext = new DynamicStatusItemModel (); - Title = $"{Application.QuitKey} to Quit"; + Title = $"{Application.QuitKey} to Quit - Scenario: Dynamic StatusBar"; var _frmStatusBar = new FrameView { diff --git a/UICatalog/Scenarios/Editor.cs b/UICatalog/Scenarios/Editor.cs index aa23821c8..d876723f1 100644 --- a/UICatalog/Scenarios/Editor.cs +++ b/UICatalog/Scenarios/Editor.cs @@ -46,7 +46,7 @@ public class Editor : Scenario // Setup - Create a top-level application window and configure it. _appWindow = new () { - //Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + //Title = GetQuitKeyAndName (), Title = _fileName ?? "Untitled", BorderStyle = LineStyle.None }; diff --git a/UICatalog/Scenarios/FileDialogExamples.cs b/UICatalog/Scenarios/FileDialogExamples.cs index 55fde0ca1..48f8cf510 100644 --- a/UICatalog/Scenarios/FileDialogExamples.cs +++ b/UICatalog/Scenarios/FileDialogExamples.cs @@ -26,104 +26,110 @@ public class FileDialogExamples : Scenario private TextField _tbCancelButton; private TextField _tbOkButton; - public override void Setup () + public override void Main () { + Application.Init (); var y = 0; var x = 1; + var win = new Window { Title = GetQuitKeyAndName () }; _cbMustExist = new CheckBox { State = CheckState.Checked, Y = y++, X = x, Text = "Must Exist" }; - Win.Add (_cbMustExist); + win.Add (_cbMustExist); _cbUseColors = new CheckBox { State = FileDialogStyle.DefaultUseColors ? CheckState.Checked : CheckState.UnChecked, Y = y++, X = x, Text = "Use Colors" }; - Win.Add (_cbUseColors); + win.Add (_cbUseColors); _cbCaseSensitive = new CheckBox { State = CheckState.UnChecked, Y = y++, X = x, Text = "Case Sensitive Search" }; - Win.Add (_cbCaseSensitive); + win.Add (_cbCaseSensitive); _cbAllowMultipleSelection = new CheckBox { State = CheckState.UnChecked, Y = y++, X = x, Text = "Multiple" }; - Win.Add (_cbAllowMultipleSelection); + win.Add (_cbAllowMultipleSelection); _cbShowTreeBranchLines = new CheckBox { State = CheckState.Checked, Y = y++, X = x, Text = "Tree Branch Lines" }; - Win.Add (_cbShowTreeBranchLines); + win.Add (_cbShowTreeBranchLines); _cbAlwaysTableShowHeaders = new CheckBox { State = CheckState.Checked, Y = y++, X = x, Text = "Always Show Headers" }; - Win.Add (_cbAlwaysTableShowHeaders); + win.Add (_cbAlwaysTableShowHeaders); _cbDrivesOnlyInTree = new CheckBox { State = CheckState.UnChecked, Y = y++, X = x, Text = "Only Show Drives" }; - Win.Add (_cbDrivesOnlyInTree); + win.Add (_cbDrivesOnlyInTree); y = 0; x = 24; - Win.Add ( + win.Add ( new LineView (Orientation.Vertical) { X = x++, Y = 1, Height = 4 } ); - Win.Add (new Label { X = x++, Y = y++, Text = "Caption" }); + win.Add (new Label { X = x++, Y = y++, Text = "Caption" }); _rgCaption = new RadioGroup { X = x, Y = y }; _rgCaption.RadioLabels = new [] { "Ok", "Open", "Save" }; - Win.Add (_rgCaption); + win.Add (_rgCaption); y = 0; x = 34; - Win.Add ( + win.Add ( new LineView (Orientation.Vertical) { X = x++, Y = 1, Height = 4 } ); - Win.Add (new Label { X = x++, Y = y++, Text = "OpenMode" }); + win.Add (new Label { X = x++, Y = y++, Text = "OpenMode" }); _rgOpenMode = new RadioGroup { X = x, Y = y }; _rgOpenMode.RadioLabels = new [] { "File", "Directory", "Mixed" }; - Win.Add (_rgOpenMode); + win.Add (_rgOpenMode); y = 0; x = 48; - Win.Add ( + win.Add ( new LineView (Orientation.Vertical) { X = x++, Y = 1, Height = 4 } ); - Win.Add (new Label { X = x++, Y = y++, Text = "Icons" }); + win.Add (new Label { X = x++, Y = y++, Text = "Icons" }); _rgIcons = new RadioGroup { X = x, Y = y }; _rgIcons.RadioLabels = new [] { "None", "Unicode", "Nerd*" }; - Win.Add (_rgIcons); + win.Add (_rgIcons); - Win.Add (new Label { Y = Pos.AnchorEnd (2), Text = "* Requires installing Nerd fonts" }); - Win.Add (new Label { Y = Pos.AnchorEnd (1), Text = " (see: https://github.com/devblackops/Terminal-Icons)" }); + win.Add (new Label { Y = Pos.AnchorEnd (2), Text = "* Requires installing Nerd fonts" }); + win.Add (new Label { Y = Pos.AnchorEnd (1), Text = " (see: https://github.com/devblackops/Terminal-Icons)" }); y = 5; x = 24; - Win.Add ( + win.Add ( new LineView (Orientation.Vertical) { X = x++, Y = y + 1, Height = 4 } ); - Win.Add (new Label { X = x++, Y = y++, Text = "Allowed" }); + win.Add (new Label { X = x++, Y = y++, Text = "Allowed" }); _rgAllowedTypes = new RadioGroup { X = x, Y = y }; _rgAllowedTypes.RadioLabels = new [] { "Any", "Csv (Recommended)", "Csv (Strict)" }; - Win.Add (_rgAllowedTypes); + win.Add (_rgAllowedTypes); y = 5; x = 45; - Win.Add ( + win.Add ( new LineView (Orientation.Vertical) { X = x++, Y = y + 1, Height = 4 } ); - Win.Add (new Label { X = x++, Y = y++, Text = "Buttons" }); + win.Add (new Label { X = x++, Y = y++, Text = "Buttons" }); - Win.Add (new Label { X = x, Y = y++, Text = "Ok Text:" }); + win.Add (new Label { X = x, Y = y++, Text = "Ok Text:" }); _tbOkButton = new TextField { X = x, Y = y++, Width = 12 }; - Win.Add (_tbOkButton); - Win.Add (new Label { X = x, Y = y++, Text = "Cancel Text:" }); + win.Add (_tbOkButton); + win.Add (new Label { X = x, Y = y++, Text = "Cancel Text:" }); _tbCancelButton = new TextField { X = x, Y = y++, Width = 12 }; - Win.Add (_tbCancelButton); + win.Add (_tbCancelButton); _cbFlipButtonOrder = new CheckBox { X = x, Y = y++, Text = "Flip Order" }; - Win.Add (_cbFlipButtonOrder); + win.Add (_cbFlipButtonOrder); var btn = new Button { X = 1, Y = 9, Text = "Run Dialog" }; SetupHandler (btn); - Win.Add (btn); + win.Add (btn); + + Application.Run (win); + win.Dispose (); + Application.Shutdown (); } private void ConfirmOverwrite (object sender, FilesSelectedEventArgs e) diff --git a/UICatalog/Scenarios/Generic.cs b/UICatalog/Scenarios/Generic.cs index 9cc5d4582..97dab5372 100644 --- a/UICatalog/Scenarios/Generic.cs +++ b/UICatalog/Scenarios/Generic.cs @@ -14,7 +14,7 @@ public sealed class MyScenario : Scenario // Setup - Create a top-level application window and configure it. Window appWindow = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", + Title = GetQuitKeyAndName (), }; var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" }; diff --git a/UICatalog/Scenarios/HotKeys.cs b/UICatalog/Scenarios/HotKeys.cs index f4a46f516..aa0e404e2 100644 --- a/UICatalog/Scenarios/HotKeys.cs +++ b/UICatalog/Scenarios/HotKeys.cs @@ -13,7 +13,7 @@ public class HotKeys : Scenario Window app = new () { - Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" + Title = GetQuitKeyAndName () }; var textViewLabel = new Label { Text = "_TextView:", X = 0, Y = 0 }; diff --git a/UICatalog/Scenarios/Images.cs b/UICatalog/Scenarios/Images.cs index 40f24d7e2..d31eae9cc 100644 --- a/UICatalog/Scenarios/Images.cs +++ b/UICatalog/Scenarios/Images.cs @@ -15,14 +15,15 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Drawing")] public class Images : Scenario { - public override void Setup () + public override void Main () { - base.Setup (); + Application.Init (); + var win = new Window { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName()}" }; bool canTrueColor = Application.Driver.SupportsTrueColor; var lblDriverName = new Label { X = 0, Y = 0, Text = $"Driver is {Application.Driver.GetType ().Name}" }; - Win.Add (lblDriverName); + win.Add (lblDriverName); var cbSupportsTrueColor = new CheckBox { @@ -32,7 +33,7 @@ public class Images : Scenario CanFocus = false, Text = "supports true color " }; - Win.Add (cbSupportsTrueColor); + win.Add (cbSupportsTrueColor); var cbUseTrueColor = new CheckBox { @@ -43,63 +44,68 @@ public class Images : Scenario Text = "Use true color" }; cbUseTrueColor.Toggle += (_, evt) => Application.Force16Colors = evt.NewValue == CheckState.UnChecked; - Win.Add (cbUseTrueColor); + win.Add (cbUseTrueColor); var btnOpenImage = new Button { X = Pos.Right (cbUseTrueColor) + 2, Y = 0, Text = "Open Image" }; - Win.Add (btnOpenImage); + win.Add (btnOpenImage); var imageView = new ImageView { X = 0, Y = Pos.Bottom (lblDriverName), Width = Dim.Fill (), Height = Dim.Fill () }; - Win.Add (imageView); + win.Add (imageView); btnOpenImage.Accept += (_, _) => - { - var ofd = new OpenDialog { Title = "Open Image", AllowsMultipleSelection = false }; - Application.Run (ofd); + { + var ofd = new OpenDialog { Title = "Open Image", AllowsMultipleSelection = false }; + Application.Run (ofd); - if (ofd.Path is { }) - { - Directory.SetCurrentDirectory (Path.GetFullPath (Path.GetDirectoryName (ofd.Path)!)); - } + if (ofd.Path is { }) + { + Directory.SetCurrentDirectory (Path.GetFullPath (Path.GetDirectoryName (ofd.Path)!)); + } - if (ofd.Canceled) - { - ofd.Dispose (); - return; - } + if (ofd.Canceled) + { + ofd.Dispose (); - string path = ofd.FilePaths [0]; + return; + } - ofd.Dispose (); + string path = ofd.FilePaths [0]; - if (string.IsNullOrWhiteSpace (path)) - { - return; - } + ofd.Dispose (); - if (!File.Exists (path)) - { - return; - } + if (string.IsNullOrWhiteSpace (path)) + { + return; + } - Image img; + if (!File.Exists (path)) + { + return; + } - try - { - img = Image.Load (File.ReadAllBytes (path)); - } - catch (Exception ex) - { - MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok"); + Image img; - return; - } + try + { + img = Image.Load (File.ReadAllBytes (path)); + } + catch (Exception ex) + { + MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok"); - imageView.SetImage (img); - Application.Refresh (); - }; + return; + } + + imageView.SetImage (img); + Application.Refresh (); + }; + + Application.Run (win); + win.Dispose (); + Application.Shutdown (); } private class ImageView : View diff --git a/UICatalog/Scenarios/InvertColors.cs b/UICatalog/Scenarios/InvertColors.cs index be8297cc6..a98aaf720 100644 --- a/UICatalog/Scenarios/InvertColors.cs +++ b/UICatalog/Scenarios/InvertColors.cs @@ -10,9 +10,14 @@ namespace UICatalog.Scenarios; [ScenarioCategory ("Text and Formatting")] public class InvertColors : Scenario { - public override void Setup () + public override void Main () { - Win.ColorScheme = Colors.ColorSchemes ["TopLevel"]; + Application.Init (); + var win = new Window + { + Title = GetQuitKeyAndName (), + ColorScheme = Colors.ColorSchemes ["TopLevel"] + }; List