Skip to content
Open
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
43 changes: 35 additions & 8 deletions .github/workflows/build_static_site.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ else

# first let's get a list of files _not_ to copy
cd ./sko
TRACKED_FILES=$(git log --pretty=format: --name-only --diff-filter=A -- Browser_IDE| sort - | sed '/^$/d')
TRACKED_FILES=$(git log --pretty=format: --name-only --diff-filter=A | sort - | sed '/^$/d')
EXCLUDE_FILE=$(mktemp)
echo "$TRACKED_FILES" | sed "s|^Browser_IDE||" > "$EXCLUDE_FILE"
echo "$TRACKED_FILES" > "$EXCLUDE_FILE"

# add some explicit excludes
echo "/codemirror-5.65.15" >> "$EXCLUDE_FILE"
Expand All @@ -91,26 +91,33 @@ else
cd ../

# copy in all the untracked files!
rsync -av --progress --exclude-from="$EXCLUDE_FILE" "prebuilt/" "sko/Browser_IDE/"
rsync -av --progress --exclude-from="$EXCLUDE_FILE" "prebuilt/" "sko/"

fi


echo "========================================"
echo "Install Node Dependencies"
echo "========================================"
cd ./sko/Browser_IDE
cd ./sko

npm install

cd ../../
cd ../



echo "========================================"
echo "Re-Structure Static Site"
echo "========================================"
cd ./sko/Browser_IDE
cd ./sko

# Move node_modules into Browser_IDE if it exists, otherwise work in current directory
if [ -d "Browser_IDE" ]; then
# If Browser_IDE exists (from prebuilt), move node_modules there
mv node_modules Browser_IDE/
cd Browser_IDE
fi

# if changed, remember to update the explicit excludes above
mv node_modules/codemirror codemirror-5.65.15
Expand All @@ -119,6 +126,26 @@ mv node_modules/@babel/standalone babel
mv node_modules/split.js/dist split.js
mv node_modules/mime/dist mime
rm -rf external/js-lzma/data
mv ../DemoProjects DemoProjects

cd ../
# Move DemoProjects based on current directory
if [ "$(basename $PWD)" = "Browser_IDE" ]; then
# We're in Browser_IDE, check if DemoProjects exists at ../../DemoProjects
if [ -d "../../DemoProjects" ]; then
mv ../../DemoProjects DemoProjects
fi
cd ../../
else
# We're in sko/, check if DemoProjects exists at ../DemoProjects
if [ -d "../DemoProjects" ]; then
mv ../DemoProjects DemoProjects
fi
# Create Browser_IDE directory and move everything into it for consistent upload structure
mkdir -p Browser_IDE
# Move all files except Browser_IDE itself into Browser_IDE
for item in *; do
if [ "$item" != "Browser_IDE" ]; then
mv "$item" Browser_IDE/
fi
done
cd ../
fi
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cmake.sourceDirectory": "/home/code/project/SplashkitOnline-patch-2/SplashKitWasm/cmake"
}
3 changes: 3 additions & 0 deletions CSharpWasm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Build results
bin/
obj/
111 changes: 111 additions & 0 deletions CSharpWasm/CSharpCodeRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.JavaScript;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Net.Http;
using System.Threading.Tasks;

public class DiagnosticInfo
{
public int Line { get; set; }
public string Message { get; set; }
}

public partial class CSharpCodeRunner
{

static async Task<MetadataReference> LoadAssemblyFromServer(string assemblyName)
{
var baseUrl = GetHRef();
var url = $"/CSharpWasmExpo/bin/{assemblyName}";

try
{
using var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) };
var assemblyBytes = await httpClient.GetByteArrayAsync(url);
return MetadataReference.CreateFromImage(assemblyBytes);
}
catch (Exception ex)
{
Console.WriteLine($"Error loading assembly {assemblyName}: {ex.Message}");
throw;
}
}

[JSExport]
internal static Task<string> CompileAndRun(string code)
{
return Task.Run(async () =>
{
try
{
var syntaxTree = CSharpSyntaxTree.ParseText(code);

// Use Task.WhenAll to run async LoadAssemblyFromServer in parallel
var references = await Task.WhenAll(
LoadAssemblyFromServer("mscorlib.dll"),
LoadAssemblyFromServer("netstandard.dll"),
LoadAssemblyFromServer("System.Console.dll"),
LoadAssemblyFromServer("System.Private.CoreLib.dll"),
LoadAssemblyFromServer("System.Runtime.dll"),
LoadAssemblyFromServer("CSharpWasm.dll")
);

// Create a compilation with the syntax tree and references
var compilation = CSharpCompilation.Create(
assemblyName: "DynamicAssembly",
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication)
);

// Create a MemoryStream to store the compiled assembly
using var ms = new MemoryStream();
var emitResult = compilation.Emit(ms);

// Check for compilation errors
if (!emitResult.Success)
{
var errors = emitResult.Diagnostics
.Where(d => d.Severity == DiagnosticSeverity.Error)
.Select(d => new DiagnosticInfo
{
Line = d.Location.GetLineSpan().StartLinePosition.Line,
Message = d.GetMessage()
})
.ToList();

// If you need to format it as a string, you can do:
var errorString = string.Join("\n", errors.Select(e => $"Line {e.Line}: {e.Message}"));

return $"Compilation failed:\n{errorString}";
}

// Load the compiled assembly into the current AppDomain
ms.Seek(0, SeekOrigin.Begin);
#pragma warning disable IL2026
var assembly = AppDomain.CurrentDomain.Load(ms.ToArray());
#pragma warning restore IL2026

// Get the entry point and invoke it
var entryPoint = assembly.EntryPoint;
if (entryPoint != null)
{
var result = entryPoint.Invoke(null, null);
return result?.ToString() ?? "Execution complete, no output.";
}

return "No entry point found.";
}
catch (Exception ex)
{
return $"Error: {ex}";
}
});
}

[JSImport("window.location.href", "main.js")]
public static partial string GetHRef();
}
9 changes: 9 additions & 0 deletions CSharpWasm/CSharpWasm.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.12.0" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions CSharpWasm/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System;

Console.WriteLine("Hello World from C#!");
4 changes: 4 additions & 0 deletions CSharpWasm/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

[assembly:System.Runtime.Versioning.SupportedOSPlatform("browser")]
13 changes: 13 additions & 0 deletions CSharpWasm/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"profiles": {
"CSharpWasm": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:7281;http://localhost:5178",
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
}
}
}
18 changes: 18 additions & 0 deletions CSharpWasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CSharpWasm

This project enables building and running C# code in the browser using WebAssembly (Wasm).

## Project Structure

- **SplashKitInterop.cs**: This file contains the logic for binding C# code with JavaScript functions, enabling the use of SplashKit functions within the C# environment.

- **CSharpCodeRunner.cs**: A class responsible for compiling C# code, providing the necessary functionality to run the code dynamically.

- **buildAndCopy.sh**: A shell script that builds the project and copies the necessary files into the `../CSharpWasmExpo` directory. This script helps automate the build process for easy integration with the browser.

### Running the Build and Copy Script

To build the project and copy the necessary files into the `../CSharpWasmExpo` directory, run the following shell script:

```bash
./buildAndCopy.sh
Loading