Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<NoWarn>$(NoWarn);NU1507</NoWarn>
<NetCoreVersion>11.0.0-preview.2.26159.112</NetCoreVersion>
<AspNetCoreVersion>$(NetCoreVersion)</AspNetCoreVersion>
<RoslynVersion>5.6.0-2.26127.8</RoslynVersion>
<RazorVersion>10.0.0-preview.26127.2</RazorVersion>
<RoslynVersion>5.6.0-2.26173.1</RoslynVersion>
<RazorVersion>10.0.0-preview.26171.1</RazorVersion>
<FluentUIVersion>4.14.0</FluentUIVersion>
<NuGetVersion>7.3.0</NuGetVersion>
</PropertyGroup>
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,19 @@ C# REPLs:
- https://dotnetfiddle.net/
- https://onecompiler.com/csharp
- https://www.programiz.com/csharp-programming/online-compiler/
- https://tio.run/#cs-core
- https://github.com/dotnet/try
- https://www.onlinegdb.com/online_csharp_compiler

C# compiler playgrounds:
- https://sharplab.io/
- https://godbolt.org/
- https://github.com/webmaster442/LowSharp
- https://github.com/wherewhere/SharpScript

XAML REPLs:
- https://playground.platform.uno/
- https://xaml.io/

Web IDEs:
- https://github.com/Mythetech/Apollo
Expand Down
32 changes: 28 additions & 4 deletions src/App/Lab/Page.razor
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@
*@<FluentIcon Value="@(new Icons.Regular.Size20.ArrowCollapseAll())" Color="Color.Neutral" /></FluentButton>
}
break;
case "html":
{
<FluentCheckbox @bind-Value="showRenderedHtml" Label="Rendered" Disabled="htmlOutput == null"
title="Displays the HTML code rendered inside an iframe" />
}
break;
case "il":
{
<FluentCheckbox @bind-Value:get="savedState.DecodeCustomAttributeBlobs"
Expand Down Expand Up @@ -305,10 +311,24 @@
</FluentMessageBar>
}

@* Output editor *@
<div style="flex-grow: 1">
<StandaloneCodeEditor @ref="outputEditor" Id="output-editor"
ConstructionOptions="OutputConstructionOptions" />
@* Rendered HTML *@
@{
bool actuallyShowRenderedHtml = showRenderedHtml && htmlOutput != null;
}
@if (actuallyShowRenderedHtml)
{
<iframe srcdoc="@htmlOutput" style="width: 100%; height: 100%"></iframe>
}

@* Output editor *@
@{
string style = actuallyShowRenderedHtml ? "display:none" : "display:contents";
}
<div style="@style">
<StandaloneCodeEditor @ref="outputEditor" Id="output-editor"
ConstructionOptions="OutputConstructionOptions" />
</div>
</div>
</div>
</FluentMultiSplitterPane>
Expand Down Expand Up @@ -351,8 +371,10 @@
private bool useVim;
private bool enableMemoryUsageView;
private bool displayHintSquiggles;
private bool showRenderedHtml;
private Orientation orientation;
private string? workerError;
private string? htmlOutput;

private sealed record CompiledState
{
Expand Down Expand Up @@ -484,7 +506,7 @@
=> compiled is not { Start: var compileStart } || compileStart < inputChanged;

private bool OutputHasToolbar
=> DisplayOutputType is "tree" or "il" or CompiledAssembly.DiagnosticsOutputType;
=> DisplayOutputType is "tree" or "html" or "il" or CompiledAssembly.DiagnosticsOutputType;

protected override async Task OnInitializedAsync()
{
Expand Down Expand Up @@ -1197,6 +1219,8 @@

var text = CompilerOutputPlugin.GetText(outputInfo, result, out outputDisclaimer, ref language);

htmlOutput = outputType == "html" && language == "html" ? text : null;

string? previousLanguage;

if (!outputStates.TryGetValue(outputType, out var state))
Expand Down
13 changes: 13 additions & 0 deletions src/Compiler/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public static void CSharpParseOptions(Func<CSharpParseOptions, CSharpParseOption
public static void CSharpCompilationOptions(Func<CSharpCompilationOptions, CSharpCompilationOptions> configure)
=> Instance.CSharpCompilationOptions(configure);

public static void CSharpCompilation(Func<CSharpCompilation, CSharpCompilation> configure)
=> Instance.CSharpCompilation(configure);

public static void EmitOptions(Func<EmitOptions, EmitOptions> configure)
=> Instance.EmitOptions(configure);

Expand All @@ -27,6 +30,7 @@ internal sealed class ConfigCollector : IConfig
{
private readonly List<Func<CSharpParseOptions, CSharpParseOptions>> cSharpParseOptions = new();
private readonly List<Func<CSharpCompilationOptions, CSharpCompilationOptions>> cSharpCompilationOptions = new();
private readonly List<Func<CSharpCompilation, CSharpCompilation>> cSharpCompilation = new();
private readonly List<Func<EmitOptions, EmitOptions>> emitOptions = new();
private readonly List<Func<ExtendedEmitOptions, ExtendedEmitOptions>> extendedEmitOptions = new();
private readonly List<Func<ImmutableArray<SourceFile>, ImmutableArray<SourceFile>>> additionalSources = new();
Expand All @@ -43,6 +47,7 @@ public void Reset()
{
cSharpParseOptions.Clear();
cSharpCompilationOptions.Clear();
cSharpCompilation.Clear();
emitOptions.Clear();
extendedEmitOptions.Clear();
additionalSources.Clear();
Expand All @@ -60,6 +65,11 @@ public void CSharpCompilationOptions(Func<CSharpCompilationOptions, CSharpCompil
cSharpCompilationOptions.Add(configure);
}

public void CSharpCompilation(Func<CSharpCompilation, CSharpCompilation> configure)
{
cSharpCompilation.Add(configure);
}

public void EmitOptions(Func<EmitOptions, EmitOptions> configure)
{
emitOptions.Add(configure);
Expand Down Expand Up @@ -89,6 +99,8 @@ public void AdditionalReferences(Func<RefAssemblyList> configure)

public CSharpCompilationOptions ConfigureCSharpCompilationOptions(CSharpCompilationOptions options) => Configure(options, cSharpCompilationOptions);

public CSharpCompilation ConfigureCSharpCompilation(CSharpCompilation compilation) => Configure(compilation, cSharpCompilation);

public ExtendedEmitOptions ConfigureEmitOptions(ExtendedEmitOptions options)
{
options = options with { EmitOptions = Configure(options.EmitOptions, emitOptions) };
Expand Down Expand Up @@ -128,6 +140,7 @@ internal interface IConfig
{
void CSharpParseOptions(Func<CSharpParseOptions, CSharpParseOptions> configure);
void CSharpCompilationOptions(Func<CSharpCompilationOptions, CSharpCompilationOptions> configure);
void CSharpCompilation(Func<CSharpCompilation, CSharpCompilation> configure);
void EmitOptions(Func<EmitOptions, EmitOptions> configure);
void ExtendedEmitOptions(Func<ExtendedEmitOptions, ExtendedEmitOptions> configure);
void AdditionalSources(Func<ImmutableArray<SourceFile>, ImmutableArray<SourceFile>> configure);
Expand Down
52 changes: 41 additions & 11 deletions src/Compiler/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ You can try selecting different Razor toolchain in Settings / Advanced.
global using Microsoft.CodeAnalysis.CSharp;
global using Microsoft.CodeAnalysis.Emit;
global using System;

[assembly: System.Runtime.CompilerServices.IgnoresAccessChecksTo("Microsoft.CodeAnalysis")]
[assembly: System.Runtime.CompilerServices.IgnoresAccessChecksTo("Microsoft.CodeAnalysis.CSharp")]

namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
AssemblyName = assemblyName;
}

public string AssemblyName { get; }
}
}
""";

private readonly TreeFormatter treeFormatter = new();
Expand Down Expand Up @@ -139,11 +156,12 @@ private async ValueTask<LiveCompilationResult> CompileNoCacheAsync(
ImmutableDictionary<string, ImmutableArray<byte>>? compilerAssemblies = null;
if (compilationInput.Configuration is { } configuration)
{
if (!executeConfiguration(configuration, out configDiagnostics))
(bool configExecutionSuccess, configDiagnostics) = await executeConfigurationAsync(configuration);
if (!configExecutionSuccess)
{
string configDiagnosticsText = configDiagnostics.GetDiagnosticsText();
ImmutableArray<DiagnosticData> failedConfigDiagnosticData = configDiagnostics
.Select(static d => d.ToDiagnosticData())
.Select(toDiagnosticData)
.Distinct()
.Order()
.ToImmutableArray();
Expand Down Expand Up @@ -247,6 +265,8 @@ private async ValueTask<LiveCompilationResult> CompileNoCacheAsync(
var other => throw new InvalidOperationException($"Invalid Razor toolchain '{other}'."),
};

finalCompilation = Config.Instance.ConfigureCSharpCompilation(finalCompilation);

// This is needed to avoid some blocking `Task.Run(...).Result` calls in Roslyn code paths when emitting PDBs
// which would require monitor waiting which is unsupported in browser wasm.
await Task.Yield();
Expand All @@ -266,11 +286,11 @@ private async ValueTask<LiveCompilationResult> CompileNoCacheAsync(
int numErrors = filteredDiagnostics.Count(static d => d.Severity == DiagnosticSeverity.Error);

var configDiagnosticData = configDiagnostics
.Select(static d => d.ToDiagnosticData())
.Select(toDiagnosticData)
.Distinct()
.Order();
var nonConfigDiagnosticData = nonConfigDiagnostics
.Select(static d => d.ToDiagnosticData())
.Select(toDiagnosticData)
.Distinct()
.Order();
ImmutableArray<DiagnosticData> diagnosticData = configDiagnosticData
Expand Down Expand Up @@ -477,7 +497,16 @@ LiveCompilationResult getResult(CompiledAssembly result, ImmutableArray<CSharpSy

bool filterDiagnostic(Diagnostic d) => compilationInput.Preferences.IncludeHiddenDiagnostics || d.Severity != DiagnosticSeverity.Hidden;

bool executeConfiguration(string code, out ImmutableArray<Diagnostic> diagnostics)
DiagnosticData toDiagnosticData(Diagnostic d)
{
return d.ToDiagnosticData(s => s switch
{
DiagnosticDataSeverity.Hint when compilationInput.Preferences.IncludeHiddenDiagnostics => DiagnosticDataSeverity.Info,
_ => s,
});
}

async ValueTask<(bool Success, ImmutableArray<Diagnostic> Diagnostics)> executeConfigurationAsync(string code)
{
var configurationParseOptions = parseOptions.WithFeatures(parseOptions.Features.Where(p => p.Key != FileBasedProgramFeatureName));

Expand All @@ -487,12 +516,12 @@ bool executeConfiguration(string code, out ImmutableArray<Diagnostic> diagnostic
syntaxTrees:
[
CSharpSyntaxTree.ParseText(code, configurationParseOptions, directory + "Configuration.cs", Encoding.UTF8),
CSharpSyntaxTree.ParseText(ConfigurationGlobalUsings, configurationParseOptions, directory + "GlobalUsings.cs", Encoding.UTF8)
CSharpSyntaxTree.ParseText(ConfigurationGlobalUsings, configurationParseOptions, directory + "GlobalUsings.cs", Encoding.UTF8),
],
references: getConfigurationReferences(assemblies!),
options: CreateConfigurationCompilationOptions());

var emitStreams = getEmitStreams(configCompilation, emitOptions.WithoutPdb(), out diagnostics);
var emitStreams = getEmitStreams(configCompilation, emitOptions.WithoutPdb(), out var diagnostics);

if (emitStreams != null)
{
Expand All @@ -515,18 +544,17 @@ bool executeConfiguration(string code, out ImmutableArray<Diagnostic> diagnostic
// Return some compiler assemblies anyway, so language services in the Configuration file keep working.
compilerAssemblies = assemblies;

return false;
return (false, diagnostics);
}

var configAssembly = alc.LoadFromStream(emitStreams.Value.PeStream);

var entryPoint = configAssembly.EntryPoint
?? throw new ArgumentException("No entry point found in the configuration assembly.");

var result = Executor.InvokeEntryPointAsync(entryPoint);
Debug.Assert(result.IsCompletedSuccessfully);
await Executor.InvokeEntryPointAsync(entryPoint);

return true;
return (true, diagnostics);
}

MetadataReference[] getConfigurationReferences(ImmutableDictionary<string, ImmutableArray<byte>> assemblies)
Expand Down Expand Up @@ -1129,6 +1157,8 @@ public static CSharpCompilationOptions CreateDefaultCompilationOptions(OutputKin
public static CSharpCompilationOptions CreateConfigurationCompilationOptions()
{
return CreateDefaultCompilationOptions(OutputKind.ConsoleApplication)
.WithMetadataImportOptions(MetadataImportOptions.Internal)
.WithIgnoreAccessibility()
.WithSpecificDiagnosticOptions(
[
// warning CS1701: Assuming assembly reference 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' used by 'Microsoft.CodeAnalysis.CSharp' matches identity 'System.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' of 'System.Runtime', you may need to supply runtime policy
Expand Down
Loading
Loading