Skip to content

Commit cbb2f1e

Browse files
committed
Better document new features, add ARCHITECTURE.md
Mostly just better documentation and tweaks. Snuck in a minor point release update for nuget dependencies. - Add more documentation around assembly, csproj, sln, nuget references - More detail on theming. - The new `args` feature for csx - Add contributing section and architecture.md documents
1 parent 905caf3 commit cbb2f1e

File tree

5 files changed

+67
-15
lines changed

5 files changed

+67
-15
lines changed

Diff for: ARCHITECTURE.md

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Architecture
2+
3+
This document describes the design of csharprepl at a high level. It's useful if you want to contribute to csharprepl and are trying to understand how the code is organized and what the various responsibilities are.
4+
5+
Broadly, there are three main components to csharprepl's architecture:
6+
7+
1. [Roslyn libraries](https://github.com/dotnet/roslyn) - Written by Microsoft, these provide both high-level and low-level APIs for building, running, and analyzing C# code.
8+
1. [PrettyPrompt library](https://github.com/waf/PrettyPrompt) - the PrettyPrompt library was written alongside csharprepl, and is packaged as a separate nuget package and repository. It's a Console.ReadLine replacement, and handles terminal features like accepting input, drawing autocompletion menus, syntax highlighting, keybindings, etc, and generally handles the "user experience" of the prompt. It's a general library, and does not know anything about C#; it instead provides callbacks that csharprepl implements to add C#-specific behavior.
9+
1. csharprepl (this repository) - This application uses PrettyPrompt to collect input from the user, invokes the Roslyn APIs on that input, and then prints the result.
10+
11+
Each of the above parts is described in more detail below.
12+
13+
## Roslyn libraries
14+
15+
csharprepl uses two main areas of the Roslyn libraries:
16+
17+
- C# Scripting API ([docs](https://github.com/dotnet/roslyn/blob/b796152aff3a7f872bd70db26cc9f568bbdb14cc/docs/wiki/Scripting-API-Samples.md))
18+
- C# Workspaces API ([docs](https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/work-with-workspace))
19+
20+
The C# Scripting API allows for evaluating strings containing C# and returns the result. This is the core of the REPL experience; this core is quite simple, and a basic REPL could be implemented in a couple of lines of C# using this API. In csharprepl, this is in `ScriptRunner.cs`.
21+
22+
The C# Workspaces API provides all the ancillary editor features in csharprepl, like syntax highlighting, autocompletion, documentation tooltip information, etc. A workspace is conceptually similar to a Visual Studio solution, and it has multiple projects all contained in memory. Each line of a REPL is implemented as a single project with a single document, and each project has a reference to the previously submitted project. In other words, the workspace is a linked-list of projects, where each project is a line of the REPL. Submitting a new line in csharprepl will create a new project and document. Features like syntax highlighting and autocompletion read this document as their input.
23+
24+
These two APIs are quite separate; one of the main tasks of csharprepl is to ensure that when code is evaluated in the REPL, both of these APIs receive consistent information (see `RoslynServices.cs`).
25+
26+
## PrettyPrompt library
27+
28+
This prompt library is initialized/called in the main `Program.cs`, in the "Read" part of the "Read-Eval-Print-Loop." It's instantiated with callback functions to handle syntax highlighting, autocompletion, and more; these callbacks invoke the above `RoslynServices.cs` class to fulfill the callbacks. The `PromptAdapter` class maps between Roslyn concepts (e.g. a span of text with the syntax classification) and the PrettyPrompt concepts (e.g. a span of text with a syntax highlight color).
29+
30+
## csharprepl
31+
32+
As previously described, csharprepl serves as an intermediary between the above two libraries. There are four main tasks that csharprepl performs:
33+
34+
- `Program.cs` handles basic features like command line arguments, help documentation, and the core read-eval-print-loop.
35+
- Initialization logic is managed in `RoslynServices.cs`. The Roslyn libraries do a lot of heavy lifting and are relatively slow to initialize; RoslynServices serves as an entry point to all Roslyn services, and it manages this initialization in the background to keep csharprepl snappy. It ensures that when the Roslyn services are called, they either don't block, or they wait for initialization to complete if required.
36+
- You can see this in action by starting csharprepl and typing some C# code really quickly before initialization can fully complete. You'll be able to type without delay as it won't block, but you might see syntax highlighting kick in a few seconds later, after initialization is complete; this is what RoslynServices is managing.
37+
- Synchronization between the C# Scripting API and C# Workspaces API, as described in *Roslyn libraries* above, is also managed by `RoslynServices.cs`. Upon successful evaluation of a script, it updates the workspaces API with a new project and updates the active document to use for syntax highlighting, autocompletion, and more.
38+
- Assembly reference management - Management of [Shared Frameworks](https://natemcmaster.com/blog/2017/12/21/netcore-primitives/), [implementation vs reference assemblies](https://docs.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies), and adding references dynamically are handled in the `AssemblyReferenceService.cs`. This class is called by our MetadataReferenceResolver implementation, which is an extension point provided by Roslyn.
39+
- This MetadataReferenceResolver is responsible for evaluating `#r` statements, and delegates for assembly references, nuget package installation, csproj/sln references, and shared framework loading. The implementation is in `CompositeMetadataReferenceResolver.cs`

Diff for: CSharpRepl.Services/CSharpRepl.Services.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
<PrivateAssets>all</PrivateAssets>
1111
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1212
</PackageReference>
13-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.9.0" />
14-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="3.9.0" />
13+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0" />
14+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="3.10.0" />
1515
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
16-
<PackageReference Include="NuGet.PackageManagement" Version="5.9.1" />
16+
<PackageReference Include="NuGet.PackageManagement" Version="5.10.0" />
1717
<PackageReference Include="PrettyPrompt" Version="0.9.6" />
1818
</ItemGroup>
1919

Diff for: CSharpRepl.sln

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.31019.35
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31410.414
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpRepl", "CSharpRepl\CSharpRepl.csproj", "{DAF35EEA-275E-4BF1-A7F0-5D2DF32FC0A5}"
77
EndProject
@@ -10,6 +10,7 @@ EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{000D6020-F5D7-4CC9-A539-36914452C63B}"
1111
ProjectSection(SolutionItems) = preProject
1212
.editorconfig = .editorconfig
13+
ARCHITECTURE.md = ARCHITECTURE.md
1314
nuget.config = nuget.config
1415
README.md = README.md
1516
EndProjectSection

Diff for: CSharpRepl/CommandLine.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ public static string GetHelp() =>
155155
"These [OPTIONS] can be provided at the command line, or via a [response-file.rsp]." + NewLine +
156156
"A [script-file.csx], if provided, will be executed before the prompt starts." + NewLine + NewLine +
157157
"OPTIONS:" + NewLine +
158-
" -r <dll> or --reference <dll>: Reference an assembly or csproj file. May be specified multiple times." + NewLine +
159-
" -u <namespace> or --using <namespace>: Add a using statement. May be specified multiple times." + NewLine +
158+
" -r <dll> or --reference <dll>: Reference assemblies, nuget packages, and csproj files." + NewLine +
159+
" -u <namespace> or --using <namespace>: Add using statements." + NewLine +
160160
" -f <framework> or --framework <framework>: Reference a shared framework." + NewLine +
161161
" Available shared frameworks: " + NewLine + GetInstalledFrameworks(
162162
" ") + NewLine +

Diff for: README.md

+20-8
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ the [MSDN documentation for `AddDays`](https://docs.microsoft.com/en-US/dotnet/a
104104
Use the `#r` command to add assembly or nuget references.
105105

106106
- For assembly references, run `#r "AssemblyName"` or `#r "path/to/assembly.dll"`
107+
- For project references, run `#r "path/to/project.csproj"`. Solution files (.sln) can also be referenced.
107108
- For nuget references, run `#r "nuget: PackageName"` to install the latest version of a package, or `#r "nuget: PackageName, 13.0.5"` to install a specific version (13.0.5 in this case).
108109

109110
<p align="center">
@@ -121,24 +122,25 @@ csharprepl --framework Microsoft.AspNetCore.App
121122
The C# REPL supports multiple configuration flags to control startup, behavior, and appearance:
122123

123124
```
124-
Usage: csharprepl [OPTIONS] [response-file.rsp] [script-file.csx]
125+
csharprepl [OPTIONS] [response-file.rsp] [script-file.csx] [-- <additional-arguments>]
125126
```
126127

127128
Supported options are:
128129

129130
- OPTIONS:
130-
- `-r <dll>` or `--reference <dll>`: Add an assembly reference. Can be specified multiple times.
131+
- `-r <dll>` or `--reference <dll>`: Reference an assembly, project file, or nuget package. Can be specified multiple times. Uses the same syntax as `#r` statements inside the REPL. For example, `csharprepl -r "nuget:Newtonsoft.Json" "path/to/myproj.csproj"`
132+
- When an assembly or project is referenced, assemblies in the containing directory will be added to the assembly search path. This means that you don't need to manually add references to all of your assembly's dependencies (e.g. other references and nuget packages). Referencing the main entry assembly is enough.
131133
- `-u <namespace>` or `--using <namespace>`: Add a using statement. Can be specified multiple times.
132-
- `-f <framework>` or `--framework <framework>`: Reference a [shared framework](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/metapackage-app). Available shared frameworks depends on the local .NET installation, and can be useful when running a ASP.NET application from the REPL. Example frameworks are:
134+
- `-f <framework>` or `--framework <framework>`: Reference a [shared framework](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/metapackage-app). The available shared frameworks depends on the local .NET installation, and can be useful when running an ASP.NET application from the REPL. Example frameworks are:
133135
- Microsoft.NETCore.App (default)
134136
- Microsoft.AspNetCore.All
135137
- Microsoft.AspNetCore.App
136138
- Microsoft.WindowsDesktop.App
137-
- `-t <theme.json>` or `--theme <theme.json>`: Read a theme file for syntax highlighting. The [NO_COLOR](https://no-color.org/) standard is supported.
139+
- `-t <theme.json>` or `--theme <theme.json>`: Read a theme file for syntax highlighting. This theme file associates C# syntax classifications with colors. The color values can be full RGB, or ANSI color names (defined in your terminal's theme). The [NO_COLOR](https://no-color.org/) standard is supported.
138140
- `-v` or `--version`: Show version number and exit.
139-
- `-h` or `--help`: Show this help and exit.
141+
- `-h` or `--help`: Show help and exit.
140142
- `response-file.rsp`: A filepath of an .rsp file, containing any of the above command line options.
141-
- `script-file.csx`: A filepath of a .csx file, containing lines of C# to evaluate before starting the REPL.
143+
- `script-file.csx`: A filepath of a .csx file, containing lines of C# to evaluate before starting the REPL. Arguments to this script can be passed as `<additional-arguments>`, after a double hyphen (`--`), and will be available in a global `args` variable.
142144

143145
## Integrating with other software
144146

@@ -174,6 +176,16 @@ This project is far from being the first REPL for C#. Here are some other projec
174176

175177
**csi.exe** ships with C# and is a command line REPL. It's great because it's a cross platform REPL that comes out of the box, but it doesn't support syntax highlighting or autocompletion.
176178

177-
**dotnet script** allows you to run C# scripts from the .NET CLI. It has a REPL built-in, but the predominant focus seems to be as a script runner. It's a good alternative though, and has a strong community following.
179+
**dotnet script** allows you to run C# scripts from the command line. It has a REPL built-in, but the predominant focus seems to be as a script runner. It's a great tool, though, and has a strong community following.
178180

179-
**dotnet interactive** is a tool from Microsoft that creates a Jupyter notebook for C#, runnable through Visual Studio Code.
181+
**dotnet interactive** is a tool from Microsoft that creates a Jupyter notebook for C#, runnable through Visual Studio Code. It also provides a general framework useful for running REPLs.
182+
183+
## Contributing
184+
185+
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:
186+
187+
- Read through the [ARCHITECTURE.md](/ARCHITECTURE.md) file to understand how csharprepl works. Depending on what you want to do, changes to the underlying PrettyPrompt library may be required.
188+
- For new features, please open an issue first to discuss and design the feature. This will help reduce the chance of conflicting designs.
189+
- Please include an xunit test, and ensure any code warnings are resolved.
190+
191+
Thanks!

0 commit comments

Comments
 (0)