├── docs
├── list.png
└── source.png
├── global.json
├── examples
├── Examples.slnx
├── CSharp
│ ├── Program.cs
│ └── CSharp.csproj
└── FSharp
│ ├── Program.fs
│ └── FSharp.fsproj
├── src
├── Example
│ ├── Extensions
│ │ ├── StringExtensions.cs
│ │ ├── FileExtensions.cs
│ │ └── EnumerableExtensions.cs
│ ├── Properties
│ │ └── Usings.cs
│ ├── Utilities
│ │ ├── ProjectInformation.cs
│ │ ├── ProjectParser.cs
│ │ ├── ExampleFinder.cs
│ │ └── CSharpColorizer.cs
│ ├── Example.csproj
│ ├── Features
│ │ ├── ExampleLister.cs
│ │ ├── ExampleSelector.cs
│ │ ├── ExampleSourceLister.cs
│ │ └── ExampleRunner.cs
│ └── Program.cs
├── Example.slnx
├── Directory.Build.props
└── .editorconfig
├── .editorconfig
├── .github
└── workflows
│ ├── ci.yaml
│ └── publish.yaml
├── LICENSE.md
├── .gitignore
└── README.md
/docs/list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patriksvensson/dotnet-example/HEAD/docs/list.png
--------------------------------------------------------------------------------
/docs/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patriksvensson/dotnet-example/HEAD/docs/source.png
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "10.0.100",
4 | "rollForward": "latestMinor"
5 | }
6 | }
--------------------------------------------------------------------------------
/examples/Examples.slnx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/CSharp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace First
4 | {
5 | class Program
6 | {
7 | static void Main(string[] args)
8 | {
9 | Console.WriteLine("Hello from C#");
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Example/Extensions/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public static class StringExtensions
4 | {
5 | public static string? EscapeMarkup(this string markup)
6 | {
7 | return markup?.Replace("[", "[[")?.Replace("]", "]]");
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/CSharp/CSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net10.0
6 | CSharp
7 | Writes 'Hello from C#!' to the console.
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/FSharp/Program.fs:
--------------------------------------------------------------------------------
1 | // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp
2 |
3 | open System
4 |
5 | // Define a function to construct a message to print
6 | let from whom =
7 | sprintf "from %s" whom
8 |
9 | []
10 | let main argv =
11 | let message = from "F#" // Call the function
12 | printfn "Hello %s" message
13 | 0 // return an integer exit code
--------------------------------------------------------------------------------
/src/Example/Extensions/FileExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public static class FileExtensions
4 | {
5 | public static IEnumerable ReadLines(this IFile file)
6 | {
7 | using var stream = file.OpenRead();
8 | using var reader = new StreamReader(stream);
9 | while (reader.ReadLine() is { } line)
10 | {
11 | yield return line;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/FSharp/FSharp.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net10.0
6 | FSharp
7 | Writes 'Hello from F#!' to the console.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Example.slnx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Example/Properties/Usings.cs:
--------------------------------------------------------------------------------
1 | global using System.ComponentModel;
2 | global using System.Diagnostics;
3 | global using System.Text;
4 | global using System.Xml.Linq;
5 | global using System.Xml.XPath;
6 | global using CliWrap;
7 | global using CliWrap.EventStream;
8 | global using Microsoft.CodeAnalysis;
9 | global using Microsoft.CodeAnalysis.CSharp;
10 | global using Spectre.Console;
11 | global using Spectre.Console.Cli;
12 | global using Spectre.IO;
13 | global using Environment = Spectre.IO.Environment;
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = LF
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = false
9 | trim_trailing_whitespace = true
10 |
11 | [*.{sln,slnx}]
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
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: Continuous Integration
2 | on: pull_request
3 |
4 | env:
5 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
6 | DOTNET_CLI_TELEMETRY_OPTOUT: true
7 |
8 | jobs:
9 | build:
10 | name: Build
11 | if: "!contains(github.event.head_commit.message, 'skip-ci')"
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v5
16 | with:
17 | fetch-depth: 0
18 |
19 | - name: Setup .NET SDK
20 | uses: actions/setup-dotnet@v5
21 | with:
22 | dotnet-version: |
23 | 10.0.x
24 | 9.0.x
25 | 8.0.x
26 |
27 | - name: Build
28 | shell: bash
29 | run: dotnet build.cs
--------------------------------------------------------------------------------
/src/Example/Utilities/ProjectInformation.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ProjectInformation
4 | {
5 | public string Name { get; }
6 | public FilePath Path { get; }
7 | public string Description { get; }
8 | public int Order { get; }
9 | public bool Visible { get; }
10 | public string Group { get; }
11 |
12 | public ProjectInformation(
13 | string name, FilePath path, string description,
14 | int order, bool visible, string group)
15 | {
16 | Name = name;
17 | Path = path;
18 | Description = description;
19 | Order = order;
20 | Visible = visible;
21 | Group = group;
22 | }
23 |
24 | public DirectoryPath GetWorkingDirectory()
25 | {
26 | return Path.GetDirectory();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yaml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 | branches:
8 | - main
9 |
10 | env:
11 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
12 | DOTNET_CLI_TELEMETRY_OPTOUT: true
13 |
14 | jobs:
15 |
16 | ###################################################
17 | # PUBLISH
18 | ###################################################
19 |
20 | publish:
21 | name: Publish
22 | if: "!contains(github.event.head_commit.message, 'skip-ci')"
23 | runs-on: ubuntu-latest
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v5
27 | with:
28 | fetch-depth: 0
29 |
30 | - name: Setup .NET SDK
31 | uses: actions/setup-dotnet@v5
32 | with:
33 | dotnet-version: |
34 | 10.0.x
35 | 9.0.x
36 | 8.0.x
37 |
38 | - name: Publish
39 | shell: bash
40 | run: dotnet build.cs --target="publish" --nuget-key="${{secrets.NUGET_API_KEY}}"
41 |
--------------------------------------------------------------------------------
/src/Example/Extensions/EnumerableExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | internal static class EnumerableExtensions
4 | {
5 | public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerable source)
6 | {
7 | if (source is null)
8 | {
9 | throw new ArgumentNullException(nameof(source));
10 | }
11 |
12 | return Enumerate(source.GetEnumerator());
13 | }
14 |
15 | public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerator source)
16 | {
17 | if (source is null)
18 | {
19 | throw new ArgumentNullException(nameof(source));
20 | }
21 |
22 | var first = true;
23 | var last = !source.MoveNext();
24 | T current;
25 |
26 | for (var index = 0; !last; index++)
27 | {
28 | current = source.Current;
29 | last = !source.MoveNext();
30 | yield return (index, first, last, current);
31 | first = false;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Patrik Svensson
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.
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | 14
5 | true
6 | enable
7 | true
8 | embedded
9 | true
10 | true
11 | true
12 | true
13 | true
14 | $(NoWarn);SA1633
15 | true
16 |
17 |
18 |
19 | true
20 |
21 |
22 |
23 | true
24 | true
25 |
26 |
27 |
28 |
29 |
30 |
31 | All
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Misc folders
2 | [Bb]in/
3 | [Oo]bj/
4 | [Tt]emp/
5 | [Pp]ackages/
6 | /.artifacts/
7 | src/Example/examples
8 | src/Example/samples
9 | /[Tt]ools/
10 |
11 | # Cakeup
12 | cakeup-x86_64-latest.exe
13 |
14 | # .NET Core CLI
15 | /.dotnet/
16 | /.packages/
17 | dotnet-install.sh*
18 | *.lock.json
19 |
20 | # Visual Studio
21 | .vs/
22 | .vscode/
23 | launchSettings.json
24 | *.sln.ide/
25 |
26 | # Rider
27 | src/.idea/**/workspace.xml
28 | src/.idea/**/tasks.xml
29 | src/.idea/dictionaries
30 | src/.idea/**/dataSources/
31 | src/.idea/**/dataSources.ids
32 | src/.idea/**/dataSources.xml
33 | src/.idea/**/dataSources.local.xml
34 | src/.idea/**/sqlDataSources.xml
35 | src/.idea/**/dynamic.xml
36 | src/.idea/**/uiDesigner.xml
37 |
38 | ## Ignore Visual Studio temporary files, build results, and
39 | ## files generated by popular Visual Studio add-ons.
40 |
41 | # User-specific files
42 | *.suo
43 | *.user
44 | *.sln.docstates
45 | *.userprefs
46 | *.GhostDoc.xml
47 | *StyleCop.Cache
48 |
49 | # Build results
50 | [Dd]ebug/
51 | [Rr]elease/
52 | x64/
53 | *_i.c
54 | *_p.c
55 | *.ilk
56 | *.meta
57 | *.obj
58 | *.pch
59 | *.pdb
60 | *.pgc
61 | *.pgd
62 | *.rsp
63 | *.sbr
64 | *.tlb
65 | *.tli
66 | *.tlh
67 | *.tmp
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 |
73 | # Visual Studio profiler
74 | *.psess
75 | *.vsp
76 | *.vspx
77 |
78 | # ReSharper is a .NET coding add-in
79 | _ReSharper*
80 |
81 | # NCrunch
82 | *.ncrunch*
83 | .*crunch*.local.xml
84 | _NCrunch_*
85 |
86 | # NuGet Packages Directory
87 | packages
88 |
89 | # Windows
90 | Thumbs.db
--------------------------------------------------------------------------------
/src/Example/Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | enable
6 | Example
7 | net10.0;net9.0;net8.0
8 | true
9 | dotnet-example
10 | Major
11 | dotnet-example
12 | $(MSBuildProjectDirectory)/../..
13 | false
14 |
15 |
16 |
17 | A dotnet tool to run examples.
18 | Patrik Svensson
19 | git
20 | https://github.com/patriksvensson/dotnet-example
21 | https://github.com/patriksvensson/dotnet-example
22 | MIT
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/Example/Features/ExampleLister.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ExampleLister
4 | {
5 | private readonly IAnsiConsole _console;
6 | private readonly ExampleFinder _finder;
7 |
8 | public ExampleLister(IAnsiConsole console, ExampleFinder finder)
9 | {
10 | _console = console ?? throw new ArgumentNullException(nameof(console));
11 | _finder = finder ?? throw new ArgumentNullException(nameof(finder));
12 | }
13 |
14 | public void List()
15 | {
16 | var examples = _finder.FindExamples();
17 | if (examples.Count == 0)
18 | {
19 | _console.Markup("[yellow]No examples could be found.[/]");
20 | return;
21 | }
22 |
23 | _console.WriteLine();
24 |
25 | var rows = new Grid().Collapse();
26 | rows.AddColumn();
27 | foreach (var group in examples.GroupBy(ex => ex.Group))
28 | {
29 | rows.AddRow(CreateTable(group.Key, group));
30 | rows.AddEmptyRow();
31 | }
32 |
33 | _console.Write(rows);
34 | _console.MarkupLine("Type [blue]dotnet example --help[/] for help");
35 | }
36 |
37 | private static Table CreateTable(string group, IEnumerable projects)
38 | {
39 | var grid = new Table { Border = TableBorder.Rounded }.Expand();
40 | grid.AddColumn(new TableColumn("[grey]Example[/]") { NoWrap = true, });
41 | grid.AddColumn(new TableColumn("[grey]Description[/]"));
42 |
43 | if (!string.IsNullOrWhiteSpace(group))
44 | {
45 | grid.Title = new TableTitle(group);
46 | }
47 |
48 | foreach (var example in projects.OrderBy(e => e.Order))
49 | {
50 | grid.AddRow(
51 | $"[underline blue]{example.Name}[/]",
52 | example.Description ?? "[grey]N/A[/]");
53 | }
54 |
55 | return grid;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Example/Utilities/ProjectParser.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ProjectParser
4 | {
5 | private readonly IFileSystem _fileSystem;
6 |
7 | public ProjectParser(IFileSystem fileSystem)
8 | {
9 | _fileSystem = fileSystem;
10 | }
11 |
12 | public ProjectInformation Parse(FilePath path)
13 | {
14 | // Load the project file
15 | var file = _fileSystem.GetFile(path);
16 | using var stream = file.OpenRead();
17 | var xml = XDocument.Load(stream);
18 |
19 | // Visible?
20 | var visible = true;
21 | var visibleString = Parse(xml, "//ExampleVisible");
22 | if (visibleString?.Equals("false", StringComparison.OrdinalIgnoreCase) ?? false)
23 | {
24 | visible = false;
25 | }
26 |
27 | // Got a description?
28 | var description = Parse(xml, "//ExampleDescription", "//Description");
29 |
30 | // Belongs to a group?
31 | var group = Parse(xml, "//ExampleGroup");
32 |
33 | // Got a title?
34 | var name = Parse(xml, "//ExampleTitle", "//Title");
35 | if (string.IsNullOrWhiteSpace(name))
36 | {
37 | name = path.GetFilenameWithoutExtension().FullPath;
38 | }
39 |
40 | // Got an order?
41 | var order = 1024;
42 | var orderString = Parse(xml, "//ExampleOrder");
43 | if (int.TryParse(orderString, out var orderInteger))
44 | {
45 | order = orderInteger;
46 | }
47 |
48 | return new ProjectInformation(name, path, description, order, visible, group);
49 | }
50 |
51 | private static string Parse(XDocument document, params string[] expressions)
52 | {
53 | foreach (var expression in expressions)
54 | {
55 | var element = document.Root?.XPathSelectElement(expression);
56 | if (element != null)
57 | {
58 | return element.Value;
59 | }
60 | }
61 |
62 | return string.Empty;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Example/Features/ExampleSelector.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ExampleSelector
4 | {
5 | private readonly IAnsiConsole _console;
6 | private readonly ExampleFinder _finder;
7 |
8 | public ExampleSelector(IAnsiConsole console, ExampleFinder finder)
9 | {
10 | _console = console ?? throw new ArgumentNullException(nameof(console));
11 | _finder = finder ?? throw new ArgumentNullException(nameof(finder));
12 | }
13 |
14 | public ProjectInformation? Select()
15 | {
16 | var examples = _finder.FindExamples();
17 | if (examples.Count == 0)
18 | {
19 | _console.Markup("[yellow]No examples could be found.[/]");
20 | return null;
21 | }
22 |
23 | var prompt = new SelectionPrompt();
24 | var groups = examples.GroupBy(ex => ex.Group);
25 |
26 | if (groups.Count() == 1)
27 | {
28 | prompt.AddChoices(examples.Select(x => x.Name));
29 | }
30 | else
31 | {
32 | var noGroupExamples = new List();
33 |
34 | foreach (var group in groups)
35 | {
36 | if (string.IsNullOrEmpty(group.Key))
37 | {
38 | noGroupExamples.AddRange(group.Select(x => x.Name));
39 | }
40 | else
41 | {
42 | prompt.AddChoiceGroup(
43 | group.Key,
44 | group.Select(x => x.Name));
45 | }
46 | }
47 |
48 | if (noGroupExamples.Count > 0)
49 | {
50 | prompt.AddChoices(noGroupExamples);
51 | }
52 | }
53 |
54 | var example = AnsiConsole.Prompt(prompt
55 | .Title("[yellow]Choose an example to run[/]")
56 | .MoreChoicesText("[grey](Move up and down to reveal more examples)[/]")
57 | .Mode(SelectionMode.Leaf));
58 |
59 | return examples.FirstOrDefault(x => x.Name == example);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Example/Features/ExampleSourceLister.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ExampleSourceLister
4 | {
5 | private readonly IFileSystem _fileSystem;
6 | private readonly IGlobber _globber;
7 |
8 | public ExampleSourceLister(IFileSystem fileSystem, IGlobber globber)
9 | {
10 | _fileSystem = fileSystem;
11 | _globber = globber;
12 | }
13 |
14 | public bool List(ProjectInformation project)
15 | {
16 | var result = FindProgram(project);
17 | if (result == null)
18 | {
19 | return false;
20 | }
21 |
22 | var lines = GetLines(result);
23 |
24 | var table = new Table { ShowHeaders = false, Border = TableBorder.Rounded };
25 | table.AddColumn(new TableColumn(string.Empty) { NoWrap = true });
26 | table.AddColumn(string.Empty);
27 |
28 | var lineNumber = 1;
29 | foreach (var line in lines)
30 | {
31 | table.AddRow($"[grey]{lineNumber}[/]", line);
32 | lineNumber++;
33 | }
34 |
35 | AnsiConsole.WriteLine();
36 | AnsiConsole.Write(table);
37 |
38 | return true;
39 | }
40 |
41 | private List GetLines(FilePath programFile)
42 | {
43 | using (var stream = _fileSystem.File.OpenRead(programFile.FullPath))
44 | using (var reader = new StreamReader(stream))
45 | {
46 | // F# doesn't have a SyntaxWalker, so just
47 | // return the lines.
48 | if (programFile.GetExtension() == ".fs")
49 | {
50 | var result = new List();
51 | while (true)
52 | {
53 | var line = reader.ReadLine();
54 | if (line == null)
55 | {
56 | break;
57 | }
58 |
59 | var escaped = line.EscapeMarkup();
60 | if (escaped != null)
61 | {
62 | result.Add(escaped);
63 | }
64 | }
65 |
66 | return result;
67 | }
68 |
69 | // Return colorized lines for C#
70 | return CSharpColorizer.Colorize(reader.ReadToEnd());
71 | }
72 | }
73 |
74 | private FilePath? FindProgram(ProjectInformation project)
75 | {
76 | var directory = project.Path.GetDirectory();
77 | var result = _globber.Match("**/Program.{f|c}s", new GlobberSettings { Root = directory }).OfType().ToList();
78 |
79 | if (result.Count == 0)
80 | {
81 | AnsiConsole.Markup("[red]Error:[/] Could not find Program.cs for example [underline]{0}[/].", project.Name);
82 | return null;
83 | }
84 |
85 | if (result.Count > 1)
86 | {
87 | AnsiConsole.Markup("[red]Error:[/] Found multiple Program.cs for example [underline]{0}[/].", project.Name);
88 | return null;
89 | }
90 |
91 | return result.First();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Example/Utilities/ExampleFinder.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class ExampleFinder
4 | {
5 | private readonly IFileSystem _fileSystem;
6 | private readonly IEnvironment _environment;
7 | private readonly IGlobber _globber;
8 | private readonly string[] _skip;
9 | private readonly ProjectParser _parser;
10 |
11 | public ExampleFinder(IFileSystem fileSystem, IEnvironment environment, IGlobber globber, string[]? skip)
12 | {
13 | _fileSystem = fileSystem;
14 | _environment = environment;
15 | _globber = globber;
16 | _skip = skip ?? Array.Empty();
17 | _parser = new ProjectParser(fileSystem);
18 | }
19 |
20 | public ProjectInformation? FindExample(string name)
21 | {
22 | var result = new List();
23 | foreach (var example in FindExamples())
24 | {
25 | if (example.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
26 | {
27 | result.Add(example);
28 | }
29 | }
30 |
31 | if (result.Count == 0)
32 | {
33 | AnsiConsole.Markup("[red]Error:[/] The example [underline]{0}[/] could not be found.", name);
34 | return null;
35 | }
36 |
37 | if (result.Count > 1)
38 | {
39 | AnsiConsole.Markup("[red]Error:[/] Found multiple examples called [underline]{0}[/].", name);
40 | return null;
41 | }
42 |
43 | return result[0];
44 | }
45 |
46 | public IReadOnlyList FindExamples()
47 | {
48 | var result = new List();
49 |
50 | var folders = GetExampleFolders();
51 | var examples = folders.Select(FindProjects).Aggregate((acc, xs) => acc.Concat(xs));
52 | foreach (var example in examples)
53 | {
54 | result.Add(_parser.Parse(example));
55 | }
56 |
57 | return result
58 | .Where(x => x.Visible && !_skip.Contains(x.Name, StringComparer.OrdinalIgnoreCase))
59 | .OrderBy(x => x.Order)
60 | .ToList();
61 | }
62 |
63 | private string[] GetExampleFolders()
64 | {
65 | var dotExamplesFilePath = new FilePath(".examples").MakeAbsolute(_environment);
66 | var folders = _fileSystem.Exist(dotExamplesFilePath)
67 | ? _fileSystem.GetFile(dotExamplesFilePath)
68 | .ReadLines()
69 | .Where(s => !string.IsNullOrWhiteSpace(s)
70 | && !s.StartsWith('#')) // skip comments
71 | .Select(s => s.Trim())
72 | .ToArray()
73 | : Array.Empty();
74 |
75 | if (folders.Length == 0)
76 | {
77 | folders = new[] { "examples", "samples" };
78 | }
79 |
80 | return folders;
81 | }
82 |
83 | private IEnumerable FindProjects(string folder)
84 | {
85 | var root = new DirectoryPath(folder).MakeAbsolute(_environment);
86 | var globberSettings = new GlobberSettings { Comparer = new PathComparer(false), Root = root };
87 | return _globber.Match(@"**/*.{c|f}sproj", globberSettings).OfType();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Example/Utilities/CSharpColorizer.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public sealed class CSharpColorizer
4 | {
5 | public static List Colorize(string source)
6 | {
7 | var tree = CSharpSyntaxTree.ParseText(source);
8 | var walker = new ColorizerSyntaxWalker(SyntaxWalkerDepth.StructuredTrivia);
9 | walker.Visit(tree.GetRoot());
10 |
11 | return walker.GetResult();
12 | }
13 |
14 | private sealed class ColorizerSyntaxWalker : SyntaxWalker
15 | {
16 | private readonly StringBuilder _result;
17 |
18 | public ColorizerSyntaxWalker(SyntaxWalkerDepth depth = SyntaxWalkerDepth.Node)
19 | : base(depth)
20 | {
21 | _result = new StringBuilder();
22 | }
23 |
24 | public List GetResult()
25 | {
26 | return _result.ToString()
27 | .Replace("\r\n", "\n", StringComparison.OrdinalIgnoreCase)
28 | .Replace("\r", string.Empty, StringComparison.OrdinalIgnoreCase)
29 | .TrimEnd('\n')
30 | .Split(new string[] { "\n" }, StringSplitOptions.None)
31 | .ToList();
32 | }
33 |
34 | protected override void VisitToken(SyntaxToken token)
35 | {
36 | ProcessTrivia(token.LeadingTrivia);
37 |
38 | if (token.IsKeyword())
39 | {
40 | _result.Append("[blue]").Append(token.ToString().EscapeMarkup()).Append("[/]");
41 | }
42 | else
43 | {
44 | if (token.IsKind(SyntaxKind.IdentifierToken))
45 | {
46 | _result.Append("[white]").Append(token.ToString().EscapeMarkup()).Append("[/]");
47 | }
48 | else if (token.IsKind(SyntaxKind.StringLiteralToken))
49 | {
50 | _result.Append("[grey]").Append(token.ToString().EscapeMarkup()).Append("[/]");
51 | }
52 | else
53 | {
54 | _result.Append("[silver]").Append(token.ToString().EscapeMarkup()).Append("[/]");
55 | }
56 | }
57 |
58 | ProcessTrivia(token.TrailingTrivia);
59 |
60 | base.VisitToken(token);
61 | }
62 |
63 | private void ProcessTrivia(SyntaxTriviaList list)
64 | {
65 | foreach (var trivia in list)
66 | {
67 | if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia))
68 | {
69 | _result.Append("[green]").Append(trivia.ToString().EscapeMarkup()).Append("[/]");
70 | }
71 | else if (trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))
72 | {
73 | var result = trivia.ToString().Split("\r\n", StringSplitOptions.None);
74 | foreach (var (_, _, last, item) in result.Enumerate())
75 | {
76 | _result.Append("[green]").Append(item.EscapeMarkup()).Append("[/]");
77 | if (!last)
78 | {
79 | _result.Append("\r\n");
80 | }
81 | }
82 | }
83 | else
84 | {
85 | _result.Append(trivia.ToString().EscapeMarkup());
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dotnet example
2 |
3 | A dotnet tool to list and run examples similar to Rust's `cargo run --example`.
4 |
5 | ## Installing
6 |
7 | ```
8 | > dotnet tool install -g dotnet-example
9 | ```
10 |
11 | ## Listing examples
12 |
13 | ```
14 | > dotnet example
15 |
16 | ╭─────────────┬──────────────────────────────────────────────╮
17 | │ Example │ Description │
18 | ├─────────────┼──────────────────────────────────────────────┤
19 | │ CSharp │ Writes 'Hello from C#' to the console │
20 | │ FSharp │ Writes 'Hello from F#' to the console │
21 | ╰─────────────┴──────────────────────────────────────────────╯
22 |
23 | Type dotnet example --help for help
24 | ```
25 |
26 | ## Running individual examples
27 |
28 | ```
29 | > dotnet example csharp
30 | Hello from C#
31 |
32 | > dotnet example fsharp
33 | Hello from F#
34 | ```
35 |
36 | ## Running all examples
37 |
38 | ```
39 | > dotnet example --all
40 | ── Example: CSharp ────────────────────────────────────────────────
41 | Hello from C#
42 |
43 | ── Example: FSharp ────────────────────────────────────────────────
44 | Hello from F#
45 | ```
46 |
47 | ## Showing example source code
48 |
49 | ```
50 | > dotnet example fsharp --source
51 |
52 | ╭────┬───────────────────────────────────────────────────────────────────╮
53 | │ 1 │ // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp │
54 | │ 2 │ │
55 | │ 3 │ open System │
56 | │ 4 │ │
57 | │ 5 │ // Define a function to construct a message to print │
58 | │ 6 │ let from whom = │
59 | │ 7 │ sprintf "from %s" whom │
60 | │ 8 │ │
61 | │ 9 │ [] │
62 | │ 10 │ let main argv = │
63 | │ 11 │ let message = from "F#" // Call the function │
64 | │ 12 │ printfn "Hello %s" message │
65 | │ 13 │ 0 // return an integer exit code │
66 | ╰────┴───────────────────────────────────────────────────────────────────╯
67 | ```
68 |
69 | ## Conventions
70 |
71 | The convention is simple, if there is an `examples` or `samples` folder
72 | in the directory the tool is executed in, it will fetch all `csproj`/`fsproj` files
73 | and find the best match to the query.
74 |
75 | If examples are located in unconventional folders, add a `.examples` file
76 | with the (relative) paths of the examples folders, one per line. Blank lines
77 | or lines starting with `#` in the `.examples` file are ignored.
78 |
79 | ## Example settings
80 |
81 | To change the name, description, and the order of an example, edit its `csproj`/`fsproj` file, and add the following section:
82 |
83 | ```xml
84 |
85 | Foo
86 | This is the description of the example.
87 | 5
88 |
89 | ```
90 |
91 | If no name is set in the `csproj` file, the project name will be used.
92 | To ignore an example, add the `ExampleVisible` property in the example's `csproj`/`fsproj` file.
93 |
94 | ```xml
95 |
96 | false
97 |
98 | ```
--------------------------------------------------------------------------------
/src/Example/Features/ExampleRunner.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public class ExampleRunner
4 | {
5 | private readonly IAnsiConsole _console;
6 | private readonly ExampleFinder _finder;
7 |
8 | public ExampleRunner(IAnsiConsole console, ExampleFinder finder)
9 | {
10 | _console = console ?? throw new ArgumentNullException(nameof(console));
11 | _finder = finder ?? throw new ArgumentNullException(nameof(finder));
12 | }
13 |
14 | public async Task Run(string name, IRemainingArguments remaining)
15 | {
16 | var example = _finder.FindExample(name);
17 | if (example == null)
18 | {
19 | return -1;
20 | }
21 |
22 | if (!await Build(example).ConfigureAwait(false))
23 | {
24 | return -1;
25 | }
26 |
27 | var arguments = "run";
28 | if (remaining.Raw.Count > 0)
29 | {
30 | arguments += $"--no-build --no-restore -- {string.Join(" ", remaining.Raw)}";
31 | }
32 |
33 | // Run the example using "dotnet run"
34 | var info = new ProcessStartInfo("dotnet")
35 | {
36 | Arguments = arguments,
37 | WorkingDirectory = example.GetWorkingDirectory().FullPath,
38 | };
39 |
40 | var process = Process.Start(info);
41 | if (process == null)
42 | {
43 | throw new InvalidOperationException("An error occured when starting the 'dotnet' process");
44 | }
45 |
46 | process.WaitForExit();
47 | return process.ExitCode;
48 | }
49 |
50 | public async Task RunAll(IRemainingArguments remaining)
51 | {
52 | var examples = _finder.FindExamples();
53 | foreach (var (_, first, _, example) in examples.Enumerate())
54 | {
55 | if (!first)
56 | {
57 | _console.WriteLine();
58 | }
59 |
60 | _console.Write(new Rule($"Example: [silver]{example.Name}[/]").LeftJustified().RuleStyle("grey"));
61 |
62 | var exitCode = await Run(example.Name, remaining).ConfigureAwait(false);
63 | if (exitCode != 0)
64 | {
65 | _console.MarkupLine($"[red]Error:[/] Example [u]{example.Name}[/] did not return a successful exit code.");
66 | return exitCode;
67 | }
68 | }
69 |
70 | return 0;
71 | }
72 |
73 | private async Task Build(ProjectInformation example)
74 | {
75 | var exitCode = await _console.Status().StartAsync($"Building example [yellow]{example.Name}[/]...", async ctx =>
76 | {
77 | var cmd = Cli.Wrap("dotnet").WithArguments("build")
78 | .WithWorkingDirectory(example.GetWorkingDirectory().FullPath)
79 | .WithValidation(CommandResultValidation.None);
80 |
81 | await foreach (var cmdEvent in cmd.ListenAsync())
82 | {
83 | switch (cmdEvent)
84 | {
85 | case StandardErrorCommandEvent stdErr:
86 | _console.MarkupLine($"[red]ERR>[/] {stdErr.Text.EscapeMarkup()}");
87 | break;
88 | case ExitedCommandEvent exited:
89 | return exited.ExitCode;
90 | }
91 | }
92 |
93 | // Should never occur
94 | return -1;
95 | }).ConfigureAwait(false);
96 |
97 | if (exitCode != 0)
98 | {
99 | _console.MarkupLine($"[red]Error:[/] Could not build example [u]{example.Name}[/]");
100 | }
101 |
102 | return exitCode == 0;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Example/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Example;
2 |
3 | public static class Program
4 | {
5 | public static async Task Main(string[] args)
6 | {
7 | var app = new CommandApp();
8 | app.Configure(config =>
9 | {
10 | config.SetApplicationName("dotnet example");
11 | });
12 |
13 | return await app.RunAsync(args).ConfigureAwait(false);
14 | }
15 | }
16 |
17 | public sealed class DefaultCommand : AsyncCommand
18 | {
19 | private readonly IAnsiConsole _console;
20 | private readonly IFileSystem _fileSystem;
21 | private readonly IEnvironment _environment;
22 | private readonly IGlobber _globber;
23 |
24 | public sealed class Settings : CommandSettings
25 | {
26 | [CommandArgument(0, "[EXAMPLE]")]
27 | [Description("The example to run.\nIf none is specified, all examples will be listed")]
28 | public string? Name { get; set; }
29 |
30 | [CommandOption("-l|--list")]
31 | [Description("Lists all available examples")]
32 | public bool List { get; set; }
33 |
34 | [CommandOption("-a|--all")]
35 | [Description("Runs all available examples")]
36 | public bool All { get; set; }
37 |
38 | [CommandOption("--skip")]
39 | [Description("Skips example when combined with [grey]--all[/]")]
40 | public string[]? Skip { get; set; }
41 |
42 | [CommandOption("-s|--source")]
43 | [Description("Show example source code")]
44 | public bool Source { get; set; }
45 |
46 | [CommandOption("--select")]
47 | [Description("Select an example from a list")]
48 | public bool Select { get; set; }
49 | }
50 |
51 | public DefaultCommand(IAnsiConsole console)
52 | {
53 | _console = console;
54 | _fileSystem = new FileSystem();
55 | _environment = new Environment();
56 | _globber = new Globber(_fileSystem, _environment);
57 | }
58 |
59 | public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
60 | {
61 | if (settings.All)
62 | {
63 | var finder = new ExampleFinder(_fileSystem, _environment, _globber, settings.Skip);
64 | var runner = new ExampleRunner(_console, finder);
65 | return await runner.RunAll(context.Remaining).ConfigureAwait(false);
66 | }
67 | else if (settings.Select)
68 | {
69 | var finder = new ExampleFinder(_fileSystem, _environment, _globber, settings.Skip);
70 | var selector = new ExampleSelector(_console, finder);
71 |
72 | var example = selector.Select();
73 | if (example == null)
74 | {
75 | return -1;
76 | }
77 |
78 | if (settings.Source)
79 | {
80 | var sourceLister = new ExampleSourceLister(_fileSystem, _globber);
81 | if (!sourceLister.List(example))
82 | {
83 | return -1;
84 | }
85 |
86 | return 0;
87 | }
88 | else
89 | {
90 | var runner = new ExampleRunner(_console, finder);
91 | return await runner.Run(example.Name, context.Remaining).ConfigureAwait(false);
92 | }
93 | }
94 | else if (settings.List || string.IsNullOrWhiteSpace(settings.Name))
95 | {
96 | var finder = new ExampleFinder(_fileSystem, _environment, _globber, settings.Skip);
97 |
98 | // Only one example?
99 | var examples = finder.FindExamples();
100 | if (examples.Count == 1)
101 | {
102 | // Execute it
103 | var runner = new ExampleRunner(_console, finder);
104 | return await runner.Run(examples[0].Name, context.Remaining).ConfigureAwait(false);
105 | }
106 |
107 | var lister = new ExampleLister(_console, finder);
108 | lister.List();
109 | return 0;
110 | }
111 | else if (settings.Source)
112 | {
113 | var finder = new ExampleFinder(_fileSystem, _environment, _globber, settings.Skip);
114 | var example = finder.FindExample(settings.Name);
115 | if (example == null)
116 | {
117 | return -1;
118 | }
119 |
120 | var lister = new ExampleSourceLister(_fileSystem, _globber);
121 | if (!lister.List(example))
122 | {
123 | return -1;
124 | }
125 |
126 | return 0;
127 | }
128 | else
129 | {
130 | var finder = new ExampleFinder(_fileSystem, _environment, _globber, settings.Skip);
131 | var runner = new ExampleRunner(_console, finder);
132 | return await runner.Run(settings.Name, context.Remaining).ConfigureAwait(false);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/.editorconfig:
--------------------------------------------------------------------------------
1 | root = false
2 |
3 | [*.cs]
4 | # Prefer file scoped namespace declarations
5 | csharp_style_namespace_declarations = file_scoped:warning
6 |
7 | # Sort using and Import directives with System.* appearing first
8 | dotnet_sort_system_directives_first = true
9 | dotnet_separate_import_directive_groups = false
10 |
11 | # Avoid "this." and "Me." if not necessary
12 | dotnet_style_qualification_for_field = false:refactoring
13 | dotnet_style_qualification_for_property = false:refactoring
14 | dotnet_style_qualification_for_method = false:refactoring
15 | dotnet_style_qualification_for_event = false:refactoring
16 |
17 | # Use language keywords instead of framework type names for type references
18 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
19 | dotnet_style_predefined_type_for_member_access = true:suggestion
20 |
21 | # Suggest more modern language features when available
22 | dotnet_style_object_initializer = true:suggestion
23 | dotnet_style_collection_initializer = true:suggestion
24 | dotnet_style_coalesce_expression = true:suggestion
25 | dotnet_style_null_propagation = true:suggestion
26 | dotnet_style_explicit_tuple_names = true:suggestion
27 |
28 | # Non-private static fields are PascalCase
29 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
30 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
31 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
32 | dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
33 | dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
34 | dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
35 | dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
36 |
37 | # Non-private readonly fields are PascalCase
38 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
39 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
40 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
41 | dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
42 | dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
43 | dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
44 | dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
45 |
46 | # Constants are PascalCase
47 | dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
48 | dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
49 | dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
50 | dotnet_naming_symbols.constants.applicable_kinds = field, local
51 | dotnet_naming_symbols.constants.required_modifiers = const
52 | dotnet_naming_style.constant_style.capitalization = pascal_case
53 |
54 | # Instance fields are camelCase and start with _
55 | dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
56 | dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
57 | dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
58 | dotnet_naming_symbols.instance_fields.applicable_kinds = field
59 | dotnet_naming_style.instance_field_style.capitalization = camel_case
60 | dotnet_naming_style.instance_field_style.required_prefix = _
61 |
62 | # Locals and parameters are camelCase
63 | dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
64 | dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
65 | dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
66 | dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
67 | dotnet_naming_style.camel_case_style.capitalization = camel_case
68 |
69 | # Local functions are PascalCase
70 | dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
71 | dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
72 | dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
73 | dotnet_naming_symbols.local_functions.applicable_kinds = local_function
74 | dotnet_naming_style.local_function_style.capitalization = pascal_case
75 |
76 | # By default, name items with PascalCase
77 | dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
78 | dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
79 | dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
80 | dotnet_naming_symbols.all_members.applicable_kinds = *
81 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
82 |
83 | # Newline settings
84 | csharp_new_line_before_open_brace = all
85 | csharp_new_line_before_else = true
86 | csharp_new_line_before_catch = true
87 | csharp_new_line_before_finally = true
88 | csharp_new_line_before_members_in_object_initializers = true
89 | csharp_new_line_before_members_in_anonymous_types = true
90 | csharp_new_line_between_query_expression_clauses = true
91 |
92 | # Indentation preferences
93 | csharp_indent_block_contents = true
94 | csharp_indent_braces = false
95 | csharp_indent_case_contents = true
96 | csharp_indent_case_contents_when_block = true
97 | csharp_indent_switch_labels = true
98 | csharp_indent_labels = flush_left
99 |
100 | # Prefer "var" everywhere
101 | csharp_style_var_for_built_in_types = true:suggestion
102 | csharp_style_var_when_type_is_apparent = true:suggestion
103 | csharp_style_var_elsewhere = true:suggestion
104 |
105 | # Prefer method-like constructs to have a block body
106 | csharp_style_expression_bodied_methods = false:none
107 | csharp_style_expression_bodied_constructors = false:none
108 | csharp_style_expression_bodied_operators = false:none
109 |
110 | # Prefer property-like constructs to have an expression-body
111 | csharp_style_expression_bodied_properties = true:none
112 | csharp_style_expression_bodied_indexers = true:none
113 | csharp_style_expression_bodied_accessors = true:none
114 |
115 | # Suggest more modern language features when available
116 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
117 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
118 | csharp_style_inlined_variable_declaration = true:suggestion
119 | csharp_style_throw_expression = true:suggestion
120 | csharp_style_conditional_delegate_call = true:suggestion
121 |
122 | # Space preferences
123 | csharp_space_after_cast = false
124 | csharp_space_after_colon_in_inheritance_clause = true
125 | csharp_space_after_comma = true
126 | csharp_space_after_dot = false
127 | csharp_space_after_keywords_in_control_flow_statements = true
128 | csharp_space_after_semicolon_in_for_statement = true
129 | csharp_space_around_binary_operators = before_and_after
130 | csharp_space_around_declaration_statements = do_not_ignore
131 | csharp_space_before_colon_in_inheritance_clause = true
132 | csharp_space_before_comma = false
133 | csharp_space_before_dot = false
134 | csharp_space_before_open_square_brackets = false
135 | csharp_space_before_semicolon_in_for_statement = false
136 | csharp_space_between_empty_square_brackets = false
137 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
138 | csharp_space_between_method_call_name_and_opening_parenthesis = false
139 | csharp_space_between_method_call_parameter_list_parentheses = false
140 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
141 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
142 | csharp_space_between_method_declaration_parameter_list_parentheses = false
143 | csharp_space_between_parentheses = false
144 | csharp_space_between_square_brackets = false
145 |
146 | # Blocks are allowed
147 | csharp_prefer_braces = true:silent
148 | csharp_preserve_single_line_blocks = true
149 | csharp_preserve_single_line_statements = true
150 |
151 | # RS0037: PublicAPI.txt is missing '#nullable enable'
152 | dotnet_diagnostic.RS0037.severity = none
153 |
154 | # IDE0055: Fix formatting
155 | dotnet_diagnostic.IDE0055.severity = warning
156 |
157 | # SA1101: Prefix local calls with this
158 | dotnet_diagnostic.SA1101.severity = none
159 |
160 | # SA1633: File should have header
161 | dotnet_diagnostic.SA1633.severity = none
162 |
163 | # SA1201: Elements should appear in the correct order
164 | dotnet_diagnostic.SA1201.severity = none
165 |
166 | # SA1202: Public members should come before private members
167 | dotnet_diagnostic.SA1202.severity = none
168 |
169 | # SA1309: Field names should not begin with underscore
170 | dotnet_diagnostic.SA1309.severity = none
171 |
172 | # SA1404: Code analysis suppressions should have justification
173 | dotnet_diagnostic.SA1404.severity = none
174 |
175 | # SA1516: Elements should be separated by a blank line
176 | dotnet_diagnostic.SA1516.severity = none
177 |
178 | # CA1303: Do not pass literals as localized parameters
179 | dotnet_diagnostic.CA1303.severity = none
180 |
181 | # CSA1204: Static members should appear before non-static members
182 | dotnet_diagnostic.SA1204.severity = none
183 |
184 | # IDE0052: Remove unread private members
185 | dotnet_diagnostic.IDE0052.severity = warning
186 |
187 | # IDE0063: Use simple 'using' statement
188 | csharp_prefer_simple_using_statement = false:suggestion
189 |
190 | # IDE0018: Variable declaration can be inlined
191 | dotnet_diagnostic.IDE0018.severity = warning
192 |
193 | # SA1625: Element documenation should not be copied and pasted
194 | dotnet_diagnostic.SA1625.severity = none
195 |
196 | # IDE0005: Using directive is unnecessary
197 | dotnet_diagnostic.IDE0005.severity = warning
198 |
199 | # SA1117: Parameters should be on same line or separate lines
200 | dotnet_diagnostic.SA1117.severity = none
201 |
202 | # SA1404: Code analysis suppression should have justification
203 | dotnet_diagnostic.SA1404.severity = none
204 |
205 | # SA1101: Prefix local calls with this
206 | dotnet_diagnostic.SA1101.severity = none
207 |
208 | # SA1633: File should have header
209 | dotnet_diagnostic.SA1633.severity = none
210 |
211 | # SA1649: File name should match first type name
212 | dotnet_diagnostic.SA1649.severity = none
213 |
214 | # SA1402: File may only contain a single type
215 | dotnet_diagnostic.SA1402.severity = none
216 |
217 | # CA1814: Prefer jagged arrays over multidimensional
218 | dotnet_diagnostic.CA1814.severity = none
219 |
220 | # RCS1194: Implement exception constructors.
221 | dotnet_diagnostic.RCS1194.severity = none
222 |
223 | # CA1032: Implement standard exception constructors
224 | dotnet_diagnostic.CA1032.severity = none
225 |
226 | # CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
227 | dotnet_diagnostic.CA1826.severity = none
228 |
229 | # RCS1079: Throwing of new NotImplementedException.
230 | dotnet_diagnostic.RCS1079.severity = warning
231 |
232 | # RCS1057: Add empty line between declarations.
233 | dotnet_diagnostic.RCS1057.severity = none
234 |
235 | # RCS1057: Validate arguments correctly
236 | dotnet_diagnostic.RCS1227.severity = none
237 |
238 | # IDE0004: Remove Unnecessary Cast
239 | dotnet_diagnostic.IDE0004.severity = warning
240 |
241 | # CA1810: Initialize reference type static fields inline
242 | dotnet_diagnostic.CA1810.severity = none
243 |
244 | # IDE0044: Add readonly modifier
245 | dotnet_diagnostic.IDE0044.severity = warning
246 |
247 | # RCS1047: Non-asynchronous method name should not end with 'Async'.
248 | dotnet_diagnostic.RCS1047.severity = none
249 |
250 | # RCS1090: Call 'ConfigureAwait(false)'.
251 | dotnet_diagnostic.RCS1090.severity = warning
252 |
253 | # SA1633: The file header is missing or not located at the top of the file
254 | dotnet_diagnostic.SA1633.severity = none
255 |
256 | # CA2016: Forward the CancellationToken parameter to methods that take one
257 | dotnet_diagnostic.CA2016.severity = warning
--------------------------------------------------------------------------------