├── .editorconfig ├── .github ├── funding.yml └── workflows │ ├── ci.yaml │ └── publish.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── README.md ├── build.cake ├── dotnet-tools.json ├── examples ├── Demo │ ├── Demo.csproj │ ├── Files │ │ ├── Example.md │ │ ├── Foo.cpp │ │ ├── Foo.h │ │ └── Program.cs │ └── Program.cs └── Shared │ ├── EmbeddedResourceReader.cs │ ├── EmbeddedResourceRepository.cs │ └── Shared.csproj ├── global.json ├── resources └── gfx │ ├── large-logo.png │ ├── medium-logo.png │ ├── screenshots │ └── demo.png │ └── small-logo.png └── src ├── .editorconfig ├── Directory.Build.props ├── Directory.Build.targets ├── Errata.Tests ├── .editorconfig ├── CharacterSetTests.cs ├── Data │ ├── Example.md │ ├── Foo.cpp │ ├── Foo.h │ └── Program.cs ├── Errata.Tests.csproj ├── Expectations │ └── Report │ │ └── Rendering │ │ ├── Compact.Output.verified.txt │ │ ├── LabelPriority.Output.verified.txt │ │ ├── LastCharacter.Output.verified.txt │ │ ├── LeftPadding.Output.verified.txt │ │ ├── Locations │ │ ├── LabelsWithMultipleFiles.Output.verified.txt │ │ ├── MultipleDiagnostics.Output.verified.txt │ │ ├── MultipleLabels.Output.verified.txt │ │ ├── MultipleLabelsDifferentPriority.Output.verified.txt │ │ └── SingleLabel.Output.verified.txt │ │ ├── ReportError.Output.verified.txt │ │ ├── Rows │ │ ├── MultipleLabels.Output.verified.txt │ │ ├── MultipleLabelsDifferentPriority.Output.verified.txt │ │ └── SingleLabel.Output.verified.txt │ │ └── Spans │ │ ├── LabelsWithMultipleFiles.Output.verified.txt │ │ ├── MultipleDiagnostics.Output.verified.txt │ │ ├── MultipleLabels.Output.verified.txt │ │ └── SingleLabel.Output.verified.txt ├── LabelTests.cs ├── Properties │ └── VerifyConfiguration.cs ├── ReportTests.cs ├── SourceTests.cs ├── TextLineTests.cs ├── TextSpanTests.cs └── Utilities │ ├── EmbeddedResourceReader.cs │ ├── EmbeddedResourceRepository.cs │ └── GitHubIssueAttribute.cs ├── Errata.sln ├── Errata ├── Character.cs ├── CharacterSet.cs ├── Diagnostic.cs ├── DiagnosticExtensions.cs ├── DiagnosticFormatter.cs ├── Diagnostics │ ├── ErrorDiagnostic.cs │ ├── InfoDiagnostic.cs │ └── WarningDiagnostic.cs ├── Errata.csproj ├── ErrataException.cs ├── Extensions │ ├── IAnsiConsoleExtensions.cs │ ├── IEnumerableExtensions.cs │ └── RangeExtensions.cs ├── ISourceRepository.cs ├── Label.cs ├── LabelExtensions.cs ├── Location.cs ├── Properties │ └── AssemblyInfo.cs ├── Rendering │ ├── DiagnosticContext.cs │ ├── DiagnosticRenderer.cs │ ├── LabelInfo.cs │ ├── LabelKind.cs │ ├── LineLabel.cs │ ├── LineRange.cs │ ├── RenderConsole.cs │ ├── ReportBuilder.cs │ ├── ReportContext.cs │ ├── ReportRenderable.cs │ ├── ReportRenderer.cs │ ├── SourceGroup.cs │ └── SourceGroupCollection.cs ├── Report.cs ├── ReportExtensions.cs ├── ReportSettings.cs ├── Repositories │ └── InMemorySourceRepository.cs ├── Source.cs ├── SourceComparer.cs ├── TextBuffer.cs ├── TextLine.cs └── TextSpan.cs └── stylecop.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = CRLF 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = false 9 | trim_trailing_whitespace = true 10 | 11 | [*.sln] 12 | indent_style = tab 13 | 14 | [*.{csproj,vbproj,vcxproj,vcxproj.filters}] 15 | indent_size = 2 16 | 17 | [*.{xml,config,props,targets,nuspec,ruleset}] 18 | indent_size = 2 19 | 20 | [*.{yml,yaml}] 21 | indent_size = 2 22 | 23 | [*.json] 24 | indent_size = 2 25 | 26 | [*.md] 27 | trim_trailing_whitespace = false 28 | 29 | [*.sh] 30 | end_of_line = lf 31 | 32 | [*.cs] 33 | # Prefer file scoped namespace declarations 34 | csharp_style_namespace_declarations = file_scoped:warning 35 | 36 | # Sort using and Import directives with System.* appearing first 37 | dotnet_sort_system_directives_first = true 38 | dotnet_separate_import_directive_groups = false 39 | 40 | # Avoid "this." and "Me." if not necessary 41 | dotnet_style_qualification_for_field = false:refactoring 42 | dotnet_style_qualification_for_property = false:refactoring 43 | dotnet_style_qualification_for_method = false:refactoring 44 | dotnet_style_qualification_for_event = false:refactoring 45 | 46 | # Use language keywords instead of framework type names for type references 47 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 48 | dotnet_style_predefined_type_for_member_access = true:suggestion 49 | 50 | # Suggest more modern language features when available 51 | dotnet_style_object_initializer = true:suggestion 52 | dotnet_style_collection_initializer = true:suggestion 53 | dotnet_style_coalesce_expression = true:suggestion 54 | dotnet_style_null_propagation = true:suggestion 55 | dotnet_style_explicit_tuple_names = true:suggestion 56 | 57 | # Non-private static fields are PascalCase 58 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion 59 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields 60 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style 61 | dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field 62 | dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected 63 | dotnet_naming_symbols.non_private_static_fields.required_modifiers = static 64 | dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case 65 | 66 | # Non-private readonly fields are PascalCase 67 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion 68 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields 69 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style 70 | dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field 71 | dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected 72 | dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly 73 | dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case 74 | 75 | # Constants are PascalCase 76 | dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion 77 | dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants 78 | dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style 79 | dotnet_naming_symbols.constants.applicable_kinds = field, local 80 | dotnet_naming_symbols.constants.required_modifiers = const 81 | dotnet_naming_style.constant_style.capitalization = pascal_case 82 | 83 | # Instance fields are camelCase and start with _ 84 | dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion 85 | dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields 86 | dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style 87 | dotnet_naming_symbols.instance_fields.applicable_kinds = field 88 | dotnet_naming_style.instance_field_style.capitalization = camel_case 89 | dotnet_naming_style.instance_field_style.required_prefix = _ 90 | 91 | # Locals and parameters are camelCase 92 | dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion 93 | dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters 94 | dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style 95 | dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local 96 | dotnet_naming_style.camel_case_style.capitalization = camel_case 97 | 98 | # Local functions are PascalCase 99 | dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion 100 | dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions 101 | dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style 102 | dotnet_naming_symbols.local_functions.applicable_kinds = local_function 103 | dotnet_naming_style.local_function_style.capitalization = pascal_case 104 | 105 | # By default, name items with PascalCase 106 | dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion 107 | dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members 108 | dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style 109 | dotnet_naming_symbols.all_members.applicable_kinds = * 110 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 111 | 112 | # Newline settings 113 | csharp_new_line_before_open_brace = all 114 | csharp_new_line_before_else = true 115 | csharp_new_line_before_catch = true 116 | csharp_new_line_before_finally = true 117 | csharp_new_line_before_members_in_object_initializers = true 118 | csharp_new_line_before_members_in_anonymous_types = true 119 | csharp_new_line_between_query_expression_clauses = true 120 | 121 | # Indentation preferences 122 | csharp_indent_block_contents = true 123 | csharp_indent_braces = false 124 | csharp_indent_case_contents = true 125 | csharp_indent_case_contents_when_block = true 126 | csharp_indent_switch_labels = true 127 | csharp_indent_labels = flush_left 128 | 129 | # Prefer "var" everywhere 130 | csharp_style_var_for_built_in_types = true:suggestion 131 | csharp_style_var_when_type_is_apparent = true:suggestion 132 | csharp_style_var_elsewhere = true:suggestion 133 | 134 | # Prefer method-like constructs to have a block body 135 | csharp_style_expression_bodied_methods = false:none 136 | csharp_style_expression_bodied_constructors = false:none 137 | csharp_style_expression_bodied_operators = false:none 138 | 139 | # Prefer property-like constructs to have an expression-body 140 | csharp_style_expression_bodied_properties = true:none 141 | csharp_style_expression_bodied_indexers = true:none 142 | csharp_style_expression_bodied_accessors = true:none 143 | 144 | # Suggest more modern language features when available 145 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 146 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 147 | csharp_style_inlined_variable_declaration = true:suggestion 148 | csharp_style_throw_expression = true:suggestion 149 | csharp_style_conditional_delegate_call = true:suggestion 150 | 151 | # Space preferences 152 | csharp_space_after_cast = false 153 | csharp_space_after_colon_in_inheritance_clause = true 154 | csharp_space_after_comma = true 155 | csharp_space_after_dot = false 156 | csharp_space_after_keywords_in_control_flow_statements = true 157 | csharp_space_after_semicolon_in_for_statement = true 158 | csharp_space_around_binary_operators = before_and_after 159 | csharp_space_around_declaration_statements = do_not_ignore 160 | csharp_space_before_colon_in_inheritance_clause = true 161 | csharp_space_before_comma = false 162 | csharp_space_before_dot = false 163 | csharp_space_before_open_square_brackets = false 164 | csharp_space_before_semicolon_in_for_statement = false 165 | csharp_space_between_empty_square_brackets = false 166 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 167 | csharp_space_between_method_call_name_and_opening_parenthesis = false 168 | csharp_space_between_method_call_parameter_list_parentheses = false 169 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 170 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 171 | csharp_space_between_method_declaration_parameter_list_parentheses = false 172 | csharp_space_between_parentheses = false 173 | csharp_space_between_square_brackets = false 174 | 175 | # Blocks are allowed 176 | csharp_prefer_braces = true:silent 177 | csharp_preserve_single_line_blocks = true 178 | csharp_preserve_single_line_statements = true -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: patriksvensson -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | name: Continuous Integration 3 | on: pull_request 4 | 5 | env: 6 | # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages 7 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 8 | # Disable sending usage data to Microsoft 9 | DOTNET_CLI_TELEMETRY_OPTOUT: true 10 | 11 | jobs: 12 | 13 | ################################################### 14 | # BUILD 15 | ################################################### 16 | 17 | build: 18 | name: Build 19 | if: "!contains(github.event.head_commit.message, 'skip-ci')" 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: 'Get Git tags' 28 | run: git fetch --tags 29 | shell: bash 30 | 31 | - name: Setup .NET SDK 32 | uses: actions/setup-dotnet@v3 33 | 34 | - name: Build 35 | shell: bash 36 | run: | 37 | dotnet tool restore 38 | dotnet cake -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | branches: 8 | - main 9 | 10 | env: 11 | # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages 12 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 13 | # Disable sending usage data to Microsoft 14 | DOTNET_CLI_TELEMETRY_OPTOUT: true 15 | 16 | jobs: 17 | 18 | ################################################### 19 | # PUBLISH 20 | ################################################### 21 | 22 | publish: 23 | name: Publish 24 | if: "!contains(github.event.head_commit.message, 'skip-ci')" 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 31 | 32 | - name: 'Get Git tags' 33 | run: git fetch --tags 34 | shell: bash 35 | 36 | - name: Setup .NET SDK 37 | uses: actions/setup-dotnet@v3 38 | 39 | - name: Publish 40 | shell: bash 41 | run: | 42 | dotnet tool restore 43 | dotnet cake --target="publish" \ 44 | --nuget-key="${{secrets.NUGET_API_KEY}}" \ 45 | --github-key="${{secrets.GITHUB_TOKEN}}" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Misc folders 2 | [Bb]in/ 3 | [Oo]bj/ 4 | [Tt]emp/ 5 | [Pp]ackages/ 6 | /.artifacts/ 7 | /[Tt]ools/ 8 | 9 | # Cakeup 10 | cakeup-x86_64-latest.exe 11 | 12 | # .NET Core CLI 13 | /.dotnet/ 14 | /.packages/ 15 | dotnet-install.sh* 16 | *.lock.json 17 | 18 | # Visual Studio 19 | .vs/ 20 | .vscode/ 21 | launchSettings.json 22 | *.sln.ide/ 23 | 24 | # Rider 25 | src/.idea/**/workspace.xml 26 | src/.idea/**/tasks.xml 27 | src/.idea/dictionaries 28 | src/.idea/**/dataSources/ 29 | src/.idea/**/dataSources.ids 30 | src/.idea/**/dataSources.xml 31 | src/.idea/**/dataSources.local.xml 32 | src/.idea/**/sqlDataSources.xml 33 | src/.idea/**/dynamic.xml 34 | src/.idea/**/uiDesigner.xml 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | *.userprefs 44 | *.GhostDoc.xml 45 | *StyleCop.Cache 46 | 47 | # Build results 48 | [Dd]ebug/ 49 | [Rr]elease/ 50 | x64/ 51 | *_i.c 52 | *_p.c 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # ReSharper is a .NET coding add-in 77 | _ReSharper* 78 | 79 | # NCrunch 80 | *.ncrunch* 81 | .*crunch*.local.xml 82 | _NCrunch_* 83 | 84 | # NuGet Packages Directory 85 | packages 86 | 87 | # Windows 88 | Thumbs.db 89 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at patrik@patriksvensson.se. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Patrik Svensson, Phil Scott, James Randall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Errata 2 | 3 | _[![Errata NuGet Version](https://img.shields.io/nuget/v/errata.svg?style=flat&label=NuGet%3A%20Errata)](https://www.nuget.org/packages/errata)_ 4 | 5 | A library that makes it easy to create and display diagnostics of 6 | different kinds. 7 | 8 | ![Example](resources/gfx/screenshots/demo.png) 9 | 10 | ## Running examples 11 | 12 | To see `Errata` in action, install the 13 | [dotnet-example](https://github.com/patriksvensson/dotnet-example) 14 | global tool. 15 | 16 | ``` 17 | > dotnet tool install -g dotnet-example 18 | ``` 19 | 20 | Now you can list available examples in this repository: 21 | 22 | ``` 23 | > dotnet example 24 | ``` 25 | 26 | ## Building 27 | 28 | We're using [Cake](https://github.com/cake-build/cake) as a 29 | [dotnet tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools) 30 | for building. So make sure that you've restored Cake by running 31 | the following in the repository root: 32 | 33 | ``` 34 | > dotnet tool restore 35 | ``` 36 | 37 | After that, running the build is as easy as writing: 38 | 39 | ``` 40 | > dotnet cake 41 | ``` 42 | 43 | ## Acknowledgement 44 | 45 | Inspired by the excellent [Ariadne](https://github.com/zesterer/ariadne) crate. -------------------------------------------------------------------------------- /build.cake: -------------------------------------------------------------------------------- 1 | var target = Argument("target", "Default"); 2 | var configuration = Argument("configuration", "Release"); 3 | 4 | //////////////////////////////////////////////////////////////// 5 | // Tasks 6 | 7 | Task("Build") 8 | .Does(context => 9 | { 10 | DotNetBuild("./src/Errata.sln", new DotNetBuildSettings { 11 | Configuration = configuration, 12 | NoIncremental = context.HasArgument("rebuild"), 13 | MSBuildSettings = new DotNetMSBuildSettings() 14 | .TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error) 15 | }); 16 | }); 17 | 18 | Task("Test") 19 | .IsDependentOn("Build") 20 | .Does(context => 21 | { 22 | DotNetTest("./src/Errata.sln", new DotNetTestSettings { 23 | Configuration = configuration, 24 | NoRestore = true, 25 | NoBuild = true, 26 | }); 27 | }); 28 | 29 | Task("Package") 30 | .IsDependentOn("Test") 31 | .Does(context => 32 | { 33 | context.CleanDirectory("./.artifacts"); 34 | 35 | context.DotNetPack($"./src/Errata.sln", new DotNetPackSettings { 36 | Configuration = configuration, 37 | NoRestore = true, 38 | NoBuild = true, 39 | OutputDirectory = "./.artifacts", 40 | MSBuildSettings = new DotNetMSBuildSettings() 41 | .TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error) 42 | }); 43 | }); 44 | 45 | Task("Publish-NuGet") 46 | .WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions") 47 | .IsDependentOn("Package") 48 | .Does(context => 49 | { 50 | var apiKey = Argument("nuget-key", null); 51 | if(string.IsNullOrWhiteSpace(apiKey)) { 52 | throw new CakeException("No NuGet API key was provided."); 53 | } 54 | 55 | // Publish to GitHub Packages 56 | foreach(var file in context.GetFiles("./.artifacts/*.nupkg")) 57 | { 58 | context.Information("Publishing {0}...", file.GetFilename().FullPath); 59 | DotNetNuGetPush(file.FullPath, new DotNetNuGetPushSettings 60 | { 61 | Source = "https://api.nuget.org/v3/index.json", 62 | ApiKey = apiKey, 63 | }); 64 | } 65 | }); 66 | 67 | //////////////////////////////////////////////////////////////// 68 | // Targets 69 | 70 | Task("Publish") 71 | .IsDependentOn("Publish-NuGet"); 72 | 73 | Task("Default") 74 | .IsDependentOn("Package"); 75 | 76 | //////////////////////////////////////////////////////////////// 77 | // Execution 78 | 79 | RunTarget(target) -------------------------------------------------------------------------------- /dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "3.2.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | }, 11 | "dotnet-example": { 12 | "version": "1.6.0", 13 | "commands": [ 14 | "dotnet-example" 15 | ] 16 | }, 17 | "verify.tool": { 18 | "version": "0.6.0", 19 | "commands": [ 20 | "dotnet-verify" 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /examples/Demo/Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | false 7 | Demo 8 | Demonstrates different kinds of diagnostics. 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/Demo/Files/Example.md: -------------------------------------------------------------------------------- 1 | # HELLO WORLD! 2 | 3 | This is jus an *example** file 4 | which is used by the Errata 5 | example application. 6 | 7 | Will be cool to see what this 8 | looks like once it's complete! 9 | 10 | Your failures are your own, old man! I say, follow throooough! 11 | And that's why I always say WUBBA LUBBA DUB DUB! 12 | Are you hungry for apples? ARE YOU HUNGRY FOR APPLESSS!? 13 | 14 | I mean, why would a poptart want to live inside a toaster, 15 | Rick? I mean, that would be like the scariest place for them to live. 16 | You know what I mean? Awwww thanks! Nice, Mrs Pancakes. 17 | Real nice. I'm Mr. Crowbar, and here is my friend, who is also a crowbar! 18 | 19 | / Patrik 20 | -------------------------------------------------------------------------------- /examples/Demo/Files/Foo.cpp: -------------------------------------------------------------------------------- 1 | #include "foo.h" 2 | void Foo::bar(float) 3 | { 4 | } -------------------------------------------------------------------------------- /examples/Demo/Files/Foo.h: -------------------------------------------------------------------------------- 1 | class Foo { 2 | public: 3 | void bar(int); 4 | }; -------------------------------------------------------------------------------- /examples/Demo/Files/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Example.Files 8 | { 9 | public static class Program 10 | { 11 | public static void Main() 12 | { 13 | var foo = 1; 14 | var bar = "lol"; 15 | var qux = foo / bar; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/Demo/Program.cs: -------------------------------------------------------------------------------- 1 | using Errata; 2 | using Spectre.Console; 3 | 4 | namespace Example; 5 | 6 | public static class Program 7 | { 8 | public static void Main() 9 | { 10 | // Create a new report 11 | var report = new Report( 12 | new EmbeddedResourceRepository( 13 | typeof(Program).Assembly)); 14 | 15 | // C# 16 | report.AddDiagnostic( 17 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 18 | .WithCode("CS0019") 19 | .WithNote("Try changing the type") 20 | .WithLabel(new Label("Demo/Files/Program.cs", new Location(15, 23), "This is of type 'int'") 21 | .WithLength(3) 22 | .WithPriority(1) 23 | .WithColor(Color.Yellow)) 24 | .WithLabel(new Label("Demo/Files/Program.cs", new Location(15, 27), "Division is not possible") 25 | .WithPriority(3) 26 | .WithColor(Color.Red)) 27 | .WithLabel(new Label("Demo/Files/Program.cs", new Location(15, 29), "This is of type 'string'") 28 | .WithLength(3) 29 | .WithPriority(2) 30 | .WithColor(Color.Blue))); 31 | 32 | report.AddDiagnostic( 33 | Diagnostic.Info("Fix formatting") 34 | .WithCode("IDE0055")) 35 | .WithLabel(new Label("Demo/Files/Program.cs", 174..176, "Code should not contain trailing whitespace") 36 | .WithColor(Color.Blue)); 37 | 38 | // Markdown 39 | report.AddDiagnostic( 40 | Diagnostic.Error("There were markdown errors") 41 | .WithCode("MARKDOWN001") 42 | .WithLabel(new Label("Demo/Files/Example.md", 24..27, "Did you mean 'just'?") 43 | .WithColor(Color.Yellow)) 44 | .WithLabel(new Label("Demo/Files/Example.md", 31..41, "Invalid markdown") 45 | .WithColor(Color.Red)) 46 | .WithLabel(new Label("Demo/Files/Example.md", 251..270, "Did you mean 'Yabba dabba doo'?") 47 | .WithColor(Color.Yellow))); 48 | 49 | // C++ 50 | report.AddDiagnostic( 51 | Diagnostic.Error("Compiler error") 52 | .WithCode("C2084") 53 | .WithNote("Overloaded member not found") 54 | .WithLabel(new Label("Demo/Files/Foo.cpp", 22..37, " 'void Foo::bar(float)': overloaded member function not found in 'Foo'") 55 | .WithColor(Color.Red) 56 | .WithNote("See declaration of 'Foo' in Foo.h")) 57 | .WithLabel(new Label("Demo/Files/Foo.h", 24..38, "See declaration of 'Foo'") 58 | .WithColor(Color.Blue))); 59 | 60 | // Render the report 61 | report.Render(AnsiConsole.Console); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/Shared/EmbeddedResourceReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | 5 | namespace Example; 6 | 7 | public static class EmbeddedResourceReader 8 | { 9 | public static Stream LoadResourceStream(Assembly assembly, string resourceName) 10 | { 11 | if (assembly is null) 12 | { 13 | throw new ArgumentNullException(nameof(assembly)); 14 | } 15 | 16 | if (resourceName is null) 17 | { 18 | throw new ArgumentNullException(nameof(resourceName)); 19 | } 20 | 21 | resourceName = resourceName.Replace("/", "."); 22 | return assembly.GetManifestResourceStream(resourceName); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/Shared/EmbeddedResourceRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.IO; 5 | using System.Reflection; 6 | using Errata; 7 | 8 | namespace Example; 9 | 10 | public sealed class EmbeddedResourceRepository : ISourceRepository 11 | { 12 | private readonly Dictionary _lookup; 13 | private readonly Assembly _assembly; 14 | 15 | public EmbeddedResourceRepository(Assembly assembly) 16 | { 17 | _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase); 18 | _assembly = assembly; 19 | } 20 | 21 | public bool TryGet(string id, [NotNullWhen(true)] out Source source) 22 | { 23 | if (!_lookup.TryGetValue(id, out source)) 24 | { 25 | using (var stream = EmbeddedResourceReader.LoadResourceStream(_assembly, id)) 26 | using (var reader = new StreamReader(stream)) 27 | { 28 | source = new Source(id, reader.ReadToEnd().Replace("\r\n", "\n")); 29 | _lookup[id] = source; 30 | } 31 | } 32 | 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/Shared/Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src" ], 3 | "sdk": { 4 | "version": "8.0.100", 5 | "rollForward": "latestFeature" 6 | } 7 | } -------------------------------------------------------------------------------- /resources/gfx/large-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spectreconsole/errata/b8ede51b9ab4cf018380369e244d56b37825d255/resources/gfx/large-logo.png -------------------------------------------------------------------------------- /resources/gfx/medium-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spectreconsole/errata/b8ede51b9ab4cf018380369e244d56b37825d255/resources/gfx/medium-logo.png -------------------------------------------------------------------------------- /resources/gfx/screenshots/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spectreconsole/errata/b8ede51b9ab4cf018380369e244d56b37825d255/resources/gfx/screenshots/demo.png -------------------------------------------------------------------------------- /resources/gfx/small-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spectreconsole/errata/b8ede51b9ab4cf018380369e244d56b37825d255/resources/gfx/small-logo.png -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = false 2 | 3 | [*.cs] 4 | # IDE0055: Fix formatting 5 | dotnet_diagnostic.IDE0055.severity = warning 6 | 7 | # SA1101: Prefix local calls with this 8 | dotnet_diagnostic.SA1101.severity = none 9 | 10 | # SA1633: File should have header 11 | dotnet_diagnostic.SA1633.severity = none 12 | 13 | # SA1201: Elements should appear in the correct order 14 | dotnet_diagnostic.SA1201.severity = none 15 | 16 | # SA1202: Public members should come before private members 17 | dotnet_diagnostic.SA1202.severity = none 18 | 19 | # SA1309: Field names should not begin with underscore 20 | dotnet_diagnostic.SA1309.severity = none 21 | 22 | # SA1404: Code analysis suppressions should have justification 23 | dotnet_diagnostic.SA1404.severity = none 24 | 25 | # SA1516: Elements should be separated by a blank line 26 | dotnet_diagnostic.SA1516.severity = none 27 | 28 | # CA1303: Do not pass literals as localized parameters 29 | dotnet_diagnostic.CA1303.severity = none 30 | 31 | # CSA1204: Static members should appear before non-static members 32 | dotnet_diagnostic.SA1204.severity = none 33 | 34 | # IDE0052: Remove unread private members 35 | dotnet_diagnostic.IDE0052.severity = warning 36 | 37 | # IDE0063: Use simple 'using' statement 38 | csharp_prefer_simple_using_statement = false:suggestion 39 | 40 | # IDE0018: Variable declaration can be inlined 41 | dotnet_diagnostic.IDE0018.severity = warning 42 | 43 | # SA1625: Element documenation should not be copied and pasted 44 | dotnet_diagnostic.SA1625.severity = none 45 | 46 | # IDE0005: Using directive is unnecessary 47 | dotnet_diagnostic.IDE0005.severity = warning 48 | 49 | # SA1117: Parameters should be on same line or separate lines 50 | dotnet_diagnostic.SA1117.severity = none 51 | 52 | # SA1404: Code analysis suppression should have justification 53 | dotnet_diagnostic.SA1404.severity = none 54 | 55 | # SA1101: Prefix local calls with this 56 | dotnet_diagnostic.SA1101.severity = none 57 | 58 | # SA1633: File should have header 59 | dotnet_diagnostic.SA1633.severity = none 60 | 61 | # SA1649: File name should match first type name 62 | dotnet_diagnostic.SA1649.severity = none 63 | 64 | # SA1402: File may only contain a single type 65 | dotnet_diagnostic.SA1402.severity = none 66 | 67 | # CA1814: Prefer jagged arrays over multidimensional 68 | dotnet_diagnostic.CA1814.severity = none 69 | 70 | # RCS1194: Implement exception constructors. 71 | dotnet_diagnostic.RCS1194.severity = none 72 | 73 | # CA1032: Implement standard exception constructors 74 | dotnet_diagnostic.CA1032.severity = none 75 | 76 | # CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly 77 | dotnet_diagnostic.CA1826.severity = none 78 | 79 | # RCS1079: Throwing of new NotImplementedException. 80 | dotnet_diagnostic.RCS1079.severity = warning 81 | 82 | # RCS1057: Add empty line between declarations. 83 | dotnet_diagnostic.RCS1057.severity = none 84 | 85 | # IDE0004: Remove Unnecessary Cast 86 | dotnet_diagnostic.IDE0004.severity = warning -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 10 5 | true 6 | embedded 7 | true 8 | true 9 | false 10 | 11 | 12 | 13 | true 14 | 15 | 16 | 17 | A library that makes it easy to create and display diagnostics of different kinds. 18 | Patrik Svensson, Phil Scott, James Randall 19 | Patrik Svensson, Phil Scott, James Randall 20 | git 21 | https://github.com/spectreconsole/errata 22 | small-logo.png 23 | True 24 | https://github.com/spectreconsole/errata 25 | MIT 26 | https://github.com/spectreconsole/errata/releases 27 | 28 | 29 | 30 | true 31 | true 32 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 33 | 34 | 35 | 36 | 37 | 38 | 39 | All 40 | 41 | 42 | All 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | preview.0 5 | normal 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Errata.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = false 2 | [*.cs] 3 | 4 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules' 5 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none 6 | 7 | # CA1707: Identifiers should not contain underscores 8 | dotnet_diagnostic.CA1707.severity = none 9 | 10 | # SA1600: Elements should be documented 11 | dotnet_diagnostic.SA1600.severity = none 12 | 13 | # SA1601: Partial elements should be documented 14 | dotnet_diagnostic.SA1601.severity = none 15 | 16 | # SA1200: Using directives should be placed correctly 17 | dotnet_diagnostic.SA1200.severity = none 18 | 19 | # CS1591: Missing XML comment for publicly visible type or member 20 | dotnet_diagnostic.CS1591.severity = none 21 | 22 | # SA1210: Using directives should be ordered alphabetically by namespace 23 | dotnet_diagnostic.SA1210.severity = none 24 | 25 | # CA1034: Nested types should not be visible 26 | dotnet_diagnostic.CA1034.severity = none 27 | 28 | # CA2000: Dispose objects before losing scope 29 | dotnet_diagnostic.CA2000.severity = none 30 | 31 | # SA1118: Parameter should not span multiple lines 32 | dotnet_diagnostic.SA1118.severity = none 33 | 34 | # CA1031: Do not catch general exception types 35 | dotnet_diagnostic.CA1031.severity = none -------------------------------------------------------------------------------- /src/Errata.Tests/CharacterSetTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace Errata.Tests; 5 | 6 | public sealed class CharacterSetTests 7 | { 8 | public sealed class Ansi 9 | { 10 | [Theory] 11 | [InlineData(Character.Anchor, '┬')] 12 | [InlineData(Character.AnchorHorizontalLine, '─')] 13 | [InlineData(Character.AnchorVerticalLine, '│')] 14 | [InlineData(Character.BottomLeftCornerHard, '└')] 15 | [InlineData(Character.BottomLeftCornerRound, '╰')] 16 | [InlineData(Character.Colon, ':')] 17 | [InlineData(Character.Dot, '·')] 18 | [InlineData(Character.HorizontalLine, '─')] 19 | [InlineData(Character.LeftConnector, '├')] 20 | [InlineData(Character.TopLeftCornerHard, '┌')] 21 | [InlineData(Character.VerticalLine, '│')] 22 | public void Should_Return_Expected_Characters(Character character, char expected) 23 | { 24 | // Given, When 25 | var result = CharacterSet.Unicode.Get(character); 26 | 27 | // Then 28 | result.ShouldBe(expected); 29 | } 30 | } 31 | 32 | public sealed class Ascii 33 | { 34 | [Theory] 35 | [InlineData(Character.Anchor, '┬')] 36 | [InlineData(Character.AnchorHorizontalLine, '─')] 37 | [InlineData(Character.AnchorVerticalLine, '│')] 38 | [InlineData(Character.BottomLeftCornerHard, '└')] 39 | [InlineData(Character.BottomLeftCornerRound, '└')] 40 | [InlineData(Character.Colon, ':')] 41 | [InlineData(Character.Dot, '·')] 42 | [InlineData(Character.HorizontalLine, '─')] 43 | [InlineData(Character.LeftConnector, '├')] 44 | [InlineData(Character.TopLeftCornerHard, '┌')] 45 | [InlineData(Character.VerticalLine, '│')] 46 | public void Should_Return_Expected_Characters(Character character, char expected) 47 | { 48 | // Given, When 49 | var result = CharacterSet.Ascii.Get(character); 50 | 51 | // Then 52 | result.ShouldBe(expected); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Errata.Tests/Data/Example.md: -------------------------------------------------------------------------------- 1 | # HELLO WORLD! 2 | 3 | This is jus an *example** file 4 | which is used by the Errata 5 | example application. 6 | 7 | Will be cool to see what this 8 | looks like once it's complete! 9 | 10 | Your failures are your own, old man! I say, follow throooough! 11 | And that's why I always say WUBBA LUBBA DUB DUB! 12 | Are you hungry for apples? ARE YOU HUNGRY FOR APPLESSS!? 13 | 14 | I mean, why would a poptart want to live inside a toaster, 15 | Rick? I mean, that would be like the scariest place for them to live. 16 | You know what I mean? Awwww thanks! Nice, Mrs Pancakes. 17 | Real nice. I'm Mr. Crowbar, and here is my friend, who is also a crowbar! 18 | 19 | / Patrik -------------------------------------------------------------------------------- /src/Errata.Tests/Data/Foo.cpp: -------------------------------------------------------------------------------- 1 | #include "foo.h" 2 | void Foo::bar(float) 3 | { 4 | } -------------------------------------------------------------------------------- /src/Errata.Tests/Data/Foo.h: -------------------------------------------------------------------------------- 1 | class Foo { 2 | public: 3 | void bar(int); 4 | }; -------------------------------------------------------------------------------- /src/Errata.Tests/Data/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Example.Files 8 | { 9 | public static class Program 10 | { 11 | public static void Main() 12 | { 13 | var foo = 1; 14 | var bar = "lol"; 15 | var qux = foo / bar; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Errata.Tests/Errata.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | all 26 | runtime; build; native; contentfiles; analyzers; buildtransitive 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Compact.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ ╰── This is of type 'string' 9 | · ╰───── Division is not possible 10 | │ 11 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/LabelPriority.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · │ ╰── This is of type 'string' 10 | · │ 11 | · ╰───── Division is not possible 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/LastCharacter.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error: This will fail 2 | ┌─[Example.md] 3 | │ 4 | 19 │ / Patrik 5 | · ┬ 6 | · ╰ Issue on last character of the line 7 | │ 8 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/LeftPadding.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · │ ╰── This is of type 'string' 10 | · │ 11 | · ╰───── Division is not possible 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Locations/LabelsWithMultipleFiles.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [C2084]: Compiler error 2 | NOTE: Overloaded member not found 3 | ┌─[Foo.cpp] 4 | │ 5 | 2 │ void Foo::bar(float) 6 | · ───────┬─────── 7 | · ╰─────── 'void Foo::bar(float)': overloaded member function not found in 'Foo' 8 | · 9 | · NOTE: See declaration of 'Foo' in Foo.h 10 | │ 11 | ├─[Foo.h] 12 | │ 13 | 3 │ void bar(int); 14 | · ───────┬────── 15 | · ╰────── See declaration of 'Foo' 16 | │ 17 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Locations/MultipleDiagnostics.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · ╰───── Division is not possible 10 | · │ 11 | · ╰── This is of type 'string' 12 | │ 13 | └─ 14 | 15 | Warning [IDE0055]: Fix formatting 16 | ┌─[Program.cs] 17 | │ 18 | 9 │ public static class Program 19 | · ─┬ 20 | · ╰ Code should not contain trailing whitespace 21 | │ 22 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Locations/MultipleLabels.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · ╰───── Division is not possible 10 | · │ 11 | · ╰── This is of type 'string' 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Locations/MultipleLabelsDifferentPriority.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · │ │ ╰── This is of type 'string' 8 | · │ │ 9 | · │ ╰───── Division is not possible 10 | · │ 11 | · ╰──────── This is of type 'int' 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Locations/SingleLabel.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [SPELLING001]: There are spelling errors 2 | ┌─[Example.md] 3 | │ 4 | 11 │ And that's why I always say WUBBA LUBBA DUB DUB! 5 | · ─────────┬───────── 6 | · ╰─────────── Did you mean 'Yabba dabba doo'? 7 | │ 8 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/ReportError.Output.verified.txt: -------------------------------------------------------------------------------- 1 | ┌─Errata Error─────────────────────────────────────────────────────────────────┐ 2 | │ An error occured when rendering a diagnostic. │ 3 | │ Message: Label row exceeded number of lines │ 4 | │ │ 5 | │ Diagnostic: │ 6 | │ Message: This will fail │ 7 | │ Category: Error │ 8 | │ Source: Example.md │ 9 | │ │ 10 | │ Context: │ 11 | │ Row: 20 │ 12 | │ Column: 7 │ 13 | │ Line count: 19 │ 14 | │ │ 15 | │ If you believe this is a bug in Errata, please submit an issue at │ 16 | │ https://github.com/spectreconsole/errata/issues/new │ 17 | └──────────────────────────────────────────────────────────────────────────────┘ 18 | 19 | Error: This will fail 20 | ┌─[Example.md] 21 | │ 22 | 19 │ / Patrik 23 | · ┬ 24 | · ╰ Issue on last character of the line 25 | │ 26 | └─ 27 | -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Rows/MultipleLabels.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ────────────────┬─────────────── 7 | · ╰─────────────── This is of type 'int' 8 | · │ 9 | · ╰─────────────── Division is not possible 10 | · │ 11 | · ╰─────────────── This is of type 'string' 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Rows/MultipleLabelsDifferentPriority.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ────────────────┬─────────────── 7 | · ╰─────────────── This is of type 'string' 8 | · │ 9 | · ╰─────────────── Division is not possible 10 | · │ 11 | · ╰─────────────── This is of type 'int' 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Rows/SingleLabel.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [SPELLING001]: There are spelling errors 2 | ┌─[Example.md] 3 | │ 4 | 11 │ And that's why I always say WUBBA LUBBA DUB DUB! 5 | · ────────────────────────┬──────────────────────── 6 | · ╰──────────────────────── Did you mean 'Yabba dabba doo'? 7 | │ 8 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Spans/LabelsWithMultipleFiles.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [C2084]: Compiler error 2 | NOTE: Overloaded member not found 3 | ┌─[Foo.cpp] 4 | │ 5 | 2 │ void Foo::bar(float) 6 | · ───────┬─────── 7 | · ╰─────── 'void Foo::bar(float)': overloaded member function not found in 'Foo' 8 | · 9 | · NOTE: See declaration of 'Foo' in Foo.h 10 | │ 11 | ├─[Foo.h] 12 | │ 13 | 3 │ void bar(int); 14 | · ───────┬────── 15 | · ╰────── See declaration of 'Foo' 16 | │ 17 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Spans/MultipleDiagnostics.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · ╰───── Division is not possible 10 | · │ 11 | · ╰── This is of type 'string' 12 | │ 13 | └─ 14 | 15 | Warning [IDE0055]: Fix formatting 16 | ┌─[Program.cs] 17 | │ 18 | 9 │ public static class Program 19 | · ─┬ 20 | · ╰ Code should not contain trailing whitespace 21 | │ 22 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Spans/MultipleLabels.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [CS0019]: Operator '/' cannot be applied to operands of type 'string' and 'int' 2 | NOTE: Try changing the type 3 | ┌─[Program.cs] 4 | │ 5 | 15 │ var qux = foo / bar; 6 | · ─┬─ ┬ ─┬─ 7 | · ╰──────── This is of type 'int' 8 | · │ │ 9 | · ╰───── Division is not possible 10 | · │ 11 | · ╰── This is of type 'string' 12 | │ 13 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/Expectations/Report/Rendering/Spans/SingleLabel.Output.verified.txt: -------------------------------------------------------------------------------- 1 | Error [SPELLING001]: There are spelling errors 2 | ┌─[Example.md] 3 | │ 4 | 11 │ And that's why I always say WUBBA LUBBA DUB DUB! 5 | · ─────────┬───────── 6 | · ╰─────────── Did you mean 'Yabba dabba doo'? 7 | │ 8 | └─ -------------------------------------------------------------------------------- /src/Errata.Tests/LabelTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace Errata.Tests; 5 | 6 | public sealed class LabelTests 7 | { 8 | public sealed class TheWithNoteMethod 9 | { 10 | [Fact] 11 | public void Should_Set_Note_To_Provided_Value() 12 | { 13 | // Given 14 | var label = new Label("Program.cs", new Location(1, 2), "The message"); 15 | 16 | // When 17 | label.WithNote("The note"); 18 | 19 | // Then 20 | label.Note.ShouldBe("The note"); 21 | } 22 | 23 | [Fact] 24 | public void Should_Set_Note_To_Null_If_Null_Is_Provided() 25 | { 26 | // Given 27 | var label = new Label("Program.cs", new Location(1, 2), "The message"); 28 | label.WithNote("The Note"); 29 | 30 | // When 31 | label.WithNote(null); 32 | 33 | // Then 34 | label.Note.ShouldBeNull(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Errata.Tests/Properties/VerifyConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using VerifyTests; 3 | using VerifyXunit; 4 | 5 | namespace Errata.Tests; 6 | 7 | public static class VerifyConfiguration 8 | { 9 | [ModuleInitializer] 10 | public static void Init() 11 | { 12 | Verifier.DerivePathInfo(Expectations.Initialize); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Errata.Tests/ReportTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Spectre.Console; 3 | using Spectre.Console.Testing; 4 | using VerifyTests; 5 | using VerifyXunit; 6 | using Xunit; 7 | 8 | namespace Errata.Tests; 9 | 10 | [ExpectationPath("Report")] 11 | public sealed class ReportTests 12 | { 13 | [ExpectationPath("Rendering")] 14 | public sealed class TheRenderMethod 15 | { 16 | [ExpectationPath("Spans")] 17 | public sealed class UsingSpans 18 | { 19 | [Fact] 20 | [Expectation("SingleLabel")] 21 | public Task Should_Render_Diagnostic_With_Single_Label_Correctly() 22 | { 23 | // Given 24 | var console = new TestConsole().Width(80); 25 | var report = new Report(new EmbeddedResourceRepository()); 26 | 27 | report.AddDiagnostic( 28 | Diagnostic.Error("There are spelling errors") 29 | .WithCode("SPELLING001") 30 | .WithLabel(new Label("Example.md", 251..270, "Did you mean 'Yabba dabba doo'?").WithColor(Color.Red))); 31 | 32 | // When 33 | report.Render(console); 34 | 35 | // Then 36 | return Verifier.Verify(console.Output); 37 | } 38 | 39 | [Fact] 40 | [Expectation("MultipleLabels")] 41 | public Task Should_Render_Diagnostic_With_Multiple_Labels_Correctly() 42 | { 43 | // Given 44 | var console = new TestConsole().Width(80); 45 | var report = new Report(new EmbeddedResourceRepository()); 46 | 47 | report.AddDiagnostic( 48 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 49 | .WithCode("CS0019") 50 | .WithNote("Try changing the type") 51 | .WithLabel(new Label("Program.cs", 303..306, "This is of type 'int'").WithColor(Color.Yellow)) 52 | .WithLabel(new Label("Program.cs", 307..308, "Division is not possible").WithColor(Color.Red)) 53 | .WithLabel(new Label("Program.cs", 309..312, "This is of type 'string'").WithColor(Color.Blue))); 54 | 55 | // When 56 | report.Render(console); 57 | 58 | // Then 59 | return Verifier.Verify(console.Output); 60 | } 61 | 62 | [Fact] 63 | [Expectation("LabelsWithMultipleFiles")] 64 | public Task Should_Render_Diagnostic_With_Multiple_Labels_In_Multiple_Files_Correctly() 65 | { 66 | // Given 67 | var console = new TestConsole().Width(80); 68 | var report = new Report(new EmbeddedResourceRepository()); 69 | 70 | report.AddDiagnostic( 71 | Diagnostic.Error("Compiler error") 72 | .WithCode("C2084") 73 | .WithNote("Overloaded member not found") 74 | .WithLabel(new Label("Foo.cpp", 22..37, " 'void Foo::bar(float)': overloaded member function not found in 'Foo'") 75 | .WithColor(Color.Red).WithNote("See declaration of 'Foo' in Foo.h")) 76 | .WithLabel(new Label("Foo.h", 24..38, "See declaration of 'Foo'").WithColor(Color.Blue))); 77 | 78 | // When 79 | report.Render(console); 80 | 81 | // Then 82 | return Verifier.Verify(console.Output); 83 | } 84 | 85 | [Fact] 86 | [Expectation("MultipleDiagnostics")] 87 | public Task Should_Render_Multiple_Diagnostics_Correctly() 88 | { 89 | // Given 90 | var console = new TestConsole().Width(80); 91 | var report = new Report(new EmbeddedResourceRepository()); 92 | 93 | report.AddDiagnostic( 94 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 95 | .WithCode("CS0019") 96 | .WithNote("Try changing the type") 97 | .WithLabel(new Label("Program.cs", 303..306, "This is of type 'int'").WithColor(Color.Yellow)) 98 | .WithLabel(new Label("Program.cs", 307..308, "Division is not possible").WithColor(Color.Red)) 99 | .WithLabel(new Label("Program.cs", 309..312, "This is of type 'string'").WithColor(Color.Blue))); 100 | 101 | report.AddDiagnostic( 102 | Diagnostic.Warning("Fix formatting") 103 | .WithCode("IDE0055")) 104 | .WithLabel(new Label("Program.cs", 174..176, "Code should not contain trailing whitespace").WithColor(Color.Yellow)); 105 | 106 | // When 107 | report.Render(console); 108 | 109 | // Then 110 | return Verifier.Verify(console.Output); 111 | } 112 | } 113 | 114 | [ExpectationPath("Locations")] 115 | public sealed class UsingLocations 116 | { 117 | [Fact] 118 | [Expectation("SingleLabel")] 119 | public Task Should_Render_Diagnostic_With_Single_Label_Correctly() 120 | { 121 | // Given 122 | var console = new TestConsole().Width(80); 123 | var report = new Report(new EmbeddedResourceRepository()); 124 | 125 | report.AddDiagnostic( 126 | Diagnostic.Error("There are spelling errors") 127 | .WithCode("SPELLING001") 128 | .WithLabel(new Label("Example.md", new Location(11, 29), "Did you mean 'Yabba dabba doo'?") 129 | .WithColor(Color.Red) 130 | .WithLength(19))); 131 | 132 | // When 133 | report.Render(console); 134 | 135 | // Then 136 | return Verifier.Verify(console.Output); 137 | } 138 | 139 | [Fact] 140 | [Expectation("MultipleLabels")] 141 | public Task Should_Render_Diagnostic_With_Multiple_Labels_Correctly() 142 | { 143 | // Given 144 | var console = new TestConsole().Width(80); 145 | var report = new Report(new EmbeddedResourceRepository()); 146 | 147 | report.AddDiagnostic( 148 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 149 | .WithCode("CS0019") 150 | .WithNote("Try changing the type") 151 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 152 | .WithColor(Color.Yellow).WithLength(3)) 153 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 154 | .WithColor(Color.Red).WithLength(1)) 155 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 156 | .WithColor(Color.Blue).WithLength(3))); 157 | 158 | // When 159 | report.Render(console); 160 | 161 | // Then 162 | return Verifier.Verify(console.Output); 163 | } 164 | 165 | [Fact] 166 | [Expectation("MultipleLabelsDifferentPriority")] 167 | public Task Should_Render_Diagnostic_With_Multiple_Labels_With_Different_Priority_Correctly() 168 | { 169 | // Given 170 | var console = new TestConsole().Width(80); 171 | var report = new Report(new EmbeddedResourceRepository()); 172 | 173 | report.AddDiagnostic( 174 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 175 | .WithCode("CS0019") 176 | .WithNote("Try changing the type") 177 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 178 | .WithColor(Color.Yellow).WithLength(3).WithPriority(3)) 179 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 180 | .WithColor(Color.Red).WithLength(1).WithPriority(2)) 181 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 182 | .WithColor(Color.Blue).WithLength(3).WithPriority(1))); 183 | 184 | // When 185 | report.Render(console); 186 | 187 | // Then 188 | return Verifier.Verify(console.Output); 189 | } 190 | 191 | [Fact] 192 | [Expectation("LabelsWithMultipleFiles")] 193 | public Task Should_Render_Diagnostic_With_Multiple_Labels_In_Multiple_Files_Correctly() 194 | { 195 | // Given 196 | var console = new TestConsole().Width(80); 197 | var report = new Report(new EmbeddedResourceRepository()); 198 | 199 | report.AddDiagnostic( 200 | Diagnostic.Error("Compiler error") 201 | .WithCode("C2084") 202 | .WithNote("Overloaded member not found") 203 | .WithLabel(new Label("Foo.cpp", new Location(2, 6), "'void Foo::bar(float)': overloaded member function not found in 'Foo'") 204 | .WithLength(15) 205 | .WithColor(Color.Red) 206 | .WithNote("See declaration of 'Foo' in Foo.h")) 207 | .WithLabel(new Label("Foo.h", new Location(3, 5), "See declaration of 'Foo'") 208 | .WithLength(14) 209 | .WithColor(Color.Blue))); 210 | 211 | // When 212 | report.Render(console); 213 | 214 | // Then 215 | return Verifier.Verify(console.Output); 216 | } 217 | 218 | [Fact] 219 | [Expectation("MultipleDiagnostics")] 220 | public Task Should_Render_Multiple_Diagnostics_Correctly() 221 | { 222 | // Given 223 | var console = new TestConsole().Width(80); 224 | var report = new Report(new EmbeddedResourceRepository()); 225 | 226 | report.AddDiagnostic( 227 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 228 | .WithCode("CS0019") 229 | .WithNote("Try changing the type") 230 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 231 | .WithColor(Color.Yellow).WithLength(3)) 232 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 233 | .WithColor(Color.Red).WithLength(1)) 234 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 235 | .WithColor(Color.Blue).WithLength(3))); 236 | 237 | report.AddDiagnostic( 238 | Diagnostic.Warning("Fix formatting") 239 | .WithCode("IDE0055")) 240 | .WithLabel(new Label("Program.cs", new Location(9, 32), "Code should not contain trailing whitespace") 241 | .WithLength(2) 242 | .WithColor(Color.Yellow)); 243 | 244 | // When 245 | report.Render(console); 246 | 247 | // Then 248 | return Verifier.Verify(console.Output); 249 | } 250 | } 251 | 252 | [ExpectationPath("Rows")] 253 | public sealed class UsingLocationRows 254 | { 255 | [Fact] 256 | [Expectation("SingleLabel")] 257 | public Task Should_Render_Diagnostic_With_Single_Label_Correctly() 258 | { 259 | // Given 260 | var console = new TestConsole().Width(80); 261 | var report = new Report(new EmbeddedResourceRepository()); 262 | 263 | report.AddDiagnostic( 264 | Diagnostic.Error("There are spelling errors") 265 | .WithCode("SPELLING001") 266 | .WithLabel(new Label("Example.md", new Location(11), "Did you mean 'Yabba dabba doo'?") 267 | .WithColor(Color.Red))); 268 | 269 | // When 270 | report.Render(console); 271 | 272 | // Then 273 | return Verifier.Verify(console.Output); 274 | } 275 | 276 | [Fact] 277 | [Expectation("MultipleLabels")] 278 | public Task Should_Render_Diagnostic_With_Multiple_Labels_Correctly() 279 | { 280 | // Given 281 | var console = new TestConsole().Width(80); 282 | var report = new Report(new EmbeddedResourceRepository()); 283 | 284 | report.AddDiagnostic( 285 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 286 | .WithCode("CS0019") 287 | .WithNote("Try changing the type") 288 | .WithLabel(new Label("Program.cs", new Location(15), "This is of type 'int'") 289 | .WithColor(Color.Yellow)) 290 | .WithLabel(new Label("Program.cs", new Location(15), "Division is not possible") 291 | .WithColor(Color.Red)) 292 | .WithLabel(new Label("Program.cs", new Location(15), "This is of type 'string'") 293 | .WithColor(Color.Blue))); 294 | 295 | // When 296 | report.Render(console); 297 | 298 | // Then 299 | return Verifier.Verify(console.Output); 300 | } 301 | 302 | [Fact] 303 | [Expectation("MultipleLabelsDifferentPriority")] 304 | public Task Should_Render_Diagnostic_With_Multiple_Labels_With_Different_Priority_Correctly() 305 | { 306 | // Given 307 | var console = new TestConsole().Width(80); 308 | var report = new Report(new EmbeddedResourceRepository()); 309 | 310 | report.AddDiagnostic( 311 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 312 | .WithCode("CS0019") 313 | .WithNote("Try changing the type") 314 | .WithLabel(new Label("Program.cs", new Location(15), "This is of type 'int'") 315 | .WithColor(Color.Yellow).WithPriority(3)) 316 | .WithLabel(new Label("Program.cs", new Location(15), "Division is not possible") 317 | .WithColor(Color.Red).WithPriority(2)) 318 | .WithLabel(new Label("Program.cs", new Location(15), "This is of type 'string'") 319 | .WithColor(Color.Blue).WithPriority(1))); 320 | 321 | // When 322 | report.Render(console); 323 | 324 | // Then 325 | return Verifier.Verify(console.Output); 326 | } 327 | } 328 | 329 | [Fact] 330 | [Expectation("LabelPriority")] 331 | public Task Should_Render_Labels_With_Priority_Correctly() 332 | { 333 | // Given 334 | var console = new TestConsole().Width(80); 335 | var report = new Report(new EmbeddedResourceRepository()); 336 | 337 | report.AddDiagnostic( 338 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 339 | .WithCode("CS0019") 340 | .WithNote("Try changing the type") 341 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 342 | .WithColor(Color.Yellow).WithLength(3).WithPriority(1)) 343 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 344 | .WithColor(Color.Red).WithLength(1).WithPriority(3)) 345 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 346 | .WithColor(Color.Blue).WithLength(3).WithPriority(2))); 347 | 348 | // When 349 | report.Render(console); 350 | 351 | // Then 352 | return Verifier.Verify(console.Output); 353 | } 354 | 355 | [Fact] 356 | [Expectation("Compact")] 357 | public Task Should_Render_Compact_Labels_Correctly() 358 | { 359 | // Given 360 | var console = new TestConsole().Width(80); 361 | var report = new Report(new EmbeddedResourceRepository()); 362 | 363 | report.AddDiagnostic( 364 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 365 | .WithCode("CS0019") 366 | .WithNote("Try changing the type") 367 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 368 | .WithColor(Color.Yellow).WithLength(3).WithPriority(1)) 369 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 370 | .WithColor(Color.Red).WithLength(1).WithPriority(3)) 371 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 372 | .WithColor(Color.Blue).WithLength(3).WithPriority(2))); 373 | 374 | // When 375 | report.Render(console, new ReportSettings 376 | { 377 | Compact = true, 378 | }); 379 | 380 | // Then 381 | return Verifier.Verify(console.Output); 382 | } 383 | 384 | [Fact] 385 | [Expectation("LeftPadding")] 386 | public Task Should_Render_Without_Left_Padding_Correctly() 387 | { 388 | // Given 389 | var console = new TestConsole().Width(80); 390 | var report = new Report(new EmbeddedResourceRepository()); 391 | 392 | report.AddDiagnostic( 393 | Diagnostic.Error("Operator '/' cannot be applied to operands of type 'string' and 'int'") 394 | .WithCode("CS0019") 395 | .WithNote("Try changing the type") 396 | .WithLabel(new Label("Program.cs", new Location(15, 23), "This is of type 'int'") 397 | .WithColor(Color.Yellow).WithLength(3).WithPriority(1)) 398 | .WithLabel(new Label("Program.cs", new Location(15, 27), "Division is not possible") 399 | .WithColor(Color.Red).WithLength(1).WithPriority(3)) 400 | .WithLabel(new Label("Program.cs", new Location(15, 29), "This is of type 'string'") 401 | .WithColor(Color.Blue).WithLength(3).WithPriority(2))); 402 | 403 | // When 404 | report.Render(console, new ReportSettings 405 | { 406 | LeftPadding = false, 407 | }); 408 | 409 | // Then 410 | return Verifier.Verify(console.Output); 411 | } 412 | 413 | [Fact] 414 | [Expectation("LastCharacter")] 415 | [GitHubIssue(9)] 416 | [GitHubIssue(10)] 417 | public Task Should_Render_Label_For_Last_Character_Of_A_Line_Correctly() 418 | { 419 | // Given 420 | var console = new TestConsole().Width(80); 421 | var report = new Report(new EmbeddedResourceRepository()); 422 | report.AddDiagnostic( 423 | Diagnostic.Error("This will fail") 424 | .WithLabel(new Label("Example.md", new Location(19, 8), "Issue on last character of the line") 425 | .WithColor(Color.Yellow) 426 | .WithLength(1))); 427 | 428 | // When 429 | report.Render(console); 430 | 431 | // Then 432 | return Verifier.Verify(console.Output); 433 | } 434 | 435 | [Fact] 436 | [Expectation("ReportError")] 437 | [GitHubIssue(8)] 438 | public Task Should_Render_Errata_Errors_Correctly() 439 | { 440 | // Given 441 | var console = new TestConsole().Width(80); 442 | var report = new Report(new EmbeddedResourceRepository()); 443 | report.AddDiagnostic( 444 | Diagnostic.Error("This will fail") 445 | .WithLabel(new Label("Example.md", new Location(19, 8), "Issue on last character of the line") 446 | .WithColor(Color.Yellow) 447 | .WithLength(1))); 448 | 449 | report.AddDiagnostic( 450 | Diagnostic.Error("This will fail") 451 | .WithLabel(new Label("Example.md", new Location(21, 8), "This is an error") 452 | .WithColor(Color.Yellow) 453 | .WithLength(1))); 454 | 455 | // When 456 | report.Render(console, new ReportSettings 457 | { 458 | ExcludeStackTrace = true, 459 | }); 460 | 461 | // Then 462 | return Verifier.Verify(console.Output); 463 | } 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /src/Errata.Tests/SourceTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace Errata.Tests; 5 | 6 | public sealed class SourceTests 7 | { 8 | [Fact] 9 | public void Should_Return_Correct_Length() 10 | { 11 | // Given 12 | var source = new Source("Program.cs", "public void Main()\n{\n\tConsole.WriteLine(\"Hello\")\n}"); 13 | 14 | // When 15 | var result = source.Length; 16 | 17 | // Then 18 | result.ShouldBe(50); 19 | } 20 | 21 | [Fact] 22 | public void Should_Return_Correct_Text() 23 | { 24 | // Given 25 | var source = new Source("Program.cs", "public void Main()\n{\n\tConsole.WriteLine(\"Hello\")\n}"); 26 | 27 | // When 28 | var (line, _, _) = source.GetLineOffset(22); 29 | 30 | // Then 31 | line.Text.ShouldBe("\tConsole.WriteLine(\"Hello\")"); 32 | } 33 | 34 | [Fact] 35 | public void Should_Return_Correct_Row() 36 | { 37 | // Given 38 | var source = new Source("Program.cs", "public void Main()\n{\n\tConsole.WriteLine(\"Hello\")\n}"); 39 | 40 | // When 41 | var (_, row, _) = source.GetLineOffset(22); 42 | 43 | // Then 44 | row.ShouldBe(2); 45 | } 46 | 47 | [Fact] 48 | public void Should_Return_Correct_Column() 49 | { 50 | // Given 51 | var source = new Source("Program.cs", "public void Main()\n{\n\tConsole.WriteLine(\"Hello\")\n}"); 52 | 53 | // When 54 | var (_, _, column) = source.GetLineOffset(22); 55 | 56 | // Then 57 | column.ShouldBe(1); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Errata.Tests/TextLineTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace Errata.Tests; 5 | 6 | public sealed class TextLineTests 7 | { 8 | [Fact] 9 | public void Should_Split_Lines_Correctly() 10 | { 11 | // Given, When 12 | var lines = TextLine.Split("Hello\nWorld\r\n!"); 13 | 14 | // Then 15 | lines.Count.ShouldBe(3); 16 | lines[0].Text.ShouldBe("Hello"); 17 | lines[1].Text.ShouldBe("World"); 18 | lines[2].Text.ShouldBe("!"); 19 | } 20 | 21 | [Fact] 22 | public void Should_Split_Lines_Starting_With_Line_Break_Correctly() 23 | { 24 | // Given, When 25 | var lines = TextLine.Split("\nHello\nWorld\r\n!"); 26 | 27 | // Then 28 | lines.Count.ShouldBe(4); 29 | lines[0].Text.ShouldBeEmpty(); 30 | lines[1].Text.ShouldBe("Hello"); 31 | lines[2].Text.ShouldBe("World"); 32 | lines[3].Text.ShouldBe("!"); 33 | } 34 | 35 | [Fact] 36 | public void Should_Return_Correct_Index() 37 | { 38 | // Given, When 39 | var span = new TextLine(12, "HELLO WORLD", 13); 40 | 41 | // Then 42 | span.Index.ShouldBe(12); 43 | } 44 | 45 | [Fact] 46 | public void Should_Return_Correct_Text() 47 | { 48 | // Given, When 49 | var span = new TextLine(0, "HELLO WORLD", 13); 50 | 51 | // Then 52 | span.Text.ShouldBe("HELLO WORLD"); 53 | } 54 | 55 | [Fact] 56 | public void Should_Return_Correct_Offset() 57 | { 58 | // Given, When 59 | var span = new TextLine(0, "HELLO WORLD", 13); 60 | 61 | // Then 62 | span.Offset.ShouldBe(13); 63 | } 64 | 65 | [Fact] 66 | public void Should_Return_Correct_Length() 67 | { 68 | // Given, When 69 | var span = new TextLine(0, "HELLO WORLD", 13); 70 | 71 | // Then 72 | span.Length.ShouldBe(11); 73 | } 74 | 75 | [Fact] 76 | public void Should_Return_Correct_Range() 77 | { 78 | // Given, When 79 | var span = new TextLine(0, "HELLO WORLD", 13); 80 | 81 | // Then 82 | span.Span.Start.ShouldBe(13); 83 | span.Span.End.ShouldBe(24); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Errata.Tests/TextSpanTests.cs: -------------------------------------------------------------------------------- 1 | using Shouldly; 2 | using Xunit; 3 | 4 | namespace Errata.Tests; 5 | 6 | public sealed class TextSpanTests 7 | { 8 | [Fact] 9 | public void Should_Return_Correct_Start_Position() 10 | { 11 | // Given, When 12 | var span = new TextSpan(13, 19); 13 | 14 | // Then 15 | span.Start.ShouldBe(13); 16 | } 17 | 18 | [Fact] 19 | public void Should_Return_Correct_End_Position() 20 | { 21 | // Given, When 22 | var span = new TextSpan(13, 19); 23 | 24 | // Then 25 | span.End.ShouldBe(19); 26 | } 27 | 28 | [Fact] 29 | public void Should_Return_Correct_Length() 30 | { 31 | // Given, When 32 | var span = new TextSpan(13, 19); 33 | 34 | // Then 35 | span.Length.ShouldBe(6); 36 | } 37 | 38 | public sealed class TheContainsMethod 39 | { 40 | [Theory] 41 | [InlineData(10)] 42 | [InlineData(15)] 43 | [InlineData(19)] 44 | public void Should_Return_True_If_Span_Contains_Offset(int offset) 45 | { 46 | // Given 47 | var span = new TextSpan(10, 20); 48 | 49 | // When 50 | var result = span.Contains(offset); 51 | 52 | // Then 53 | result.ShouldBeTrue(); 54 | } 55 | 56 | [Theory] 57 | [InlineData(9)] 58 | [InlineData(20)] 59 | public void Should_Return_False_If_Span_Do_Not_Contain_Offset(int offset) 60 | { 61 | // Given 62 | var span = new TextSpan(10, 20); 63 | 64 | // When 65 | var result = span.Contains(offset); 66 | 67 | // Then 68 | result.ShouldBeFalse(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Errata.Tests/Utilities/EmbeddedResourceReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | 5 | namespace Errata.Tests; 6 | 7 | public static class EmbeddedResourceReader 8 | { 9 | public static Stream LoadResourceStream(string resourceName) 10 | { 11 | if (resourceName is null) 12 | { 13 | throw new ArgumentNullException(nameof(resourceName)); 14 | } 15 | 16 | var assembly = typeof(EmbeddedResourceRepository).Assembly; 17 | resourceName = resourceName.Replace("/", "."); 18 | 19 | return assembly.GetManifestResourceStream(resourceName); 20 | } 21 | 22 | public static Stream LoadResourceStream(Assembly assembly, string resourceName) 23 | { 24 | if (assembly is null) 25 | { 26 | throw new ArgumentNullException(nameof(assembly)); 27 | } 28 | 29 | if (resourceName is null) 30 | { 31 | throw new ArgumentNullException(nameof(resourceName)); 32 | } 33 | 34 | resourceName = resourceName.Replace("/", "."); 35 | return assembly.GetManifestResourceStream(resourceName); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Errata.Tests/Utilities/EmbeddedResourceRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.IO; 5 | 6 | namespace Errata.Tests; 7 | 8 | public sealed class EmbeddedResourceRepository : ISourceRepository 9 | { 10 | private readonly Dictionary _lookup; 11 | 12 | public EmbeddedResourceRepository() 13 | { 14 | _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase); 15 | } 16 | 17 | public bool TryGet(string id, [NotNullWhen(true)] out Source source) 18 | { 19 | if (!_lookup.TryGetValue(id, out source)) 20 | { 21 | using (var stream = EmbeddedResourceReader.LoadResourceStream($"Errata.Tests/Data/{id}")) 22 | using (var reader = new StreamReader(stream)) 23 | { 24 | source = new Source(id, reader.ReadToEnd().Replace("\r\n", "\n")); 25 | _lookup[id] = source; 26 | } 27 | } 28 | 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Errata.Tests/Utilities/GitHubIssueAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Errata.Tests; 4 | 5 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 6 | public sealed class GitHubIssueAttribute : Attribute 7 | { 8 | public int Issue { get; set; } 9 | 10 | public GitHubIssueAttribute(int issue) 11 | { 12 | Issue = issue; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Errata.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31515.178 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Errata", "Errata\Errata.csproj", "{97277350-2069-4863-B0DE-07E929629958}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Errata.Tests", "Errata.Tests\Errata.Tests.csproj", "{A90C8C46-58DF-41B8-B273-B24396E8424C}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{FE3DAEB7-4C57-48B8-ADFB-74D429CD05DE}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9C3DA7B2-0055-453E-BFF7-F4D24B438433}" 13 | ProjectSection(SolutionItems) = preProject 14 | .editorconfig = .editorconfig 15 | Directory.Build.props = Directory.Build.props 16 | Directory.Build.targets = Directory.Build.targets 17 | EndProjectSection 18 | EndProject 19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "..\examples\Shared\Shared.csproj", "{8C92F934-B9E6-498A-AC30-0E37559CB8C7}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "..\examples\Demo\Demo.csproj", "{16FB1949-2CB4-48E7-835A-BFFF3B28DA35}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Debug|x64 = Debug|x64 27 | Debug|x86 = Debug|x86 28 | Release|Any CPU = Release|Any CPU 29 | Release|x64 = Release|x64 30 | Release|x86 = Release|x86 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {97277350-2069-4863-B0DE-07E929629958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {97277350-2069-4863-B0DE-07E929629958}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {97277350-2069-4863-B0DE-07E929629958}.Debug|x64.ActiveCfg = Debug|Any CPU 36 | {97277350-2069-4863-B0DE-07E929629958}.Debug|x64.Build.0 = Debug|Any CPU 37 | {97277350-2069-4863-B0DE-07E929629958}.Debug|x86.ActiveCfg = Debug|Any CPU 38 | {97277350-2069-4863-B0DE-07E929629958}.Debug|x86.Build.0 = Debug|Any CPU 39 | {97277350-2069-4863-B0DE-07E929629958}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {97277350-2069-4863-B0DE-07E929629958}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {97277350-2069-4863-B0DE-07E929629958}.Release|x64.ActiveCfg = Release|Any CPU 42 | {97277350-2069-4863-B0DE-07E929629958}.Release|x64.Build.0 = Release|Any CPU 43 | {97277350-2069-4863-B0DE-07E929629958}.Release|x86.ActiveCfg = Release|Any CPU 44 | {97277350-2069-4863-B0DE-07E929629958}.Release|x86.Build.0 = Release|Any CPU 45 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|x64.ActiveCfg = Debug|Any CPU 48 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|x64.Build.0 = Debug|Any CPU 49 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|x86.ActiveCfg = Debug|Any CPU 50 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Debug|x86.Build.0 = Debug|Any CPU 51 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|x64.ActiveCfg = Release|Any CPU 54 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|x64.Build.0 = Release|Any CPU 55 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|x86.ActiveCfg = Release|Any CPU 56 | {A90C8C46-58DF-41B8-B273-B24396E8424C}.Release|x86.Build.0 = Release|Any CPU 57 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 58 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 59 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|x64.ActiveCfg = Debug|Any CPU 60 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|x64.Build.0 = Debug|Any CPU 61 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|x86.ActiveCfg = Debug|Any CPU 62 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Debug|x86.Build.0 = Debug|Any CPU 63 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 64 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|Any CPU.Build.0 = Release|Any CPU 65 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|x64.ActiveCfg = Release|Any CPU 66 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|x64.Build.0 = Release|Any CPU 67 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|x86.ActiveCfg = Release|Any CPU 68 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7}.Release|x86.Build.0 = Release|Any CPU 69 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 70 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|Any CPU.Build.0 = Debug|Any CPU 71 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|x64.ActiveCfg = Debug|Any CPU 72 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|x64.Build.0 = Debug|Any CPU 73 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|x86.ActiveCfg = Debug|Any CPU 74 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Debug|x86.Build.0 = Debug|Any CPU 75 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|Any CPU.ActiveCfg = Release|Any CPU 76 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|Any CPU.Build.0 = Release|Any CPU 77 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|x64.ActiveCfg = Release|Any CPU 78 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|x64.Build.0 = Release|Any CPU 79 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|x86.ActiveCfg = Release|Any CPU 80 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35}.Release|x86.Build.0 = Release|Any CPU 81 | EndGlobalSection 82 | GlobalSection(SolutionProperties) = preSolution 83 | HideSolutionNode = FALSE 84 | EndGlobalSection 85 | GlobalSection(NestedProjects) = preSolution 86 | {8C92F934-B9E6-498A-AC30-0E37559CB8C7} = {FE3DAEB7-4C57-48B8-ADFB-74D429CD05DE} 87 | {16FB1949-2CB4-48E7-835A-BFFF3B28DA35} = {FE3DAEB7-4C57-48B8-ADFB-74D429CD05DE} 88 | EndGlobalSection 89 | GlobalSection(ExtensibilityGlobals) = postSolution 90 | SolutionGuid = {91DC3E44-F01D-459A-A956-418FE23E6723} 91 | EndGlobalSection 92 | EndGlobal 93 | -------------------------------------------------------------------------------- /src/Errata/Character.cs: -------------------------------------------------------------------------------- 1 | namespace Errata; 2 | 3 | /// 4 | /// Represents a renderable character. 5 | /// 6 | public enum Character 7 | { 8 | /// 9 | /// Represents `:`. 10 | /// 11 | Colon, 12 | 13 | /// 14 | /// Represents `┌`. 15 | /// 16 | TopLeftCornerHard, 17 | 18 | /// 19 | /// Represents `└`. 20 | /// 21 | BottomLeftCornerHard, 22 | 23 | /// 24 | /// Represents `├`. 25 | /// 26 | LeftConnector, 27 | 28 | /// 29 | /// Represents `─`. 30 | /// 31 | HorizontalLine, 32 | 33 | /// 34 | /// Represents `│`. 35 | /// 36 | VerticalLine, 37 | 38 | /// 39 | /// Represents `·`. 40 | /// 41 | Dot, 42 | 43 | /// 44 | /// Represents `┬`. 45 | /// 46 | Anchor, 47 | 48 | /// 49 | /// Represents `─`. 50 | /// 51 | AnchorHorizontalLine, 52 | 53 | /// 54 | /// Represents `│`. 55 | /// 56 | AnchorVerticalLine, 57 | 58 | /// 59 | /// Represents `╰`. 60 | /// 61 | BottomLeftCornerRound, 62 | } 63 | -------------------------------------------------------------------------------- /src/Errata/CharacterSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Spectre.Console; 3 | 4 | namespace Errata; 5 | 6 | /// 7 | /// Represents a character set. 8 | /// 9 | public abstract class CharacterSet 10 | { 11 | /// 12 | /// Gets a renderable representation of `:`. 13 | /// 14 | public virtual char Colon { get; } = ':'; 15 | 16 | /// 17 | /// Gets a renderable representation of `┌`. 18 | /// 19 | public virtual char TopLeftCornerHard { get; } = '┌'; 20 | 21 | /// 22 | /// Gets a renderable representation of `└`. 23 | /// 24 | public virtual char BottomLeftCornerHard { get; } = '└'; 25 | 26 | /// 27 | /// Gets a renderable representation of `├`. 28 | /// 29 | public virtual char LeftConnector { get; } = '├'; 30 | 31 | /// 32 | /// Gets a renderable representation of `─`. 33 | /// 34 | public virtual char HorizontalLine { get; } = '─'; 35 | 36 | /// 37 | /// Gets a renderable representation of `│`. 38 | /// 39 | public virtual char VerticalLine { get; } = '│'; 40 | 41 | /// 42 | /// Gets a renderable representation of `·`. 43 | /// 44 | public virtual char Dot { get; } = '·'; 45 | 46 | /// 47 | /// Gets a renderable representation of `┬`. 48 | /// 49 | public virtual char Anchor { get; } = '┬'; 50 | 51 | /// 52 | /// Gets a renderable representation of `─`. 53 | /// 54 | public virtual char AnchorHorizontalLine { get; } = '─'; 55 | 56 | /// 57 | /// Gets a renderable representation of `│`. 58 | /// 59 | public virtual char AnchorVerticalLine { get; } = '│'; 60 | 61 | /// 62 | /// Gets a renderable representation of `╰`. 63 | /// 64 | public virtual char BottomLeftCornerRound { get; } = '╰'; 65 | 66 | /// 67 | /// Gets a Unicode compatible character set. 68 | /// 69 | public static UnicodeCharacterSet Unicode => UnicodeCharacterSet.Shared; 70 | 71 | /// 72 | /// Gets an ASCII compatible character set. 73 | /// 74 | public static AsciiCharacterSet Ascii => AsciiCharacterSet.Shared; 75 | 76 | /// 77 | /// Gets a renderable representation of a . 78 | /// 79 | /// The character to get a renderable representation of. 80 | /// A renderable representation of a . 81 | public char Get(Character character) 82 | { 83 | return character switch 84 | { 85 | Character.Colon => Colon, 86 | Character.TopLeftCornerHard => TopLeftCornerHard, 87 | Character.BottomLeftCornerHard => BottomLeftCornerHard, 88 | Character.LeftConnector => LeftConnector, 89 | Character.HorizontalLine => HorizontalLine, 90 | Character.VerticalLine => VerticalLine, 91 | Character.Dot => Dot, 92 | Character.Anchor => Anchor, 93 | Character.AnchorHorizontalLine => AnchorHorizontalLine, 94 | Character.AnchorVerticalLine => AnchorVerticalLine, 95 | Character.BottomLeftCornerRound => BottomLeftCornerRound, 96 | _ => throw new NotSupportedException($"Unknown character '{character}'"), 97 | }; 98 | } 99 | 100 | /// 101 | /// Creates a that is compatible with the specified . 102 | /// 103 | /// The console. 104 | /// A that is compatible with the specified . 105 | public static CharacterSet Create(IAnsiConsole console) 106 | { 107 | if (console is null) 108 | { 109 | throw new ArgumentNullException(nameof(console)); 110 | } 111 | 112 | return console.Profile.Capabilities.Unicode 113 | ? UnicodeCharacterSet.Shared 114 | : AsciiCharacterSet.Shared; 115 | } 116 | } 117 | 118 | /// 119 | /// Represents a Unicode compatible character set. 120 | /// 121 | public class UnicodeCharacterSet : CharacterSet 122 | { 123 | internal static UnicodeCharacterSet Shared { get; } = new UnicodeCharacterSet(); 124 | } 125 | 126 | /// 127 | /// Represents an ASCII compatible character set. 128 | /// 129 | public class AsciiCharacterSet : CharacterSet 130 | { 131 | internal static AsciiCharacterSet Shared { get; } = new AsciiCharacterSet(); 132 | 133 | /// 134 | public override char Anchor { get; } = '┬'; 135 | 136 | /// 137 | public override char AnchorHorizontalLine { get; } = '─'; 138 | 139 | /// 140 | public override char BottomLeftCornerRound { get; } = '└'; 141 | } 142 | -------------------------------------------------------------------------------- /src/Errata/Diagnostic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Spectre.Console; 4 | 5 | namespace Errata; 6 | 7 | /// 8 | /// Represents a diagnostic. 9 | /// 10 | public class Diagnostic 11 | { 12 | /// 13 | /// Gets the message. 14 | /// 15 | public string Message { get; } 16 | 17 | /// 18 | /// Gets the labels. 19 | /// 20 | public List