Implement changes from latest version of IC10Editor.dll
This commit is contained in:
@@ -4,15 +4,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
using StationeersIC10Editor;
|
using StationeersIC10Editor;
|
||||||
|
|
||||||
public class SlangFormatter : ICodeFormatter
|
public class SlangFormatter : ICodeFormatter
|
||||||
{
|
{
|
||||||
private CancellationTokenSource? _lspCancellationToken;
|
private CancellationTokenSource? _lspCancellationToken;
|
||||||
private readonly SynchronizationContext? _mainThreadContext;
|
private object _tokenLock = new();
|
||||||
private volatile bool IsDiagnosing = false;
|
|
||||||
|
|
||||||
public static readonly uint ColorInstruction = ColorFromHTML("#ffff00");
|
public static readonly uint ColorInstruction = ColorFromHTML("#ffff00");
|
||||||
public static readonly uint ColorString = ColorFromHTML("#ce9178");
|
public static readonly uint ColorString = ColorFromHTML("#ce9178");
|
||||||
@@ -20,10 +19,39 @@ public class SlangFormatter : ICodeFormatter
|
|||||||
private HashSet<uint> _linesWithErrors = new();
|
private HashSet<uint> _linesWithErrors = new();
|
||||||
|
|
||||||
public SlangFormatter()
|
public SlangFormatter()
|
||||||
|
: base()
|
||||||
{
|
{
|
||||||
// 1. Capture the Main Thread context.
|
OnCodeChanged += HandleCodeChanged;
|
||||||
// This works because the Editor instantiates this class on the main thread.
|
}
|
||||||
_mainThreadContext = SynchronizationContext.Current;
|
|
||||||
|
public static double MatchingScore(string input)
|
||||||
|
{
|
||||||
|
// Empty input is not valid Slang
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return 0d;
|
||||||
|
|
||||||
|
// Run the compiler to get diagnostics
|
||||||
|
var diagnostics = Marshal.DiagnoseSource(input);
|
||||||
|
|
||||||
|
// Count the number of actual Errors (Severity 1).
|
||||||
|
// We ignore Warnings (2), Info (3), etc.
|
||||||
|
double errorCount = diagnostics.Count(d => d.Severity == 1);
|
||||||
|
|
||||||
|
// Get the total line count to calculate error density
|
||||||
|
double lineCount = input.Split('\n').Length;
|
||||||
|
|
||||||
|
// Prevent division by zero
|
||||||
|
if (lineCount == 0)
|
||||||
|
return 0d;
|
||||||
|
|
||||||
|
// Calculate score: Start at 1.0 (100%) and subtract the ratio of errors per line.
|
||||||
|
// Example: 10 lines with 0 errors = 1.0
|
||||||
|
// Example: 10 lines with 2 errors = 0.8
|
||||||
|
// Example: 10 lines with 10+ errors = 0.0
|
||||||
|
double score = 1.0d - (errorCount / lineCount);
|
||||||
|
|
||||||
|
// Clamp the result between 0 and 1
|
||||||
|
return Math.Max(0d, Math.Min(1d, score));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Compile()
|
public override string Compile()
|
||||||
@@ -33,65 +61,65 @@ public class SlangFormatter : ICodeFormatter
|
|||||||
|
|
||||||
public override Line ParseLine(string line)
|
public override Line ParseLine(string line)
|
||||||
{
|
{
|
||||||
HandleCodeChanged();
|
|
||||||
return Marshal.TokenizeLine(line);
|
return Marshal.TokenizeLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCodeChanged()
|
private void HandleCodeChanged()
|
||||||
{
|
{
|
||||||
if (IsDiagnosing)
|
CancellationToken token;
|
||||||
return;
|
string inputSrc;
|
||||||
|
lock (_tokenLock)
|
||||||
|
{
|
||||||
_lspCancellationToken?.Cancel();
|
_lspCancellationToken?.Cancel();
|
||||||
_lspCancellationToken?.Dispose();
|
|
||||||
|
|
||||||
_lspCancellationToken = new CancellationTokenSource();
|
_lspCancellationToken = new CancellationTokenSource();
|
||||||
|
token = _lspCancellationToken.Token;
|
||||||
|
inputSrc = this.RawText;
|
||||||
|
}
|
||||||
|
|
||||||
_ = Task.Run(() => HandleLsp(_lspCancellationToken.Token), _lspCancellationToken.Token);
|
HandleLsp(inputSrc, token).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTimerElapsed(object sender, ElapsedEventArgs e) { }
|
private void OnTimerElapsed(object sender, ElapsedEventArgs e) { }
|
||||||
|
|
||||||
private async Task HandleLsp(CancellationToken cancellationToken)
|
private async UniTaskVoid HandleLsp(string inputSrc, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(200, cancellationToken);
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Dispatch the UI update to the Main Thread
|
await System.Threading.Tasks.Task.Delay(200, cancellationToken: cancellationToken);
|
||||||
if (_mainThreadContext != null)
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dict = Marshal
|
||||||
|
.DiagnoseSource(inputSrc)
|
||||||
|
.GroupBy(d => d.Range.StartLine)
|
||||||
|
.ToDictionary(g => g.Key);
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
|
||||||
|
|
||||||
|
ApplyDiagnostics(dict);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Post ensures ApplyDiagnostics runs on the captured thread (Main Thread)
|
L.Error(ex.Message);
|
||||||
_mainThreadContext.Post(_ => ApplyDiagnostics(), null);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Fallback: If context is null (rare in Unity), try running directly
|
|
||||||
// but warn, as this might crash if not thread-safe.
|
|
||||||
L.Warning("SynchronizationContext was null. Attempting direct update (risky).");
|
|
||||||
ApplyDiagnostics();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This runs on the Main Thread
|
// This runs on the Main Thread
|
||||||
private void ApplyDiagnostics()
|
private void ApplyDiagnostics(Dictionary<uint, IGrouping<uint, Diagnostic>> dict)
|
||||||
{
|
{
|
||||||
List<Diagnostic> diagnosis = Marshal.DiagnoseSource(this.RawText);
|
|
||||||
|
|
||||||
var dict = diagnosis.GroupBy(d => d.Range.StartLine).ToDictionary(g => g.Key);
|
|
||||||
|
|
||||||
var linesToRefresh = new HashSet<uint>(dict.Keys);
|
var linesToRefresh = new HashSet<uint>(dict.Keys);
|
||||||
linesToRefresh.UnionWith(_linesWithErrors);
|
linesToRefresh.UnionWith(_linesWithErrors);
|
||||||
|
|
||||||
IsDiagnosing = true;
|
|
||||||
|
|
||||||
foreach (var lineIndex in linesToRefresh)
|
foreach (var lineIndex in linesToRefresh)
|
||||||
{
|
{
|
||||||
// safety check for out of bounds (in case lines were deleted)
|
// safety check for out of bounds (in case lines were deleted)
|
||||||
@@ -134,7 +162,5 @@ public class SlangFormatter : ICodeFormatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
_linesWithErrors = new HashSet<uint>(dict.Keys);
|
_linesWithErrors = new HashSet<uint>(dict.Keys);
|
||||||
|
|
||||||
IsDiagnosing = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ public static class SlangPatches
|
|||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
public static void isc_ButtonInputCancel()
|
public static void isc_ButtonInputCancel()
|
||||||
{
|
{
|
||||||
L.Info("ButtonInputCancel called on the InputSourceCode static instance.");
|
|
||||||
if (_currentlyEditingMotherboard is null || _motherboardCachedCode is null)
|
if (_currentlyEditingMotherboard is null || _motherboardCachedCode is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,6 +41,10 @@
|
|||||||
<HintPath>$(ManagedDir)/Assembly-CSharp.dll</HintPath>
|
<HintPath>$(ManagedDir)/Assembly-CSharp.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="UniTask">
|
||||||
|
<HintPath>$(ManagedDir)/UniTask.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
|
||||||
<Reference Include="IC10Editor.dll">
|
<Reference Include="IC10Editor.dll">
|
||||||
<HintPath>./ref/IC10Editor.dll</HintPath>
|
<HintPath>./ref/IC10Editor.dll</HintPath>
|
||||||
|
|||||||
Reference in New Issue
Block a user