├── .editorconfig
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── BUG.yml
│ └── FEATURE.yml
├── PULL_REQUEST_TEMPLATE
│ └── pull_request_template.md
├── codecov.yml
├── dependabot.yml
├── readme_assets
│ ├── csharprepl.mp4
│ ├── csharprepl.png
│ ├── nuget.png
│ └── vscode.png
└── workflows
│ ├── main.yml
│ └── release.yml
├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── ARCHITECTURE.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CSharpRepl.Services
├── CSharpRepl.Services.csproj
├── Completion
│ ├── AutoCompleteService.cs
│ └── OpenAICompleteService.cs
├── Configuration.cs
├── Disassembly
│ └── Disassembler.cs
├── Dotnet
│ └── DotnetBuilder.cs
├── Extensions
│ ├── KeyExtensions.cs
│ ├── LinqExtensions.cs
│ ├── MiscExtensions.cs
│ ├── RoslynExtensions.cs
│ └── SpectreExtensions.cs
├── GlobalSuppressions.cs
├── IConsoleEx.cs
├── Logging
│ └── ITraceLogger.cs
├── Nuget
│ ├── ConsoleNugetLogger.cs
│ ├── NugetHelper.cs
│ └── NugetPackageInstaller.cs
├── Roslyn
│ ├── DocumentationComment.cs
│ ├── DocumentationCommentXmlNames.cs
│ ├── Formatting
│ │ ├── CustomObjectFormatters
│ │ │ ├── CustomObjectFormatter.cs
│ │ │ ├── GuidFormatter.cs
│ │ │ ├── IEnumerableFormatter.cs
│ │ │ ├── KeyValuePairFormatter.cs
│ │ │ ├── MethodInfoFormatter.cs
│ │ │ ├── ReflectionHelpers.cs
│ │ │ ├── TupleFormatter.cs
│ │ │ └── TypeFormatter.cs
│ │ ├── FormattedObject.cs
│ │ ├── LengthLimiting.cs
│ │ ├── Level.cs
│ │ ├── PrettyPrinter.Exceptions.cs
│ │ ├── PrettyPrinter.Members.cs
│ │ ├── PrettyPrinter.cs
│ │ ├── PrimitiveFormatter.cs
│ │ ├── Rendering
│ │ │ ├── FormattedObjectRenderable.cs
│ │ │ └── RenderableSequence.cs
│ │ └── TypeNameFormatter.cs
│ ├── MetadataResolvers
│ │ ├── AlternativeReferenceResolver.cs
│ │ ├── AssemblyReferenceMetadataResolver.cs
│ │ ├── CompositeAlternativeReferenceResolver.cs
│ │ ├── CompositeMetadataReferenceResolver.cs
│ │ ├── NugetPackageMetadataResolver.cs
│ │ └── SolutionFileMetadataResolver.cs
│ ├── Microsoft.CodeAnalysis.CSharp.Symbols
│ │ ├── GeneratedNameConstants.cs
│ │ ├── GeneratedNameKind.cs
│ │ ├── GeneratedNameParser.cs
│ │ └── GeneratedNames.cs
│ ├── Microsoft.CodeAnalysis.CSharp
│ │ └── ObjectDisplay.cs
│ ├── Microsoft.CodeAnalysis.PooledObjects
│ │ ├── ArrayBuilder.Enumerator.cs
│ │ ├── ArrayBuilder.cs
│ │ ├── ObjectPool`1.cs
│ │ ├── PooledHashSet.cs
│ │ └── PooledStringBuilder.cs
│ ├── Microsoft.CodeAnalysis.Scripting.Hosting
│ │ ├── MemberFilter.cs
│ │ ├── ObjectFormatterHelpers.cs
│ │ ├── PrimitiveFormatterOptions.cs
│ │ └── TypeNameFormatterOptions.cs
│ ├── Microsoft.CodeAnalysis
│ │ ├── ObjectDisplayExtensions.cs
│ │ └── ObjectDisplayOptions.cs
│ ├── OverloadItemGenerator.cs
│ ├── References
│ │ ├── AssemblyReferenceComparer.cs
│ │ ├── AssemblyReferenceService.cs
│ │ ├── DotNetInstallationLocator.cs
│ │ └── SharedFramework.cs
│ ├── RoslynServices.Overloads.cs
│ ├── RoslynServices.cs
│ ├── Scripting
│ │ ├── EvaluationResult.cs
│ │ ├── ScriptGlobals.cs
│ │ └── ScriptRunner.cs
│ ├── WorkspaceManager.cs
│ └── XmlFragmentParser.cs
├── RuntimeHelper.cs
├── SymbolExploration
│ ├── DebugSymbolLoader.cs
│ ├── NullSymbolLogger.cs
│ ├── SourceLink
│ │ ├── GitHubSourceLinkHost.cs
│ │ └── SourceLinkLookup.cs
│ └── SymbolExplorer.cs
├── SyntaxHighlighting
│ ├── HighlightedSpan.cs
│ └── SyntaxHighlighter.cs
├── SystemConsoleEx.cs
├── Theming
│ ├── ExportVisualStudioTheme.csx
│ ├── FormattedStringParser.cs
│ ├── StyledString.cs
│ ├── StyledStringBuilder.cs
│ ├── StyledStringSegment.cs
│ ├── SyntaxHighlightingColor.cs
│ ├── Theme.cs
│ └── ThemeColor.cs
└── runtime.json
├── CSharpRepl.Tests
├── CSharpRepl.Tests.csproj
├── CommandLineTests.cs
├── CompletionTests.cs
├── ConfigurationTests.cs
├── Data
│ ├── ComplexSolution
│ │ ├── ComplexSolution.sln
│ │ ├── EntryPoint
│ │ │ ├── EntryPoint.csproj
│ │ │ └── Program.cs
│ │ ├── LibraryA
│ │ │ ├── A.cs
│ │ │ └── LibraryA.csproj
│ │ └── LibraryB
│ │ │ ├── B.cs
│ │ │ └── LibraryB.csproj
│ ├── Config.rsp
│ ├── DemoLibrary.README.txt
│ ├── DemoLibrary.dll
│ ├── DemoSolution
│ │ ├── DemoSolution.DemoProject1
│ │ │ ├── DemoClass1.cs
│ │ │ └── DemoSolution.DemoProject1.csproj
│ │ ├── DemoSolution.DemoProject2
│ │ │ ├── DemoClass2.cs
│ │ │ └── DemoSolution.DemoProject2.csproj
│ │ ├── DemoSolution.DemoProject3
│ │ │ ├── DemoClass3.cs
│ │ │ └── DemoSolution.DemoProject3.csproj
│ │ └── DemoSolution.sln
│ ├── Disassembly
│ │ ├── TopLevelProgram.Input.txt
│ │ ├── TopLevelProgram.Output.Debug.il
│ │ ├── TopLevelProgram.Output.Release.il
│ │ ├── TypeDeclaration.Input.txt
│ │ ├── TypeDeclaration.Output.Debug.il
│ │ └── TypeDeclaration.Output.Release.il
│ ├── LoadScript.csx
│ ├── ResponseFile.rsp
│ ├── WebApplication1.dll
│ ├── WebApplication1.runtimeconfig.json
│ └── theme.json
├── DisassemblerTests.cs
├── DotNetInstallationLocatorTest.cs
├── EvaluationTests.cs
├── Extensions.cs
├── FakeConsole.cs
├── FakeHttp.cs
├── FormattedStringParserTests.cs
├── NugetPackageInstallerTests.cs
├── ObjectFormatting
│ ├── CustomObjectFormattersTests.cs
│ ├── PrettyPrinterTests.cs
│ └── TestFormatter.cs
├── PipedInputEvaluatorTests.cs
├── ProgramTests.cs
├── PromptConfigurationTests.cs
├── ReadEvalPrintLoopTests.cs
├── RoslynServicesFixture.cs
├── RoslynServicesTests.Overloads.cs
├── RoslynServicesTests.cs
├── ScriptArgumentTests.cs
├── StyledStringTests.cs
├── SymbolExplorerTests.cs
├── SyntaxHighlightingTests.cs
└── TraceLoggerTests.cs
├── CSharpRepl.sln
├── CSharpRepl.sln.licenseheader
├── CSharpRepl
├── CSharpRepl.csproj
├── CSharpReplPromptCallbacks.cs
├── CommandLine.cs
├── ConfigurationFile.cs
├── Logging
│ ├── NullLogger.cs
│ └── TraceLogger.cs
├── PipedInputEvaluator.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── ReadEvalPrintLoop.cs
└── themes
│ ├── VisualStudio_BlueExtraContrast.json
│ ├── VisualStudio_Dark.json
│ ├── VisualStudio_Light.json
│ └── dracula.json
├── LICENSE.txt
├── README.md
├── nuget.config
└── publish-release.ps1
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | indent_style=space
4 | end_of_line=crlf
5 |
6 | # CS1591: Missing XML comment for publicly visible type or member
7 | dotnet_diagnostic.CS1591.severity = none
8 |
9 | # S3358: Ternary operators should not be nested
10 | dotnet_diagnostic.S3358.severity = none
11 |
12 | csharp_style_namespace_declarations=file_scoped:warning
13 |
14 | # CA1068: CancellationToken parameters must come last
15 | dotnet_diagnostic.CA1068.severity = warning
16 |
17 | # CA2250: Use ThrowIfCancellationRequested
18 | dotnet_diagnostic.CA2250.severity = warning
19 |
20 | # CA2016: Forward the CancellationToken parameter to methods that take one
21 | dotnet_diagnostic.CA2016.severity = warning
22 |
23 | # IDE0040: Add accessibility modifiers
24 | dotnet_diagnostic.IDE0040.severity = warning
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # We'll let Git's auto-detection algorithm infer if a file is text. If it is,
2 | # enforce CRLF line endings regardless of OS or git configurations.
3 | * text=auto eol=crlf
4 |
5 | # Isolate binary files in case the auto-detection algorithm fails and
6 | # marks them as text files (which could brick them).
7 | *.{png,jpg,jpeg,gif,webp,woff,woff2} binary
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | labels: [bug]
4 | assignees:
5 | - waf
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this bug report!
11 | - type: input
12 | id: version
13 | attributes:
14 | label: Version
15 | description: What version of `csharprepl` are you running? You can check with `csharprepl -v`
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: what-happened
20 | attributes:
21 | label: What happened?
22 | description: If you found a crash, please include the output of `csharprepl --trace` in your report.
23 | placeholder: Tell us what you see.
24 | value: "Something went wrong :("
25 | validations:
26 | required: true
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE.yml:
--------------------------------------------------------------------------------
1 | name: Feature
2 | description: Request or design a new feature
3 | labels: [enhancement]
4 | assignees:
5 | - waf
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to discuss this feature!
11 | - type: textarea
12 | id: feature-description
13 | attributes:
14 | label: Feature Description
15 | description: Does this work in other REPLs, and is it compatible across Mac/Linux/Windows?
16 | validations:
17 | required: true
18 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Thanks for creating a PR! Please make sure you've done the following (replace [ ] with [X]):
2 |
3 | From the [Contributing Guidelines](https://github.com/waf/CSharpRepl/blob/main/README.md#contributing):
4 |
5 | - [ ] If adding a new feature, I discussed it's design in an issue first
6 | - [ ] I verified there are no code warnings emitted for my code
7 | - [ ] I've included a unit test, and all the unit tests are passing
8 |
9 | **Pull Request Description**
10 |
11 | Your text goes here
--------------------------------------------------------------------------------
/.github/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | range: 60..80 # test coverage thresholds. 60% and below fails (red), 80% and up passes (green), between is "yellow"
3 | round: down
4 | precision: 1
5 | status:
6 | project:
7 | default:
8 | target: 70% # require new commits to have at least 70% coverage
9 | threshold: 2% # more than 2% coverage drop, fail.
10 | patch:
11 | default:
12 | enabled: no
13 | ignore:
14 | - "**/Microsoft.CodeAnalysis.CSharp.Symbols" # ignore folders and all its contents
15 | - "**/Microsoft.CodeAnalysis.PooledObjects" # ignore folders and all its contents
16 | - "**/Microsoft.CodeAnalysis" # ignore folders and all its contents
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
2 |
3 | version: 2
4 | updates:
5 | - package-ecosystem: nuget
6 | directory: "/"
7 | schedule:
8 | interval: "weekly"
9 | groups:
10 | dotnet-dependencies:
11 | patterns:
12 | - "*"
13 |
--------------------------------------------------------------------------------
/.github/readme_assets/csharprepl.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/waf/CSharpRepl/bd79130d49c06736a2d5f4d56ac7643889ad2328/.github/readme_assets/csharprepl.mp4
--------------------------------------------------------------------------------
/.github/readme_assets/csharprepl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/waf/CSharpRepl/bd79130d49c06736a2d5f4d56ac7643889ad2328/.github/readme_assets/csharprepl.png
--------------------------------------------------------------------------------
/.github/readme_assets/nuget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/waf/CSharpRepl/bd79130d49c06736a2d5f4d56ac7643889ad2328/.github/readme_assets/nuget.png
--------------------------------------------------------------------------------
/.github/readme_assets/vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/waf/CSharpRepl/bd79130d49c06736a2d5f4d56ac7643889ad2328/.github/readme_assets/vscode.png
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main build
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - main
8 |
9 | jobs:
10 | build:
11 | strategy:
12 | matrix:
13 | platform: [ubuntu-latest, windows-latest]
14 |
15 | runs-on: ${{ matrix.platform }}
16 |
17 | steps:
18 | - uses: actions/checkout@230611dbd0eb52da1e1f4f7bc8bb0c3a339fc8b7
19 |
20 | - name: Install Dotnet
21 | uses: actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a
22 | with:
23 | dotnet-version: '9.0.x'
24 |
25 | - name: Dotnet Installation Info
26 | run: dotnet --info
27 |
28 | - name: Build
29 | run: dotnet build
30 |
31 | - name: Test
32 | run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
33 |
34 | - name: Report Code Coverage
35 | if: matrix.platform == 'windows-latest' # only generate and upload code coverage once
36 | uses: codecov/codecov-action@260aa3b4b2f265b8578bc0e721e33ebf8ff53313
37 | with:
38 | token: ${{ secrets.CODECOV_TOKEN }}
39 | files: CSharpRepl.Tests/coverage.opencover.xml
40 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # On pushing a tag like v0.3.2, publish to nuget.org
2 | # Use publish-release.ps1 to push a release
3 | name: release
4 |
5 | on:
6 | push:
7 | tags:
8 | - "v[0-9]+.*" # not a regex! ".*" means a period followed by any character https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: windows-latest
14 |
15 | steps:
16 | - uses: actions/checkout@230611dbd0eb52da1e1f4f7bc8bb0c3a339fc8b7
17 |
18 | - name: Install Dotnet
19 | uses: actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a
20 | with:
21 | dotnet-version: '9.0.x'
22 |
23 | - name: Dotnet Installation Info
24 | run: dotnet --info
25 |
26 | - name: Pack
27 | run: dotnet pack -c Release /p:ContinuousIntegrationBuild=true
28 |
29 | # publish to nuget. This will publish both a nupkg and snupkg file.
30 | - name: Publish
31 | shell: pwsh
32 | run: |
33 | pwd
34 | cd CSharpRepl/nupkg
35 | ls
36 | dotnet nuget push CSharpRepl.*.nupkg --api-key=${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
37 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (console)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | "program": "${workspaceFolder}/CSharpRepl/bin/Debug/net5.0/CSharpRepl.dll",
13 | "args": [],
14 | "cwd": "${workspaceFolder}/CSharpRepl",
15 | "console": "integratedTerminal",
16 | "stopAtEntry": false
17 | },
18 | {
19 | "name": ".NET Core Attach",
20 | "type": "coreclr",
21 | "request": "attach"
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/CSharpRepl/CSharpRepl.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/CSharpRepl/CSharpRepl.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "${workspaceFolder}/CSharpRepl/CSharpRepl.csproj",
36 | "/property:GenerateFullPaths=true",
37 | "/consoleloggerparameters:NoSummary"
38 | ],
39 | "problemMatcher": "$msCompile"
40 | }
41 | ]
42 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | If you'd like to help out, thanks! We use Visual Studio 2022 for development, though any standard .NET 5 development environment should work. Please read through these guidelines to get started:
4 |
5 | - Read through the ARCHITECTURE.md file to understand how csharprepl works. Depending on what you want to do, changes to the underlying PrettyPrompt library may be required.
6 | - For new features, please open an issue first to discuss and design the feature. This will help reduce the chance of conflicting designs.
7 | - Please include an xunit test, and ensure any code warnings and nullability issues are resolved.
8 |
9 | Thanks!
10 |
11 | ## CSharpRepl Contributors
12 |
13 | Thanks to everyone who contributes! The following contributors have helped out with CSharpRepl:
14 |
15 | - Hubert Kindermann ([kindermannhubert](https://github.com/kindermannhubert))
16 | - [IBIT-ZEE](https://github.com/IBIT-ZEE)
17 | - Nattapong Nunpan ([aixasz](https://github.com/aixasz))
18 | - Ivan Kara ([realivanjx](https://github.com/realivanjx))
19 | - José Javier Rodríguez Zas (JJ) ([jjavierdguezas](https://github.com/jjavierdguezas))
20 | - Marlon Regenhardt ([Regenhardt](https://github.com/Regenhardt))
21 | - Luiz-Ossinho ([Luiz-Ossinho](https://github.com/Luiz-Ossinho))
22 | - Vinod Pal ([VNDPAL](https://github.com/VNDPAL))
23 | - Rasim Keita ([Keyros](https://github.com/Keyros))
24 | - Atif Aziz ([atifaziz](https://github.com/atifaziz))
25 | - [lonix1](https://github.com/lonix1)
26 | - Weihan Li ([WeihanLi](https://github.com/WeihanLi))
27 |
28 | ## PrettyPrompt Contributors
29 |
30 | CSharpRepl heavily relies on the PrettyPrompt library, so make sure to check out the [contributors](https://github.com/waf/PrettyPrompt/blob/main/CONTRIBUTORS.md) there, too!
31 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/CSharpRepl.Services.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | PreserveNewest
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Completion/OpenAICompleteService.cs:
--------------------------------------------------------------------------------
1 | #region License Header
2 | // This Source Code Form is subject to the terms of the Mozilla Public
3 | // License, v. 2.0. If a copy of the MPL was not distributed with this
4 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 | #endregion
6 |
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Net.Http;
11 | using System.Runtime.CompilerServices;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 | using OpenAI.Chat;
15 |
16 | namespace CSharpRepl.Services.Completion;
17 |
18 | ///
19 | /// Call the OpenAI API to get C# completions. Requires an OpenAI API token (which can be purchased from OpenAI).
20 | ///
21 | public class OpenAICompleteService
22 | {
23 | public const int DefaultHistoryEntryCount = 5;
24 | public const string DefaultModel = "gpt-4o";
25 | public const string DefaultPrompt =
26 | "// Complete the following C# code that will be run in a REPL. Do not output markdown code fences like ```. "
27 | + "Prefer functions, statements, and expressions instead of a full program. Prefer modern, terse C# over more verbose C#. "
28 | + "Never comment what the code prints. Any plain-text, English answers MUST be in a C# comment, and C# code should not be inside comments.";
29 | public const string ApiKeyEnvironmentVariableName = "OPENAI_API_KEY";
30 |
31 | private readonly ChatClient? client; // null if no Open AI API key is available.
32 | private readonly SystemChatMessage? prompt;
33 |
34 | public OpenAICompleteService(OpenAIConfiguration? configuration, ChatClient? chatClient = null)
35 | {
36 | if (configuration is null || string.IsNullOrEmpty(configuration.ApiKey))
37 | {
38 | return;
39 | }
40 |
41 | client = chatClient ?? new ChatClient(configuration.Model, configuration.ApiKey);
42 | prompt = new SystemChatMessage(configuration.Prompt ?? DefaultPrompt);
43 | }
44 |
45 | public static string? ApiKey =>
46 | Environment.GetEnvironmentVariable(ApiKeyEnvironmentVariableName, EnvironmentVariableTarget.Process)
47 | ?? Environment.GetEnvironmentVariable(ApiKeyEnvironmentVariableName, EnvironmentVariableTarget.User);
48 |
49 | public async IAsyncEnumerable CompleteAsync(IReadOnlyList submissions, string code, int caret, [EnumeratorCancellation] CancellationToken cancellationToken)
50 | {
51 | if (client is null)
52 | {
53 | yield break;
54 | }
55 |
56 | var input = new ChatMessage[] { prompt! }
57 | .Concat(submissions.Append(code).Select(s => new UserChatMessage(s)))
58 | .ToArray();
59 |
60 | var output = client.CompleteChatStreamingAsync(input, cancellationToken: cancellationToken);
61 |
62 | await foreach (var update in output.WithCancellation(cancellationToken))
63 | {
64 | if (update is null or { ContentUpdate.Count: 0 })
65 | {
66 | continue;
67 | }
68 | var content = update.ContentUpdate[0].Text;
69 | if (string.IsNullOrEmpty(content))
70 | {
71 | yield return "\n";
72 | }
73 | yield return content.Replace("\t", " ");
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Dotnet/DotnetBuilder.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Collections.Immutable;
8 | using System.Diagnostics;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace CSharpRepl.Services.Dotnet;
13 |
14 | internal class DotnetBuilder
15 | {
16 | private readonly IConsoleEx console;
17 |
18 | public DotnetBuilder(IConsoleEx console)
19 | {
20 | this.console = console;
21 | }
22 |
23 | public (int exitCode, ImmutableArray outputLines) Build(string path)
24 | {
25 | using var process = StartBuild(path, out var output);
26 | process.WaitForExit();
27 | return (process.ExitCode, output.ToImmutableArray());
28 | }
29 |
30 | public async Task<(int exitCode, ImmutableArray outputLines)> BuildAsync(string path, CancellationToken cancellationToken)
31 | {
32 | using var process = StartBuild(path, out var output);
33 | await process.WaitForExitAsync(cancellationToken);
34 | return (process.ExitCode, output.ToImmutableArray());
35 | }
36 |
37 | private Process StartBuild(string path, out List output)
38 | {
39 | output = [];
40 | var process = new Process
41 | {
42 | StartInfo =
43 | {
44 | FileName = OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet",
45 | ArgumentList = { "build", path },
46 | RedirectStandardOutput = true
47 | }
48 | };
49 |
50 | var outputForClosure = output;
51 | process.OutputDataReceived += (_, data) =>
52 | {
53 | if (data.Data is null) return;
54 |
55 | outputForClosure.Add(data.Data);
56 | console.WriteLine(data.Data);
57 | };
58 |
59 | console.WriteLine("Building " + path);
60 | process.Start();
61 | process.BeginOutputReadLine();
62 | return process;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Extensions/KeyExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using PrettyPrompt.Consoles;
4 |
5 | namespace CSharpRepl.Services.Extensions;
6 |
7 | public static class KeyExtensions
8 | {
9 | public static string GetStringValue(this KeyPressPattern pattern)
10 | {
11 | if (pattern.Key != default)
12 | {
13 | return pattern.Modifiers == default
14 | ? $"{pattern.Key}"
15 | : $"{pattern.Modifiers.GetStringValue()}+{pattern.Key}";
16 | }
17 | return $"{pattern.Character}";
18 | }
19 |
20 | private static string GetStringValue(this ConsoleModifiers modifiers)
21 | {
22 | var values = new[] { ConsoleModifiers.Control, ConsoleModifiers.Alt, ConsoleModifiers.Shift }
23 | .Where(x => modifiers.HasFlag(x))
24 | .OrderDescending()
25 | .Select(x => x.ToString());
26 | return string.Join("+", values);
27 | }
28 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Extensions/LinqExtensions.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace CSharpRepl.Services.Extensions;
9 |
10 | internal static class LinqExtensions
11 | {
12 | // purely for nullable reference type analysis
13 | public static IEnumerable WhereNotNull(this IEnumerable source) where T : class
14 | {
15 | return source.Where(x => x != null)!;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Extensions/MiscExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace CSharpRepl.Services.Extensions;
4 |
5 | internal static class MiscExtensions
6 | {
7 | public static bool TryGet(this T? nullableValue, out T value)
8 | where T : struct
9 | {
10 | if (nullableValue.HasValue)
11 | {
12 | value = nullableValue.GetValueOrDefault();
13 | return true;
14 | }
15 | else
16 | {
17 | value = default;
18 | return false;
19 | }
20 | }
21 |
22 | public static bool TryGet(this T? nullableValue, [MaybeNullWhen(false)] out T value)
23 | where T : class
24 | {
25 | if (nullableValue is null)
26 | {
27 | value = null;
28 | return false;
29 | }
30 | else
31 | {
32 | value = nullableValue;
33 | return true;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Extensions/SpectreExtensions.cs:
--------------------------------------------------------------------------------
1 | using CSharpRepl.Services.Theming;
2 | using Spectre.Console;
3 |
4 | namespace CSharpRepl.Services.Extensions;
5 |
6 | internal static class SpectreExtensions
7 | {
8 | public static Paragraph Append(this Paragraph paragraph, StyledStringSegment text)
9 | => paragraph.Append(text.Text, text.Style);
10 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | // This file is used by Code Analysis to maintain SuppressMessage
6 | // attributes that are applied to this project.
7 | // Project-level suppressions either have no target or are given
8 | // a specific target and scoped to a namespace, type, member, etc.
9 |
10 | using System.Diagnostics.CodeAnalysis;
11 |
12 | [assembly: SuppressMessage("Performance", "CA1822:Mark members as static")]
13 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/IConsoleEx.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using PrettyPrompt.Consoles;
6 | using PrettyPrompt.Highlighting;
7 | using Spectre.Console;
8 | using Spectre.Console.Rendering;
9 |
10 | namespace CSharpRepl.Services;
11 |
12 | public interface IConsoleEx : IAnsiConsole
13 | {
14 | IConsole PrettyPromptConsole { get; }
15 |
16 | private IAnsiConsole AnsiConsole => this;
17 |
18 | void Write(string text) => AnsiConsole.Write(text);
19 | void Write(FormattedString text) => PrettyPromptConsole.Write(text);
20 |
21 | void WriteLine(string text) => AnsiConsole.WriteLine(text);
22 | void WriteLine() => AnsiConsole.WriteLine();
23 | void WriteLine(FormattedString text) => PrettyPromptConsole.WriteLine(text);
24 |
25 | void WriteError(string text)
26 | {
27 | if (PrettyPromptConsole.IsErrorRedirected)
28 | {
29 | PrettyPromptConsole.WriteError(text);
30 | }
31 | else
32 | {
33 | //AnsiConsole is smarter about word wrapping
34 | Write(text);
35 | }
36 | }
37 |
38 | /// Text written to error stream (used only if error stream is redirected).
39 | void WriteError(IRenderable renderable, string text)
40 | {
41 | if (PrettyPromptConsole.IsErrorRedirected)
42 | {
43 | PrettyPromptConsole.WriteError(text);
44 | }
45 | else
46 | {
47 | //AnsiConsole is smarter about word wrapping
48 | Write(renderable);
49 | }
50 | }
51 |
52 | /// Text written to error stream (used only if error stream is redirected).
53 | void WriteErrorLine(IRenderable renderable, string text)
54 | {
55 | if (PrettyPromptConsole.IsErrorRedirected)
56 | {
57 | PrettyPromptConsole.WriteErrorLine(text);
58 | }
59 | else
60 | {
61 | //AnsiConsole is smarter about word wrapping
62 | Write(renderable);
63 | WriteLine();
64 | }
65 | }
66 |
67 | void WriteErrorLine(string text)
68 | {
69 | if (PrettyPromptConsole.IsErrorRedirected)
70 | {
71 | PrettyPromptConsole.WriteErrorLine(text);
72 | }
73 | else
74 | {
75 | //AnsiConsole is smarter about word wrapping
76 | WriteLine(text);
77 | }
78 | }
79 |
80 | string? ReadLine();
81 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Logging/ITraceLogger.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 |
8 | namespace CSharpRepl.Services.Logging;
9 |
10 | public interface ITraceLogger
11 | {
12 | void Log(string message);
13 | void Log(Func message);
14 | void LogPaths(string message, Func> paths);
15 | }
16 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Nuget/NugetHelper.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Diagnostics.CodeAnalysis;
7 | using System.IO;
8 | using System.Reflection;
9 | using System.Runtime.Versioning;
10 | using NuGet.Frameworks;
11 | using NuGet.RuntimeModel;
12 |
13 | namespace CSharpRepl.Services.Nuget;
14 |
15 | internal static class NugetHelper
16 | {
17 | private const string RuntimeFileName = "runtime.json";
18 |
19 | public static RuntimeGraph GetRuntimeGraph(Action? error)
20 | {
21 | var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
22 | if (dir != null)
23 | {
24 | var path = Path.Combine(dir, RuntimeFileName);
25 | if (File.Exists(path))
26 | {
27 | using var stream = File.OpenRead(path);
28 | return JsonRuntimeFormat.ReadRuntimeGraph(stream);
29 | }
30 | }
31 | error?.Invoke($"Cannot find '{RuntimeFileName}' in '{dir}'");
32 | return new RuntimeGraph();
33 | }
34 |
35 | public static bool TryGetCurrentFramework([NotNullWhen(true)] out NuGetFramework? result)
36 | {
37 | var assembly = Assembly.GetEntryAssembly();
38 | if (assembly is null ||
39 | assembly.Location.EndsWith("testhost.dll", StringComparison.OrdinalIgnoreCase)) //for unit tests (testhost.dll targets netcoreapp2.1 instead of net6.0)
40 | {
41 | assembly = Assembly.GetExecutingAssembly();
42 | }
43 |
44 | var targetFrameworkAttribute = assembly.GetCustomAttribute();
45 | if (targetFrameworkAttribute is null)
46 | {
47 | result = null;
48 | return false;
49 | }
50 |
51 | result = NuGetFramework.Parse(targetFrameworkAttribute.FrameworkName);
52 | return true;
53 | }
54 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/DocumentationCommentXmlNames.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | //Modified copy of https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/InternalUtilities/DocumentationCommentXmlNames.cs
6 |
7 | using System;
8 |
9 | namespace CSharpRepl.Services.Roslyn;
10 |
11 | ///
12 | /// Names of well-known XML attributes and elements.
13 | ///
14 | internal static class DocumentationCommentXmlNames
15 | {
16 | public const string CElementName = "c";
17 | public const string CodeElementName = "code";
18 | public const string CompletionListElementName = "completionlist";
19 | public const string DescriptionElementName = "description";
20 | public const string ExampleElementName = "example";
21 | public const string ExceptionElementName = "exception";
22 | public const string IncludeElementName = "include";
23 | public const string InheritdocElementName = "inheritdoc";
24 | public const string ItemElementName = "item";
25 | public const string ListElementName = "list";
26 | public const string ListHeaderElementName = "listheader";
27 | public const string ParaElementName = "para";
28 | public const string ParameterElementName = "param";
29 | public const string ParameterReferenceElementName = "paramref";
30 | public const string PermissionElementName = "permission";
31 | public const string PlaceholderElementName = "placeholder";
32 | public const string PreliminaryElementName = "preliminary";
33 | public const string RemarksElementName = "remarks";
34 | public const string ReturnsElementName = "returns";
35 | public const string SeeElementName = "see";
36 | public const string SeeAlsoElementName = "seealso";
37 | public const string SummaryElementName = "summary";
38 | public const string TermElementName = "term";
39 | public const string ThreadSafetyElementName = "threadsafety";
40 | public const string TypeParameterElementName = "typeparam";
41 | public const string TypeParameterReferenceElementName = "typeparamref";
42 | public const string ValueElementName = "value";
43 |
44 | public const string CrefAttributeName = "cref";
45 | public const string HrefAttributeName = "href";
46 | public const string FileAttributeName = "file";
47 | public const string InstanceAttributeName = "instance";
48 | public const string LangwordAttributeName = "langword";
49 | public const string NameAttributeName = "name";
50 | public const string PathAttributeName = "path";
51 | public const string StaticAttributeName = "static";
52 | public const string TypeAttributeName = "type";
53 |
54 | public static bool ElementEquals(string name1, string name2, bool fromVb = false)
55 | {
56 | return string.Equals(name1, name2, fromVb ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
57 | }
58 |
59 | public static bool AttributeEquals(string name1, string name2)
60 | {
61 | return string.Equals(name1, name2, StringComparison.Ordinal);
62 | }
63 |
64 | public static new bool Equals(object left, object right)
65 | {
66 | return object.Equals(left, right);
67 | }
68 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/CustomObjectFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using CSharpRepl.Services.Roslyn.Formatting.Rendering;
7 | using CSharpRepl.Services.SyntaxHighlighting;
8 | using CSharpRepl.Services.Theming;
9 | using Spectre.Console;
10 |
11 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
12 |
13 | internal interface ICustomObjectFormatter
14 | {
15 | ///
16 | /// Is this formatter to the value?
17 | ///
18 | bool IsApplicable(object value);
19 |
20 | StyledString FormatToText(object value, Level level, Formatter formatter);
21 | FormattedObjectRenderable FormatToRenderable(object value, Level level, Formatter formatter);
22 | }
23 |
24 | internal abstract class CustomObjectFormatter : ICustomObjectFormatter
25 | {
26 | public virtual bool IsApplicable(object value)
27 | {
28 | if (value is null) return true;
29 | return value.GetType().IsAssignableTo(Type);
30 | }
31 |
32 | public abstract Type Type { get; }
33 |
34 | public abstract StyledString FormatToText(object value, Level level, Formatter formatter);
35 |
36 | public virtual FormattedObjectRenderable FormatToRenderable(object value, Level level, Formatter formatter)
37 | => new(FormatToText(value, level, formatter).ToParagraph(), renderOnNewLine: false);
38 | }
39 |
40 | internal abstract class CustomObjectFormatter : CustomObjectFormatter
41 | where T : notnull
42 | {
43 | public sealed override Type Type => typeof(T);
44 |
45 | public sealed override StyledString FormatToText(object value, Level level, Formatter formatter)
46 | => FormatToText((T)value, level, formatter);
47 |
48 | public sealed override FormattedObjectRenderable FormatToRenderable(object value, Level level, Formatter formatter)
49 | => FormatToRenderable((T)value, level, formatter);
50 |
51 | public abstract StyledString FormatToText(T value, Level level, Formatter formatter);
52 |
53 | public virtual FormattedObjectRenderable FormatToRenderable(T value, Level level, Formatter formatter)
54 | => base.FormatToRenderable(value, level, formatter);
55 | }
56 |
57 | internal class Formatter
58 | {
59 | private readonly PrettyPrinter prettyPrinter;
60 | private readonly SyntaxHighlighter syntaxHighlighter;
61 |
62 | public StyledStringSegment NullLiteral => prettyPrinter.NullLiteral;
63 | public Style KeywordStyle => syntaxHighlighter.KeywordStyle;
64 | public Profile ConsoleProfile { get; }
65 |
66 | public Formatter(PrettyPrinter prettyPrinter, SyntaxHighlighter syntaxHighlighter, Profile consoleProfile)
67 | {
68 | this.prettyPrinter = prettyPrinter;
69 | this.syntaxHighlighter = syntaxHighlighter;
70 | ConsoleProfile = consoleProfile;
71 | }
72 |
73 | public StyledString FormatObjectToText(object? obj, Level level)
74 | => prettyPrinter.FormatObjectToText(obj, level);
75 |
76 | public FormattedObjectRenderable FormatObjectToRenderable(object? obj, Level level)
77 | => prettyPrinter.FormatObjectToRenderable(obj, level);
78 |
79 | public StyledString FormatTypeName(Type type, bool showNamespaces, bool useLanguageKeywords, bool hideSystemNamespace)
80 | => prettyPrinter.FormatTypeName(type, showNamespaces, useLanguageKeywords, hideSystemNamespace);
81 |
82 | public Style GetStyle(string? classification)
83 | => syntaxHighlighter.GetStyle(classification);
84 |
85 | public StyledString GetValueRetrievalExceptionText(Exception exception, Level level)
86 | => prettyPrinter.GetValueRetrievalExceptionText(exception, level);
87 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/GuidFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using CSharpRepl.Services.Theming;
7 | using Microsoft.CodeAnalysis.Classification;
8 |
9 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
10 |
11 | internal sealed class GuidFormatter : CustomObjectFormatter
12 | {
13 | public static readonly GuidFormatter Instance = new();
14 |
15 | private GuidFormatter() { }
16 |
17 | public override StyledString FormatToText(Guid value, Level level, Formatter formatter)
18 | {
19 | //32 digits separated by hyphens: 00000000-0000-0000-0000-000000000000
20 | var parts = value.ToString().Split('-');
21 | var style = formatter.GetStyle(ClassificationTypeNames.NumericLiteral);
22 | return new StyledString(
23 | [
24 | new(parts[0], style),
25 | new("-"),
26 | new(parts[1], style),
27 | new("-"),
28 | new(parts[2], style),
29 | new("-"),
30 | new(parts[3], style),
31 | new("-"),
32 | new(parts[4], style)
33 | ]);
34 | }
35 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/KeyValuePairFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using CSharpRepl.Services.Theming;
8 |
9 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
10 |
11 | internal sealed class KeyValuePairFormatter : CustomObjectFormatter
12 | {
13 | public static readonly KeyValuePairFormatter Instance = new();
14 |
15 | public override Type Type => typeof(KeyValuePair<,>);
16 |
17 | private KeyValuePairFormatter() { }
18 |
19 | public override bool IsApplicable(object value)
20 | => value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == Type;
21 |
22 | public override StyledString FormatToText(object value, Level level, Formatter formatter)
23 | {
24 | var sb = new StyledStringBuilder();
25 |
26 | dynamic kv = value;
27 | if (level == Level.FirstDetailed)
28 | {
29 | // KeyValuePair { key, value }
30 | sb.Append(formatter.FormatTypeName(value.GetType(), showNamespaces: false, useLanguageKeywords: true, hideSystemNamespace: true));
31 | sb.Append(" { ");
32 | sb.Append(formatter.FormatObjectToText(kv.Key, level));
33 | sb.Append(", ");
34 | sb.Append(formatter.FormatObjectToText(kv.Value, level));
35 | }
36 | else if (level == Level.FirstSimple)
37 | {
38 | // { Key: key, Value: value }
39 | sb.Append("{ Key: ");
40 | sb.Append(formatter.FormatObjectToText(kv.Key, level));
41 | sb.Append(", Value: ");
42 | sb.Append(formatter.FormatObjectToText(kv.Value, level));
43 | }
44 | else
45 | {
46 | // { key, value }
47 | sb.Append("{ ");
48 | sb.Append(formatter.FormatObjectToText(kv.Key, level));
49 | sb.Append(", ");
50 | sb.Append(formatter.FormatObjectToText(kv.Value, level));
51 | }
52 | sb.Append(" }");
53 |
54 | return sb.ToStyledString();
55 | }
56 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/MethodInfoFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Linq;
6 | using System.Reflection;
7 | using CSharpRepl.Services.Theming;
8 | using Microsoft.CodeAnalysis.Classification;
9 |
10 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
11 |
12 | internal sealed class MethodInfoFormatter : CustomObjectFormatter
13 | {
14 | public static readonly MethodInfoFormatter Instance = new();
15 |
16 | private MethodInfoFormatter() { }
17 |
18 | public override StyledString FormatToText(MethodInfo value, Level level, Formatter formatter)
19 | {
20 | var methodNameStyle = formatter.GetStyle(ClassificationTypeNames.MethodName);
21 | var typeFormatter = TypeFormatter.Instance;
22 |
23 | var sb = new StyledStringBuilder();
24 |
25 | //modifiers
26 | if (level is Level.FirstDetailed or Level.FirstSimple)
27 | {
28 | var modifiers = string.Join(" ", ReflectionHelpers.GetModifiers(value));
29 | sb.Append(modifiers, formatter.KeywordStyle)
30 | .Append(' ');
31 | }
32 |
33 | //return type
34 | if (level < Level.ThirdPlus)
35 | {
36 | AppendReturnType(level is Level.FirstDetailed ? level : level.Increment()).Append(' ');
37 | }
38 |
39 | //name
40 | string name;
41 | if (level is Level.FirstDetailed)
42 | {
43 | name = value.Name;
44 | }
45 | else
46 | {
47 | var nameParts = value.Name.Split('.');
48 | name = string.Join(".", nameParts.TakeLast(level is Level.FirstSimple ? 2 : 1)); //"interface.method" or "method" without namespace
49 | }
50 | sb.Append(name, methodNameStyle);
51 |
52 | if (level < Level.ThirdPlus)
53 | {
54 | //generic arguments
55 | if (value.IsGenericMethod)
56 | {
57 | sb.Append('<');
58 | foreach (var a in value.GetGenericArguments())
59 | {
60 | sb.Append(typeFormatter.FormatToText(a, level, formatter));
61 | }
62 | sb.Append('>');
63 | }
64 |
65 | //parameters
66 | sb.Append('(');
67 | var parameters = value.GetParameters();
68 | for (int i = 0; i < parameters.Length; i++)
69 | {
70 | var p = parameters[i];
71 | sb.Append(typeFormatter.FormatToText(p.ParameterType, level, formatter));
72 |
73 | if (level < Level.Second)
74 | {
75 | sb.Append(' ').Append(p.Name);
76 | }
77 |
78 | if (i != parameters.Length - 1) sb.Append(", ");
79 | }
80 | sb.Append(')');
81 | }
82 |
83 | return sb.ToStyledString();
84 |
85 | StyledStringBuilder AppendReturnType(Level level)
86 | {
87 | return
88 | value.ReturnType == typeof(void) ?
89 | sb.Append(new StyledString("void", formatter.KeywordStyle)) :
90 | sb.Append(typeFormatter.FormatToText(value.ReturnType, level, formatter));
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/ReflectionHelpers.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Generic;
6 | using System.Reflection;
7 |
8 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
9 |
10 | internal static class ReflectionHelpers
11 | {
12 | public static IEnumerable GetModifiers(MethodInfo methodInfo)
13 | {
14 | if (methodInfo.IsPrivate) yield return "private";
15 | else if (methodInfo.IsFamily) yield return "protected";
16 | else if (methodInfo.IsFamilyOrAssembly) yield return "protected internal";
17 | else if (methodInfo.IsFamilyAndAssembly) yield return "private protected";
18 | else if (methodInfo.IsAssembly) yield return "internal";
19 | else if (methodInfo.IsPublic) yield return "public";
20 |
21 | if (methodInfo.IsStatic) yield return "static";
22 |
23 | if (methodInfo.IsAbstract) yield return "abstract";
24 | else if (methodInfo.IsVirtual) yield return "virtual";
25 | }
26 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/TupleFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Runtime.CompilerServices;
6 | using CSharpRepl.Services.Theming;
7 |
8 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
9 |
10 | internal sealed class TupleFormatter : CustomObjectFormatter
11 | {
12 | public static readonly TupleFormatter Instance = new();
13 |
14 | private TupleFormatter() { }
15 |
16 | public override StyledString FormatToText(ITuple value, Level level, Formatter formatter)
17 | {
18 | var sb = new StyledStringBuilder();
19 |
20 | sb.Append('(');
21 | for (int i = 0; i < value.Length; i++)
22 | {
23 | sb.Append(formatter.FormatObjectToText(value[i], level));
24 |
25 | bool isLast = i == value.Length - 1;
26 | if (!isLast) sb.Append(", ");
27 | }
28 | sb.Append(')');
29 |
30 | return sb.ToStyledString();
31 | }
32 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/CustomObjectFormatters/TypeFormatter.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using CSharpRepl.Services.Theming;
7 |
8 | namespace CSharpRepl.Services.Roslyn.Formatting.CustomObjectFormatters;
9 |
10 | internal sealed class TypeFormatter : CustomObjectFormatter
11 | {
12 | public static readonly TypeFormatter Instance = new();
13 |
14 | private TypeFormatter() { }
15 |
16 | public override StyledString FormatToText(Type value, Level level, Formatter formatter)
17 | {
18 | return formatter.FormatTypeName(
19 | value,
20 | showNamespaces: level == Level.FirstDetailed,
21 | useLanguageKeywords: level != Level.FirstDetailed,
22 | hideSystemNamespace: false);
23 | }
24 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/FormattedObject.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Spectre.Console.Rendering;
3 |
4 | namespace CSharpRepl.Services.Roslyn.Formatting;
5 |
6 | internal readonly struct FormattedObject
7 | {
8 | public readonly IRenderable Renderable;
9 | public readonly object? Value;
10 |
11 | public FormattedObject(IRenderable renderable, object? value)
12 | {
13 | Renderable = renderable;
14 | Value = value;
15 | }
16 |
17 | public IEnumerable FormatMembers(PrettyPrinter prettyPrinter, Level level, bool includeNonPublic)
18 | {
19 | if (Value is null) return [];
20 |
21 | return prettyPrinter.FormatMembers(Value, level.Increment(), includeNonPublic);
22 | }
23 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/LengthLimiting.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using CSharpRepl.Services.Theming;
7 | using Spectre.Console;
8 |
9 | namespace CSharpRepl.Services.Roslyn.Formatting;
10 |
11 | public static class LengthLimiting
12 | {
13 | public static int GetMaxParagraphLength(Level level, Profile profile)
14 | {
15 | var ratio = level switch
16 | {
17 | Level.FirstDetailed => 2,
18 | Level.FirstSimple => 0.4,
19 | Level.Second => 0.2,
20 | Level.ThirdPlus => 0.1,
21 | _ => throw new InvalidOperationException("unexpected level")
22 | };
23 |
24 | return (int)(ratio * profile.Width * profile.Height);
25 | }
26 |
27 | public static int GetTableMaxItems(Level level, Profile profile)
28 | {
29 | var ratio = level switch
30 | {
31 | Level.FirstDetailed => 2,
32 | Level.FirstSimple => 0.5,
33 | Level.Second => 0.4,
34 | Level.ThirdPlus => 0.3,
35 | _ => throw new InvalidOperationException("unexpected level")
36 | };
37 |
38 | return (int)(ratio * profile.Height);
39 | }
40 |
41 | public static int GetTreeMaxItems(Level level, Profile profile)
42 | {
43 | var ratio = level switch
44 | {
45 | Level.FirstDetailed => 2,
46 | Level.FirstSimple => 0.5,
47 | Level.Second => 0.4,
48 | Level.ThirdPlus => 0.3,
49 | _ => throw new InvalidOperationException("unexpected level")
50 | };
51 |
52 | return (int)(ratio * profile.Height);
53 | }
54 |
55 | public static string LimitLength(string? value, Level level, Profile profile)
56 | {
57 | if (string.IsNullOrEmpty(value)) return "";
58 | var maxLen = GetMaxParagraphLength(level, profile);
59 | if (value.Length > maxLen)
60 | {
61 | value = string.Concat(value.AsSpan(0, maxLen), "...");
62 | }
63 | return value;
64 | }
65 |
66 | public static StyledStringSegment LimitLength(StyledStringSegment value, Level level, Profile profile)
67 | {
68 | var maxLen = GetMaxParagraphLength(level, profile);
69 | if (value.Length > maxLen)
70 | {
71 | value = value.Substring(0, maxLen) + "...";
72 | }
73 | return value;
74 | }
75 |
76 | public static StyledString LimitLength(StyledString value, Level level, Profile profile)
77 | {
78 | var maxLen = GetMaxParagraphLength(level, profile);
79 | if (value.Length > maxLen)
80 | {
81 | value = value.Substring(0, maxLen) + "...";
82 | }
83 | return value;
84 | }
85 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/Level.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 |
7 | namespace CSharpRepl.Services.Roslyn.Formatting;
8 |
9 | public enum Level
10 | {
11 | FirstDetailed,
12 | FirstSimple,
13 | Second,
14 | ThirdPlus
15 | }
16 |
17 | internal static class LevelX
18 | {
19 | public static Level Increment(this Level level) => (Level)Math.Min((int)level + 1, (int)Level.ThirdPlus);
20 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/Rendering/FormattedObjectRenderable.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Generic;
6 | using Spectre.Console.Rendering;
7 |
8 | namespace CSharpRepl.Services.Roslyn.Formatting.Rendering;
9 |
10 | internal sealed class FormattedObjectRenderable : IRenderable
11 | {
12 | private readonly IRenderable renderable;
13 | private readonly bool renderOnNewLine;
14 |
15 | public FormattedObjectRenderable(IRenderable renderable, bool renderOnNewLine)
16 | {
17 | this.renderable = renderable;
18 | this.renderOnNewLine = renderOnNewLine;
19 | }
20 |
21 | public Measurement Measure(RenderOptions options, int maxWidth)
22 | => renderable.Measure(options, maxWidth);
23 |
24 | public IEnumerable Render(RenderOptions options, int maxWidth)
25 | {
26 | if (renderOnNewLine)
27 | {
28 | yield return Segment.LineBreak;
29 | }
30 | foreach (var segment in renderable.Render(options, maxWidth))
31 | {
32 | yield return segment;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Formatting/Rendering/RenderableSequence.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Generic;
6 | using Spectre.Console.Rendering;
7 |
8 | namespace CSharpRepl.Services.Roslyn.Formatting.Rendering;
9 |
10 | internal sealed class RenderableSequence : Renderable
11 | {
12 | private readonly Wrap[] items;
13 |
14 | public RenderableSequence(IRenderable r1, IRenderable r2, bool separateByLineBreak)
15 | {
16 | items = [new(r1, separateByLineBreak), new(r2, false)];
17 | }
18 |
19 | protected override IEnumerable Render(RenderOptions options, int maxWidth)
20 | {
21 | foreach (var item in items)
22 | {
23 | foreach (var segment in item.Renderable.Render(options, maxWidth))
24 | {
25 | yield return segment;
26 | }
27 |
28 | if (item.UseLineBreak)
29 | {
30 | yield return Segment.LineBreak;
31 | }
32 | }
33 | }
34 |
35 | private readonly struct Wrap
36 | {
37 | public readonly IRenderable Renderable;
38 | public readonly bool UseLineBreak;
39 |
40 | public Wrap(IRenderable renderable, bool useLineBreak)
41 | {
42 | Renderable = renderable;
43 | UseLineBreak = useLineBreak;
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/MetadataResolvers/AlternativeReferenceResolver.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Immutable;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Microsoft.CodeAnalysis;
9 |
10 | namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
11 | ///
12 | /// An alternative to MetadataReferenceResolver.ResolveReference.
13 | /// This can be used when multiple references can be added from a single ResolveReference call, as Roslyn does not yet support it (https://github.com/dotnet/roslyn/issues/6900).
14 | ///
15 | public abstract class AlternativeReferenceResolver : IIndividualMetadataReferenceResolver
16 | {
17 | public static PortableExecutableReference DummyReference { get; } = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
18 |
19 | public ImmutableArray ResolveReference(string reference, string? baseFilePath, MetadataReferenceProperties properties, MetadataReferenceResolver compositeResolver)
20 | {
21 | if (CanResolve(reference))
22 | return ImmutableArray.Create(DummyReference);
23 |
24 | return [];
25 | }
26 |
27 | public abstract bool CanResolve(string reference);
28 |
29 | public virtual Task> ResolveAsync(string reference, CancellationToken cancellationToken)
30 | => Task.FromResult(Resolve(reference));
31 |
32 | public virtual ImmutableArray Resolve(string reference)
33 | => [];
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/MetadataResolvers/CompositeAlternativeReferenceResolver.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Immutable;
7 | using System.Linq;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Microsoft.CodeAnalysis;
11 |
12 | namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
13 | internal sealed class CompositeAlternativeReferenceResolver
14 | {
15 | private readonly AlternativeReferenceResolver[] alternativeResolvers;
16 |
17 | public CompositeAlternativeReferenceResolver(params AlternativeReferenceResolver[] alternativeResolvers)
18 | {
19 | this.alternativeResolvers = alternativeResolvers;
20 | }
21 |
22 | public async Task> GetAllAlternativeReferences(string code, CancellationToken cancellationToken)
23 | {
24 | var splitCommands = code.Split(new[] { '\r', '\n' }, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
25 |
26 | var resolveReferencesTasks =
27 | from cmd in splitCommands
28 | from resolver in alternativeResolvers
29 | where resolver.CanResolve(cmd)
30 | select resolver.ResolveAsync(cmd, cancellationToken);
31 |
32 | return (await Task.WhenAll(resolveReferencesTasks))
33 | .SelectMany(r => r)
34 | .ToImmutableArray();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/MetadataResolvers/CompositeMetadataReferenceResolver.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Collections.Immutable;
8 | using System.Linq;
9 | using Microsoft.CodeAnalysis;
10 |
11 | namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
12 |
13 | ///
14 | /// A that is contained by the .
15 | /// It gets a chance to resolve a reference; if it doesn't, the next is called.
16 | ///
17 | internal interface IIndividualMetadataReferenceResolver
18 | {
19 | ImmutableArray ResolveReference(string reference, string? baseFilePath, MetadataReferenceProperties properties, MetadataReferenceResolver compositeResolver);
20 | }
21 |
22 | ///
23 | /// A top-level metadata resolver. We can only specify a single in roslyn scripting.
24 | /// This composite class delegates to individual implementations (nuget resolver, assembly resolver, csproj resolver, etc).
25 | ///
26 | internal sealed class CompositeMetadataReferenceResolver : MetadataReferenceResolver, IEquatable
27 | {
28 | private readonly IIndividualMetadataReferenceResolver[] resolvers;
29 |
30 | public CompositeMetadataReferenceResolver(params IIndividualMetadataReferenceResolver[] resolvers) =>
31 | this.resolvers = resolvers;
32 |
33 | public override ImmutableArray ResolveReference(string reference, string? baseFilePath, MetadataReferenceProperties properties)
34 | {
35 | reference = reference.Trim();
36 |
37 | foreach (var resolver in resolvers)
38 | {
39 | var resolved = resolver.ResolveReference(reference, baseFilePath, properties, this);
40 | if (resolved.Any())
41 | {
42 | return resolved;
43 | }
44 | }
45 |
46 | return [];
47 | }
48 |
49 | public override bool Equals(object? other) =>
50 | Equals(other as CompositeMetadataReferenceResolver);
51 |
52 | public bool Equals(CompositeMetadataReferenceResolver? other) =>
53 | other != null
54 | && EqualityComparer.Default.Equals(resolvers, other.resolvers);
55 |
56 | public override int GetHashCode() =>
57 | HashCode.Combine(resolvers);
58 | }
59 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/MetadataResolvers/NugetPackageMetadataResolver.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Immutable;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using CSharpRepl.Services.Nuget;
10 | using Microsoft.CodeAnalysis;
11 |
12 | namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
13 |
14 | ///
15 | /// Resolves nuget references, e.g. #r "nuget: Newtonsoft.Json" or #r "nuget: Newtonsoft.Json, 13.0.1"
16 | ///
17 | internal sealed class NugetPackageMetadataResolver : AlternativeReferenceResolver
18 | {
19 | private const string NugetPrefix = "nuget:";
20 | private const string NugetPrefixWithHashR = "#r \"" + NugetPrefix;
21 | private readonly NugetPackageInstaller nugetInstaller;
22 |
23 | public NugetPackageMetadataResolver(IConsoleEx console, Configuration configuration)
24 | {
25 | this.nugetInstaller = new NugetPackageInstaller(console, configuration);
26 | }
27 |
28 | public override bool CanResolve(string reference) =>
29 | reference.StartsWith(NugetPrefix, StringComparison.OrdinalIgnoreCase) ||
30 | reference.StartsWith(NugetPrefixWithHashR, StringComparison.OrdinalIgnoreCase); // roslyn trims the "#r" prefix when passing to the resolver, but it has the prefix when called from our ScriptRunner
31 |
32 | public override Task> ResolveAsync(string reference, CancellationToken cancellationToken)
33 | {
34 | // we can be a bit loose in our parsing here, because we were more strict in IsNugetReference.
35 | // the 0th element will be the "nuget" keyword, which we ignore.
36 | var packageParts = reference.Split(
37 | new[] { "#r", "\"", ":", " ", ",", "/", "\\" },
38 | StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries
39 | );
40 |
41 | return packageParts.Length switch
42 | {
43 | 2 => nugetInstaller.InstallAsync(packageId: packageParts[1], cancellationToken: cancellationToken),
44 | 3 => nugetInstaller.InstallAsync(packageId: packageParts[1], version: packageParts[2].TrimStart('v'), cancellationToken),
45 | _ => throw new InvalidOperationException(@"Malformed nuget reference. Expected #r ""nuget: PackageName"" or #r ""nuget: PackageName, version""")
46 | };
47 | }
48 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/MetadataResolvers/SolutionFileMetadataResolver.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Immutable;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using CSharpRepl.Services.Dotnet;
12 | using Microsoft.CodeAnalysis;
13 | using Microsoft.CodeAnalysis.MSBuild;
14 |
15 | namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
16 |
17 | internal sealed class SolutionFileMetadataResolver : AlternativeReferenceResolver
18 | {
19 | private readonly DotnetBuilder builder;
20 | private readonly IConsoleEx console;
21 |
22 | public SolutionFileMetadataResolver(DotnetBuilder builder, IConsoleEx console)
23 | {
24 | this.builder = builder;
25 | this.console = console;
26 | }
27 |
28 | public override bool CanResolve(string reference) =>
29 | reference.EndsWith(".sln", StringComparison.OrdinalIgnoreCase) ||
30 | reference.EndsWith(".sln\"", StringComparison.OrdinalIgnoreCase) ||
31 | reference.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) ||
32 | reference.EndsWith(".csproj\"", StringComparison.OrdinalIgnoreCase);
33 |
34 | public override async Task> ResolveAsync(string reference, CancellationToken cancellationToken)
35 | {
36 | var solutionPath = Path.GetFullPath(reference
37 | .Split('\"', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
38 | .Last());
39 |
40 | var (exitCode, _) = await builder.BuildAsync(solutionPath, cancellationToken);
41 |
42 | if (exitCode != 0)
43 | {
44 | console.WriteErrorLine("Reference not added: build failed.");
45 | return [];
46 | }
47 |
48 | console.WriteLine("Adding references from built project...");
49 | var metadataReferences = await GetMetadataReferences(solutionPath, cancellationToken);
50 | return metadataReferences;
51 | }
52 |
53 | private async Task> GetMetadataReferences(string solutionOrProject, CancellationToken cancellationToken)
54 | {
55 | var workspace = MSBuildWorkspace.Create();
56 |
57 | var projects = Path.GetExtension(solutionOrProject) switch
58 | {
59 | ".csproj" => [await workspace.OpenProjectAsync(solutionOrProject, cancellationToken: cancellationToken)],
60 | ".sln" => (await workspace.OpenSolutionAsync(solutionOrProject, cancellationToken: cancellationToken)).Projects,
61 | _ => throw new ArgumentException("Unexpected filetype for file " + solutionOrProject)
62 | };
63 |
64 | foreach (var error in workspace.Diagnostics.Where(d => d.Kind == WorkspaceDiagnosticKind.Failure))
65 | {
66 | console.WriteErrorLine(error.Message);
67 | }
68 |
69 | return projects
70 | .SelectMany(p =>
71 | p.MetadataReferences
72 | .OfType()
73 | .Concat(p.OutputFilePath is not null
74 | ? [MetadataReference.CreateFromFile(p.OutputFilePath)]
75 | : Array.Empty()
76 | )
77 | )
78 | .Distinct()
79 | .ToImmutableArray();
80 | }
81 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.CSharp.Symbols/GeneratedNameConstants.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | namespace Microsoft.CodeAnalysis.CSharp.Symbols;
6 |
7 | internal static class GeneratedNameConstants
8 | {
9 | internal const char DotReplacementInTypeNames = '-';
10 | internal const string SynthesizedLocalNamePrefix = "CS$";
11 | internal const string SuffixSeparator = "__";
12 | internal const char LocalFunctionNameTerminator = '|';
13 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.CSharp.Symbols/GeneratedNameKind.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 |
7 | namespace Microsoft.CodeAnalysis.CSharp.Symbols;
8 |
9 | internal enum GeneratedNameKind
10 | {
11 | None = 0,
12 |
13 | // Used by EE:
14 | ThisProxyField = '4',
15 | HoistedLocalField = '5',
16 | DisplayClassLocalOrField = '8',
17 | LambdaMethod = 'b',
18 | LambdaDisplayClass = 'c',
19 | StateMachineType = 'd',
20 | LocalFunction = 'g', // note collision with Deprecated_InitializerLocal, however this one is only used for method names
21 |
22 | // Used by EnC:
23 | AwaiterField = 'u',
24 | HoistedSynthesizedLocalField = 's',
25 |
26 | // Currently not parsed:
27 | StateMachineStateField = '1',
28 | IteratorCurrentBackingField = '2',
29 | StateMachineParameterProxyField = '3',
30 | ReusableHoistedLocalField = '7',
31 | LambdaCacheField = '9',
32 | FixedBufferField = 'e',
33 | FileType = 'F',
34 | AnonymousType = 'f',
35 | TransparentIdentifier = 'h',
36 | AnonymousTypeField = 'i',
37 | AnonymousTypeTypeParameter = 'j',
38 | AutoPropertyBackingField = 'k',
39 | IteratorCurrentThreadIdField = 'l',
40 | IteratorFinallyMethod = 'm',
41 | BaseMethodWrapper = 'n',
42 | AsyncBuilderField = 't',
43 | DelegateCacheContainerType = 'O',
44 | DynamicCallSiteContainerType = 'o',
45 | DynamicCallSiteField = 'p',
46 | AsyncIteratorPromiseOfValueOrEndBackingField = 'v',
47 | DisposeModeField = 'w',
48 | CombinedTokensField = 'x', // last
49 |
50 | // Deprecated - emitted by Dev12, but not by Roslyn.
51 | // Don't reuse the values because the debugger might encounter them when consuming old binaries.
52 | [Obsolete]
53 | Deprecated_OuterscopeLocals = '6',
54 | [Obsolete]
55 | Deprecated_IteratorInstance = 'a',
56 | [Obsolete]
57 | Deprecated_InitializerLocal = 'g',
58 | [Obsolete]
59 | Deprecated_DynamicDelegate = 'q',
60 | [Obsolete]
61 | Deprecated_ComrefCallLocal = 'r',
62 | }
63 |
64 | internal static class GeneratedNameKindExtensions
65 | {
66 | internal static bool IsTypeName(this GeneratedNameKind kind)
67 | => kind is GeneratedNameKind.LambdaDisplayClass
68 | or GeneratedNameKind.StateMachineType
69 | or GeneratedNameKind.DynamicCallSiteContainerType
70 | or GeneratedNameKind.DelegateCacheContainerType;
71 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.CSharp.Symbols/GeneratedNameParser.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Diagnostics.CodeAnalysis;
7 |
8 | namespace Microsoft.CodeAnalysis.CSharp.Symbols;
9 |
10 | internal static class GeneratedNameParser
11 | {
12 | internal static bool IsSynthesizedLocalName(string name)
13 | => name.StartsWith(GeneratedNameConstants.SynthesizedLocalNamePrefix, StringComparison.Ordinal);
14 |
15 | // The type of generated name. See TryParseGeneratedName.
16 | internal static GeneratedNameKind GetKind(string name)
17 | => TryParseGeneratedName(name, out var kind, out _, out _) ? kind : GeneratedNameKind.None;
18 |
19 | // Parse the generated name. Returns true for names of the form
20 | // [CS$]<[middle]>c[__[suffix]] where [CS$] is included for certain
21 | // generated names, where [middle] and [__[suffix]] are optional,
22 | // and where c is a single character in [1-9a-z]
23 | // (csharp\LanguageAnalysis\LIB\SpecialName.cpp).
24 | internal static bool TryParseGeneratedName(
25 | string name,
26 | out GeneratedNameKind kind,
27 | out int openBracketOffset,
28 | out int closeBracketOffset)
29 | {
30 | openBracketOffset = -1;
31 | if (name.StartsWith("CS$<", StringComparison.Ordinal))
32 | {
33 | openBracketOffset = 3;
34 | }
35 | else if (name.StartsWith("<", StringComparison.Ordinal))
36 | {
37 | openBracketOffset = 0;
38 | }
39 |
40 | if (openBracketOffset >= 0)
41 | {
42 | closeBracketOffset = IndexOfBalancedParenthesis(name, openBracketOffset, '>');
43 | if (closeBracketOffset >= 0 && closeBracketOffset + 1 < name.Length)
44 | {
45 | int c = name[closeBracketOffset + 1];
46 | if (c is >= '1' and <= '9' or >= 'a' and <= 'z') // Note '0' is not special.
47 | {
48 | kind = (GeneratedNameKind)c;
49 | return true;
50 | }
51 | }
52 | }
53 |
54 | kind = GeneratedNameKind.None;
55 | openBracketOffset = -1;
56 | closeBracketOffset = -1;
57 | return false;
58 | }
59 |
60 | private static int IndexOfBalancedParenthesis(string str, int openingOffset, char closing)
61 | {
62 | char opening = str[openingOffset];
63 |
64 | int depth = 1;
65 | for (int i = openingOffset + 1; i < str.Length; i++)
66 | {
67 | var c = str[i];
68 | if (c == opening)
69 | {
70 | depth++;
71 | }
72 | else if (c == closing)
73 | {
74 | depth--;
75 | if (depth == 0)
76 | {
77 | return i;
78 | }
79 | }
80 | }
81 |
82 | return -1;
83 | }
84 |
85 | internal static bool TryParseSourceMethodNameFromGeneratedName(string generatedName, GeneratedNameKind requiredKind, [NotNullWhen(true)] out string? methodName)
86 | {
87 | if (!TryParseGeneratedName(generatedName, out var kind, out int openBracketOffset, out int closeBracketOffset))
88 | {
89 | methodName = null;
90 | return false;
91 | }
92 |
93 | if (requiredKind != 0 && kind != requiredKind)
94 | {
95 | methodName = null;
96 | return false;
97 | }
98 |
99 | methodName = generatedName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1);
100 |
101 | if (kind.IsTypeName())
102 | {
103 | methodName = methodName.Replace(GeneratedNameConstants.DotReplacementInTypeNames, '.');
104 | }
105 |
106 | return true;
107 | }
108 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.CSharp.Symbols/GeneratedNames.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | namespace Microsoft.CodeAnalysis.CSharp.Symbols;
6 |
7 | internal static class GeneratedNames
8 | {
9 | internal static bool IsGeneratedMemberName(string memberName)
10 | {
11 | return memberName.Length > 0 && memberName[0] == '<';
12 | }
13 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.PooledObjects/ArrayBuilder.Enumerator.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | namespace Microsoft.CodeAnalysis.PooledObjects;
6 |
7 | internal partial class ArrayBuilder
8 | {
9 | ///
10 | /// struct enumerator used in foreach.
11 | ///
12 | internal struct Enumerator
13 | {
14 | private readonly ArrayBuilder _builder;
15 | private int _index;
16 |
17 | public Enumerator(ArrayBuilder builder)
18 | {
19 | _builder = builder;
20 | _index = -1;
21 | }
22 |
23 | public T Current
24 | {
25 | get
26 | {
27 | return _builder[_index];
28 | }
29 | }
30 |
31 | public bool MoveNext()
32 | {
33 | _index++;
34 | return _index < _builder.Count;
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.PooledObjects/PooledHashSet.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 |
8 | namespace Microsoft.CodeAnalysis.PooledObjects;
9 |
10 | // HashSet that can be recycled via an object pool
11 | // NOTE: these HashSets always have the default comparer.
12 | internal sealed partial class PooledHashSet : HashSet
13 | {
14 | private readonly ObjectPool> _pool;
15 |
16 | private PooledHashSet(ObjectPool> pool, IEqualityComparer equalityComparer) :
17 | base(equalityComparer)
18 | {
19 | _pool = pool;
20 | }
21 |
22 | public void Free()
23 | {
24 | this.Clear();
25 | _pool?.Free(this);
26 | }
27 |
28 | // global pool
29 | private static readonly ObjectPool> s_poolInstance = CreatePool(EqualityComparer.Default);
30 |
31 | // if someone needs to create a pool;
32 | public static ObjectPool> CreatePool(IEqualityComparer equalityComparer)
33 | {
34 | ObjectPool>? pool = null;
35 | pool = new ObjectPool>(() => new PooledHashSet(pool!, equalityComparer), 128);
36 | return pool;
37 | }
38 |
39 | public static PooledHashSet GetInstance()
40 | {
41 | var instance = s_poolInstance.Allocate();
42 | Debug.Assert(instance.Count == 0);
43 | return instance;
44 | }
45 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.PooledObjects/PooledStringBuilder.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Diagnostics;
6 | using System.Text;
7 |
8 | namespace Microsoft.CodeAnalysis.PooledObjects;
9 |
10 | ///
11 | /// The usage is:
12 | /// var inst = PooledStringBuilder.GetInstance();
13 | /// var sb = inst.builder;
14 | /// ... Do Stuff...
15 | /// ... sb.ToString() ...
16 | /// inst.Free();
17 | ///
18 | internal sealed partial class PooledStringBuilder
19 | {
20 | public readonly StringBuilder Builder = new();
21 | private readonly ObjectPool _pool;
22 |
23 | private PooledStringBuilder(ObjectPool pool)
24 | {
25 | Debug.Assert(pool != null);
26 | _pool = pool!;
27 | }
28 |
29 | public int Length
30 | {
31 | get { return this.Builder.Length; }
32 | }
33 |
34 | public void Free()
35 | {
36 | var builder = this.Builder;
37 |
38 | // do not store builders that are too large.
39 | if (builder.Capacity <= 1024)
40 | {
41 | builder.Clear();
42 | _pool.Free(this);
43 | }
44 | else
45 | {
46 | _pool.ForgetTrackedObject(this);
47 | }
48 | }
49 |
50 | [System.Obsolete("Consider calling ToStringAndFree instead.")]
51 | public new string ToString()
52 | {
53 | return this.Builder.ToString();
54 | }
55 |
56 | public string ToStringAndFree()
57 | {
58 | var result = this.Builder.ToString();
59 | this.Free();
60 |
61 | return result;
62 | }
63 |
64 | public string ToStringAndFree(int startIndex, int length)
65 | {
66 | var result = this.Builder.ToString(startIndex, length);
67 | this.Free();
68 |
69 | return result;
70 | }
71 |
72 | // global pool
73 | private static readonly ObjectPool s_poolInstance = CreatePool();
74 |
75 | // if someone needs to create a private pool;
76 | ///
77 | /// If someone need to create a private pool
78 | ///
79 | /// The size of the pool.
80 | ///
81 | public static ObjectPool CreatePool(int size = 32)
82 | {
83 | ObjectPool? pool = null;
84 | pool = new ObjectPool(() => new PooledStringBuilder(pool!), size);
85 | return pool;
86 | }
87 |
88 | public static PooledStringBuilder GetInstance()
89 | {
90 | var builder = s_poolInstance.Allocate();
91 | Debug.Assert(builder.Builder.Length == 0);
92 | return builder;
93 | }
94 |
95 | public static implicit operator StringBuilder(PooledStringBuilder obj)
96 | {
97 | return obj.Builder;
98 | }
99 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.Scripting.Hosting/MemberFilter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Reflection;
6 | using Microsoft.CodeAnalysis.CSharp.Symbols;
7 |
8 | namespace Microsoft.CodeAnalysis.Scripting.Hosting;
9 |
10 | internal sealed class MemberFilter
11 | {
12 | public bool Include(MemberInfo member)
13 | => !IsGeneratedMemberName(member.Name);
14 |
15 | private bool IsGeneratedMemberName(string name)
16 | {
17 | // Generated fields, e.g. "k__BackingField"
18 | return GeneratedNames.IsGeneratedMemberName(name);
19 | }
20 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.Scripting.Hosting/PrimitiveFormatterOptions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Globalization;
6 |
7 | namespace Microsoft.CodeAnalysis.Scripting.Hosting;
8 |
9 | internal readonly struct PrimitiveFormatterOptions
10 | {
11 | ///
12 | /// Since is an extension point, we don't
13 | /// perform any validation on - it's up to the individual
14 | /// subtype.
15 | ///
16 | public int NumberRadix { get; }
17 | public bool IncludeCharacterCodePoints { get; }
18 | public bool QuoteStringsAndCharacters { get; }
19 | public bool EscapeNonPrintableCharacters { get; }
20 | public CultureInfo CultureInfo { get; }
21 |
22 | public PrimitiveFormatterOptions(
23 | int numberRadix,
24 | bool includeCodePoints,
25 | bool quoteStringsAndCharacters,
26 | bool escapeNonPrintableCharacters,
27 | CultureInfo cultureInfo)
28 | {
29 | NumberRadix = numberRadix;
30 | IncludeCharacterCodePoints = includeCodePoints;
31 | QuoteStringsAndCharacters = quoteStringsAndCharacters;
32 | EscapeNonPrintableCharacters = escapeNonPrintableCharacters;
33 | CultureInfo = cultureInfo;
34 | }
35 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis.Scripting.Hosting/TypeNameFormatterOptions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | namespace Microsoft.CodeAnalysis.Scripting.Hosting;
6 |
7 | internal readonly struct TypeNameFormatterOptions
8 | {
9 | public readonly int ArrayBoundRadix;
10 | public readonly bool ShowNamespaces;
11 | public readonly bool UseLanguageKeywords;
12 | public readonly bool HideSystemNamespace;
13 |
14 | public TypeNameFormatterOptions(int arrayBoundRadix, bool showNamespaces, bool useLanguageKeywords, bool hideSystemNamespace)
15 | {
16 | ArrayBoundRadix = arrayBoundRadix;
17 | ShowNamespaces = showNamespaces;
18 | UseLanguageKeywords = useLanguageKeywords;
19 | HideSystemNamespace = hideSystemNamespace;
20 | }
21 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis/ObjectDisplayExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | #nullable disable
6 |
7 | namespace Microsoft.CodeAnalysis;
8 |
9 | internal static class ObjectDisplayExtensions
10 | {
11 | ///
12 | /// Determines if a flag is set on the enum.
13 | ///
14 | /// The value to check.
15 | /// An enum field that specifies the flag.
16 | /// Whether the is set on the .
17 | internal static bool IncludesOption(this ObjectDisplayOptions options, ObjectDisplayOptions flag)
18 | {
19 | return (options & flag) == flag;
20 | }
21 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Microsoft.CodeAnalysis/ObjectDisplayOptions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | #nullable disable
6 |
7 | using System;
8 |
9 | namespace Microsoft.CodeAnalysis;
10 |
11 | ///
12 | /// Specifies the options for how generics are displayed in the description of a symbol.
13 | ///
14 | [Flags]
15 | internal enum ObjectDisplayOptions
16 | {
17 | ///
18 | /// Format object using default options.
19 | ///
20 | None = 0,
21 |
22 | ///
23 | /// In C#, include the numeric code point before character literals.
24 | ///
25 | IncludeCodePoints = 1 << 0,
26 |
27 | ///
28 | /// Whether or not to include type suffix for applicable integral literals.
29 | ///
30 | IncludeTypeSuffix = 1 << 1,
31 |
32 | ///
33 | /// Whether or not to display integral literals in hexadecimal.
34 | ///
35 | UseHexadecimalNumbers = 1 << 2,
36 |
37 | ///
38 | /// Whether or not to quote character and string literals.
39 | ///
40 | UseQuotes = 1 << 3,
41 |
42 | ///
43 | /// In C#, replace non-printable (e.g. control) characters with dedicated (e.g. \t) or unicode (\u0001) escape sequences.
44 | /// In Visual Basic, replace non-printable characters with calls to ChrW and vb* constants.
45 | ///
46 | EscapeNonPrintableCharacters = 1 << 4,
47 | }
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/References/AssemblyReferenceComparer.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System.Collections.Generic;
6 | using System.Diagnostics.CodeAnalysis;
7 | using Microsoft.CodeAnalysis;
8 |
9 | namespace CSharpRepl.Services.Roslyn.References;
10 |
11 | ///
12 | /// Compares assembly references based on their filepath.
13 | ///
14 | internal sealed class AssemblyReferenceComparer : IEqualityComparer
15 | {
16 | public bool Equals(MetadataReference? x, MetadataReference? y) =>
17 | x?.Display == y?.Display;
18 |
19 | public int GetHashCode([DisallowNull] MetadataReference obj) =>
20 | (obj.Display ?? string.Empty).GetHashCode();
21 | }
22 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/References/SharedFramework.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using Microsoft.CodeAnalysis;
10 |
11 | namespace CSharpRepl.Services.Roslyn.References;
12 |
13 | ///
14 | /// Represents an installed Shared Framework. Can be a base framework (Microsoft.NETCore.App), ASP.NET, Windows Desktop, etc.
15 | /// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/metapackage-app?view=aspnetcore-5.0
16 | ///
17 | public class SharedFramework
18 | {
19 | public const string NetCoreApp = "Microsoft.NETCore.App";
20 | public string ReferencePath { get; }
21 | public string ImplementationPath { get; }
22 | public IReadOnlyCollection ReferenceAssemblies { get; }
23 | public IReadOnlyCollection ImplementationAssemblies { get; }
24 |
25 | public SharedFramework(
26 | string referencePath, IReadOnlyCollection ReferenceAssemblies,
27 | string ImplementationPath, IReadOnlyCollection ImplementationAssemblies)
28 | {
29 | this.ReferencePath = referencePath;
30 | this.ImplementationPath = ImplementationPath;
31 | this.ReferenceAssemblies = ReferenceAssemblies;
32 | this.ImplementationAssemblies = ImplementationAssemblies;
33 | }
34 |
35 | public static string[] SupportedFrameworks { get; } =
36 | Path.GetDirectoryName(typeof(object).Assembly.Location) is string frameworkDirectory
37 | ? Directory
38 | .GetDirectories(Path.Combine(frameworkDirectory, "../../"))
39 | .Select(dir => Path.GetFileName(dir))
40 | .ToArray()
41 | : [];
42 |
43 | public static Version ToDotNetVersion(string version) =>
44 | // discard trailing preview versions, e.g. 6.0.0-preview.4.21253.7
45 | new Version(version.Split('-', 2).First());
46 | }
47 |
--------------------------------------------------------------------------------
/CSharpRepl.Services/Roslyn/Scripting/EvaluationResult.cs:
--------------------------------------------------------------------------------
1 | // This Source Code Form is subject to the terms of the Mozilla Public
2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using Microsoft.CodeAnalysis;
8 |
9 | namespace CSharpRepl.Services.Roslyn.Scripting;
10 |
11 | /// about as close to a discriminated union as I can get
12 | public abstract record EvaluationResult
13 | {
14 | public sealed record Success(string Input, Optional