Repository navigation
feat: add csharp support via csc direct compilation - #12
Aryan-Raj-7167 wants to merge 2 commits into
Conversation
Aryan-Raj-7167
commented
Jul 2, 2026
- Uses csc (Roslyn compiler) instead of dotnet run for faster execution
- Includes DOTNET_GCHeapHardLimit workaround for Android memory constraints
- Generates GlobalUsings.cs to match dotnet new console's implicit usings
- Caches Program.runtimeconfig.json per project to avoid regeneration
- Uses csc (Roslyn compiler) instead of dotnet run for faster execution - Includes DOTNET_GCHeapHardLimit workaround for Android memory constraints - Generates GlobalUsings.cs to match dotnet new console's implicit usings - Caches Program.runtimeconfig.json per project to avoid regeneration
Greptile SummaryThis PR adds C# support to the Acode runner plugin using
Confidence Score: 3/5The C# runner works for unsaved/content:// files but breaks for .cs files saved to the Alpine filesystem, which is the primary interactive editing location for many users. The copy step runs after a directory change, using a basename-only path that does not exist in the temp directory. Any user who saves a .cs file in the Alpine home directory and presses Run will hit a cp failure before compilation starts. src/languageRunners.js — specifically the single-line cmd string for the C# runner Important Files Changed
Reviews (1): Last reviewed commit: "feat: add csharp support via csc direct ..." | Re-trigger Greptile |
| extensions: ['cs'], | ||
| commands: [ | ||
| { | ||
| cmd: `mkdir -p /tmp/csrun_{name} && cd /tmp/csrun_{name} && cp "{file}" ./Program.cs && export DOTNET_gcServer=0 DOTNET_GCHeapHardLimit=0x10000000 DOTNET_GCgen0size=0x2000000 && CSC=$(find /usr/lib/dotnet/sdk -name "csc.dll" 2>/dev/null | head -1) && REFDIR=$(find /usr/lib/dotnet/packs/Microsoft.NETCore.App.Ref -type d -name "net8.0" 2>/dev/null | head -1) && REFS=$(find "$REFDIR" -name "*.dll" 2>/dev/null | sed 's/^/-r:/' | tr '\n' ' ') && ([ -f Program.runtimeconfig.json ] || printf '{"runtimeOptions":{"tfm":"net8.0","framework":{"name":"Microsoft.NETCore.App","version":"8.0.0"}}}' > Program.runtimeconfig.json) && ([ -f GlobalUsings.cs ] || printf 'global using System;\\nglobal using System.Collections.Generic;\\nglobal using System.Linq;\\nglobal using System.IO;\\nglobal using System.Threading.Tasks;\\n' > GlobalUsings.cs) && dotnet exec "$CSC" -nologo -optimize -langversion:latest $REFS -out:Program.dll Program.cs GlobalUsings.cs && dotnet Program.dll`, |
There was a problem hiding this comment.
cp "{file}" fails for saved files after cd /tmp/csrun_{name}
The command issues cd /tmp/csrun_{name} first, then cp "{file}" ./Program.cs. In the needsTempFile=false path (files accessed via a file:// URI — i.e., files saved in the Alpine filesystem), {file} is substituted with just the basename of the file (e.g., MyProgram.cs), not an absolute path. Once the shell has changed into /tmp/csrun_{name}, that basename does not exist there, so cp fails with "No such file or directory" and the whole && chain aborts before compilation. The needsTempFile=true path (unsaved/content:// files) is safe because {file} resolves to the absolute /tmp/<filename> in that branch.
The fix is to use {path} instead of {file} in the cp sub-command, or to copy the file before the cd. {path} resolves to the absolute filesystem path in both the saved-file branch (actualPath) and the temp-file branch (tempFile), so it is safe to use unconditionally here.
| // C# | ||
| this.#runners.set('csharp', { | ||
| extensions: ['cs'], | ||
| commands: [ | ||
| { | ||
| cmd: `mkdir -p /tmp/csrun_{name} && cd /tmp/csrun_{name} && cp "{file}" ./Program.cs && export DOTNET_gcServer=0 DOTNET_GCHeapHardLimit=0x10000000 DOTNET_GCgen0size=0x2000000 && CSC=$(find /usr/lib/dotnet/sdk -name "csc.dll" 2>/dev/null | head -1) && REFDIR=$(find /usr/lib/dotnet/packs/Microsoft.NETCore.App.Ref -type d -name "net8.0" 2>/dev/null | head -1) && REFS=$(find "$REFDIR" -name "*.dll" 2>/dev/null | sed 's/^/-r:/' | tr '\n' ' ') && ([ -f Program.runtimeconfig.json ] || printf '{"runtimeOptions":{"tfm":"net8.0","framework":{"name":"Microsoft.NETCore.App","version":"8.0.0"}}}' > Program.runtimeconfig.json) && ([ -f GlobalUsings.cs ] || printf 'global using System;\\nglobal using System.Collections.Generic;\\nglobal using System.Linq;\\nglobal using System.IO;\\nglobal using System.Threading.Tasks;\\n' > GlobalUsings.cs) && dotnet exec "$CSC" -nologo -optimize -langversion:latest $REFS -out:Program.dll Program.cs GlobalUsings.cs && dotnet Program.dll`, | ||
| packages: ['dotnet8-sdk'], | ||
| checkCommand: 'dotnet' | ||
| } | ||
| ], | ||
| description: 'C# compiler' | ||
| }); |
There was a problem hiding this comment.
The C# block uses 4-space indentation while every other runner in the file uses tabs. This creates a visible inconsistency in editors and in
git diff output.
| // C# | |
| this.#runners.set('csharp', { | |
| extensions: ['cs'], | |
| commands: [ | |
| { | |
| cmd: `mkdir -p /tmp/csrun_{name} && cd /tmp/csrun_{name} && cp "{file}" ./Program.cs && export DOTNET_gcServer=0 DOTNET_GCHeapHardLimit=0x10000000 DOTNET_GCgen0size=0x2000000 && CSC=$(find /usr/lib/dotnet/sdk -name "csc.dll" 2>/dev/null | head -1) && REFDIR=$(find /usr/lib/dotnet/packs/Microsoft.NETCore.App.Ref -type d -name "net8.0" 2>/dev/null | head -1) && REFS=$(find "$REFDIR" -name "*.dll" 2>/dev/null | sed 's/^/-r:/' | tr '\n' ' ') && ([ -f Program.runtimeconfig.json ] || printf '{"runtimeOptions":{"tfm":"net8.0","framework":{"name":"Microsoft.NETCore.App","version":"8.0.0"}}}' > Program.runtimeconfig.json) && ([ -f GlobalUsings.cs ] || printf 'global using System;\\nglobal using System.Collections.Generic;\\nglobal using System.Linq;\\nglobal using System.IO;\\nglobal using System.Threading.Tasks;\\n' > GlobalUsings.cs) && dotnet exec "$CSC" -nologo -optimize -langversion:latest $REFS -out:Program.dll Program.cs GlobalUsings.cs && dotnet Program.dll`, | |
| packages: ['dotnet8-sdk'], | |
| checkCommand: 'dotnet' | |
| } | |
| ], | |
| description: 'C# compiler' | |
| }); | |
| // C# | |
| this.#runners.set('csharp', { | |
| extensions: ['cs'], | |
| commands: [ | |
| { | |
| cmd: `mkdir -p /tmp/csrun_{name} && cd /tmp/csrun_{name} && cp "{file}" ./Program.cs && export DOTNET_gcServer=0 DOTNET_GCHeapHardLimit=0x10000000 DOTNET_GCgen0size=0x2000000 && CSC=$(find /usr/lib/dotnet/sdk -name "csc.dll" 2>/dev/null | head -1) && REFDIR=$(find /usr/lib/dotnet/packs/Microsoft.NETCore.App.Ref -type d -name "net8.0" 2>/dev/null | head -1) && REFS=$(find "$REFDIR" -name "*.dll" 2>/dev/null | sed 's/^/-r:/' | tr '\n' ' ') && ([ -f Program.runtimeconfig.json ] || printf '{"runtimeOptions":{"tfm":"net8.0","framework":{"name":"Microsoft.NETCore.App","version":"8.0.0"}}}' > Program.runtimeconfig.json) && ([ -f GlobalUsings.cs ] || printf 'global using System;\\nglobal using System.Collections.Generic;\\nglobal using System.Linq;\\nglobal using System.IO;\\nglobal using System.Threading.Tasks;\\n' > GlobalUsings.cs) && dotnet exec "$CSC" -nologo -optimize -langversion:latest $REFS -out:Program.dll Program.cs GlobalUsings.cs && dotnet Program.dll`, | |
| packages: ['dotnet8-sdk'], | |
| checkCommand: 'dotnet' | |
| } | |
| ], | |
| description: 'C# compiler' | |
| }); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!