Add linting

This commit is contained in:
Neil Brommer 2023-07-26 11:46:15 -07:00
parent b917b99a2c
commit e1cc716606
5 changed files with 126 additions and 30 deletions

View file

@ -1,4 +1,6 @@
using Microsoft.CodeAnalysis.CSharp.Scripting; using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting;
namespace Cauldron.Core; namespace Cauldron.Core;
@ -13,8 +15,7 @@ public class RoslynHost
/// <param name="globals">Values that will be made available to the script</param> /// <param name="globals">Values that will be made available to the script</param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
public static async Task RunScript(string code, string[] imports, public static async Task RunScript(string code, string[] imports,
RoslynHostGlobals globals, RoslynHostGlobals globals, CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default)
{ {
ScriptOptions options = ScriptOptions.Default ScriptOptions options = ScriptOptions.Default
.AddImports(imports); .AddImports(imports);
@ -22,6 +23,16 @@ public class RoslynHost
await CSharpScript.RunAsync(code, options, globals, await CSharpScript.RunAsync(code, options, globals,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
} }
public static ImmutableArray<Diagnostic> BuildScript(string code, string[] imports,
RoslynHostGlobals globals)
{
ScriptOptions options = ScriptOptions.Default
.AddImports(imports);
Script<object> script = CSharpScript.Create(code, options, globals.GetType());
return script.GetCompilation().GetDiagnostics();
}
} }
public class RoslynHostGlobals public class RoslynHostGlobals

View file

@ -413,7 +413,7 @@
<customObject id="YLy-65-1bz" customClass="NSFontManager"/> <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="-23" y="-243"/> <point key="canvasLocation" x="-23" y="-256"/>
</scene> </scene>
<!--Window Controller--> <!--Window Controller-->
<scene sceneID="ktg-sd-7li"> <scene sceneID="ktg-sd-7li">
@ -421,11 +421,11 @@
<windowController id="JKR-xj-8kh" customClass="MainWindow" sceneMemberID="viewController"> <windowController id="JKR-xj-8kh" customClass="MainWindow" sceneMemberID="viewController">
<window key="window" title="Cauldron" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="" animationBehavior="default" tabbingMode="preferred" id="d7K-Gm-g9N"> <window key="window" title="Cauldron" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="" animationBehavior="default" tabbingMode="preferred" id="d7K-Gm-g9N">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<rect key="contentRect" x="211" y="264" width="620" height="406"/> <rect key="contentRect" x="211" y="264" width="749" height="445"/>
<rect key="screenRect" x="0.0" y="0.0" width="1512" height="944"/> <rect key="screenRect" x="0.0" y="0.0" width="1512" height="944"/>
<value key="minSize" type="size" width="480" height="270"/> <value key="minSize" type="size" width="480" height="270"/>
<view key="contentView" id="3If-Oy-0LB"> <view key="contentView" id="3If-Oy-0LB">
<rect key="frame" x="0.0" y="0.0" width="620" height="406"/> <rect key="frame" x="0.0" y="0.0" width="749" height="445"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</view> </view>
<toolbar key="toolbar" implicitIdentifier="09D11707-F4A3-4FD5-970E-AC5832E91C2B" showsBaselineSeparator="NO" displayMode="iconOnly" sizeMode="regular" id="c7l-9K-zGH"> <toolbar key="toolbar" implicitIdentifier="09D11707-F4A3-4FD5-970E-AC5832E91C2B" showsBaselineSeparator="NO" displayMode="iconOnly" sizeMode="regular" id="c7l-9K-zGH">
@ -463,7 +463,7 @@
</windowController> </windowController>
<customObject id="Dyo-ea-3jV" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="Dyo-ea-3jV" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="-24" y="70"/> <point key="canvasLocation" x="-23" y="73"/>
</scene> </scene>
<!--Split View Controller--> <!--Split View Controller-->
<scene sceneID="BCF-ui-EPb"> <scene sceneID="BCF-ui-EPb">

View file

@ -1,8 +1,13 @@
using System; using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading; using System.Threading;
using System.Timers;
using AppKit; using AppKit;
using Cauldron.Macos.SourceWriter; using Cauldron.Macos.SourceWriter;
using Cauldron.Macos.SourceWriter.LanguageFormats; using Cauldron.Macos.SourceWriter.LanguageFormats;
using Foundation;
using Microsoft.CodeAnalysis;
namespace Cauldron.Macos; namespace Cauldron.Macos;
@ -61,6 +66,7 @@ public partial class MainWindow : NSWindowController
this.RunScriptToolbarButton.Activated += RunScript; this.RunScriptToolbarButton.Activated += RunScript;
SourceTextView scriptTextBox = this.ScriptEditorTextBox; SourceTextView scriptTextBox = this.ScriptEditorTextBox;
scriptTextBox.OnFinishedTyping += this.BuildScript;
scriptTextBox.Font = NSFont.MonospacedSystemFont(new nfloat(14), NSFontWeight.Regular); scriptTextBox.Font = NSFont.MonospacedSystemFont(new nfloat(14), NSFontWeight.Regular);
scriptTextBox.AutomaticQuoteSubstitutionEnabled = false; scriptTextBox.AutomaticQuoteSubstitutionEnabled = false;
scriptTextBox.AutomaticDashSubstitutionEnabled = false; scriptTextBox.AutomaticDashSubstitutionEnabled = false;
@ -74,6 +80,11 @@ public partial class MainWindow : NSWindowController
scriptTextBox.Formatter.Reformat(); scriptTextBox.Formatter.Reformat();
} }
public void BuildScript(object sender, ElapsedEventArgs args)
{
ScriptRunner.BuildScript(this);
}
public void RunScript(object sender, EventArgs e) public void RunScript(object sender, EventArgs e)
{ {
ScriptRunner.RunScript(this); ScriptRunner.RunScript(this);
@ -94,6 +105,46 @@ public partial class MainWindow : NSWindowController
this.CreateNewTab(); this.CreateNewTab();
} }
public void UpdateScriptDiagnostics(ImmutableArray<Diagnostic> diagnostics)
{
Console.WriteLine(diagnostics.Select(d => $"{d.Severity}: {d.GetMessage()}").Join("\n"));
foreach (Diagnostic diagnostic in diagnostics)
{
int start = diagnostic.Location.SourceSpan.Start;
int end = diagnostic.Location.SourceSpan.End;
if (start == end && end < this.ScriptText.Length)
end += 1;
else if (start == end)
start -= 1;
NSRange range = new(start,end);
this.ScriptEditorTextBox.LayoutManager
.AddTemporaryAttribute(NSStringAttributeKey.UnderlineStyle,
new NSNumber((int)(NSUnderlineStyle.Thick | NSUnderlineStyle.PatternDot)),
range);
this.ScriptEditorTextBox.LayoutManager
.AddTemporaryAttribute(NSStringAttributeKey.ToolTip,
new NSString($"{diagnostic.Id} {diagnostic.GetMessage()}"),
range);
if (diagnostic.Severity == DiagnosticSeverity.Error)
this.ScriptEditorTextBox.LayoutManager
.AddTemporaryAttribute(NSStringAttributeKey.UnderlineColor, NSColor.SystemRed,
range);
else if (diagnostic.Severity == DiagnosticSeverity.Warning)
this.ScriptEditorTextBox.LayoutManager
.AddTemporaryAttribute(NSStringAttributeKey.UnderlineColor, NSColor.SystemGreen,
range);
else if (diagnostic.Severity == DiagnosticSeverity.Info)
this.ScriptEditorTextBox.LayoutManager
.AddTemporaryAttribute(NSStringAttributeKey.UnderlineColor, NSColor.SystemBlue,
range);
}
}
public void SetScriptRunState(bool scriptIsRunning) public void SetScriptRunState(bool scriptIsRunning)
{ {
if (scriptIsRunning) if (scriptIsRunning)

View file

@ -7,40 +7,39 @@ using Cauldron.Core;
using System.Reflection; using System.Reflection;
using System.Linq; using System.Linq;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.IO; using System.IO;
namespace Cauldron.Macos; namespace Cauldron.Macos;
public static class ScriptRunner public static class ScriptRunner
{ {
public static void BuildScript(MainWindow window)
{
string script = "";
window.BeginInvokeOnMainThread(() => script = window.ScriptText);
TagBuilder body = new("body");
RoslynHostGlobals globals = new(null);
window.BeginInvokeOnMainThread(() => globals = new RoslynHostGlobals(CreateCauldronWriter(window, body)));
Task task = Task
.Run(() => RoslynHost.BuildScript(script, Array.Empty<string>(), globals))
.ContinueWith(t => window.BeginInvokeOnMainThread(
() => window.UpdateScriptDiagnostics(t.Result)));
}
public static void RunScript(MainWindow window) public static void RunScript(MainWindow window)
{ {
window.SetScriptRunState(true); window.SetScriptRunState(true);
TagBuilder body = new("body"); TagBuilder body = new("body");
string script = window.ScriptText;
window.ScriptOutputWebView.SetOutputPanelContent(body); window.ScriptCancellationTokenSource = new CancellationTokenSource();
TaskScheduler uiThread = TaskScheduler.FromCurrentSynchronizationContext(); TaskScheduler uiThread = TaskScheduler.FromCurrentSynchronizationContext();
CauldronWriter writer = new(obj => // Clear the output for the new run
{ window.ScriptOutputWebView.SetOutputPanelContent(body);
window.BeginInvokeOnMainThread(() =>
{
TagBuilder outputSection = new("section");
outputSection.AddCssClass("output-section");
outputSection.InnerHtml.AppendHtml(GenerateValueOutput(obj));
body.InnerHtml.AppendHtml(outputSection);
window.ScriptOutputWebView.SetOutputPanelContent(body);
});
return Task.CompletedTask;
});
window.ScriptCancellationTokenSource = new CancellationTokenSource();
string script = window.ScriptText;
Task task = Task Task task = Task
.Run(async () => .Run(async () =>
@ -48,7 +47,7 @@ public static class ScriptRunner
try try
{ {
await RoslynHost.RunScript(script, Array.Empty<string>(), await RoslynHost.RunScript(script, Array.Empty<string>(),
new RoslynHostGlobals(writer), new RoslynHostGlobals(CreateCauldronWriter(window, body)),
window.ScriptCancellationTokenSource.Token); window.ScriptCancellationTokenSource.Token);
} }
catch (Exception ex) catch (Exception ex)
@ -66,6 +65,24 @@ public static class ScriptRunner
.ContinueWith((t) => window.SetScriptRunState(false), uiThread); .ContinueWith((t) => window.SetScriptRunState(false), uiThread);
} }
private static CauldronWriter CreateCauldronWriter(MainWindow window, TagBuilder body)
{
return new CauldronWriter (obj =>
{
window.BeginInvokeOnMainThread(() =>
{
TagBuilder outputSection = new("section");
outputSection.AddCssClass("output-section");
outputSection.InnerHtml.AppendHtml(GenerateValueOutput(obj));
body.InnerHtml.AppendHtml(outputSection);
window.ScriptOutputWebView.SetOutputPanelContent(body);
});
return Task.CompletedTask;
});
}
private static TagBuilder GenerateValueOutput(object value) private static TagBuilder GenerateValueOutput(object value)
{ {
if (value is null) if (value is null)

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Timers;
using AppKit; using AppKit;
using CoreGraphics; using CoreGraphics;
using Foundation; using Foundation;
@ -435,6 +436,17 @@ public class SourceTextView : NSTextView
#region Override Methods #region Override Methods
private Timer InputTimoutTimer { get; set; }
/// <summary>
/// The amount of time with no user input after which <see cref="OnFinishedTyping"/> will be run
/// </summary>
public TimeSpan InputTimeoutInterval { get; set; } = new TimeSpan(0, 0, 1);
/// <summary>
/// An event triggered when the user has stopped typing for a period of time defined by
/// <see cref="InputTimeoutInterval"/>
/// </summary>
public event ElapsedEventHandler OnFinishedTyping;
/// <summary> /// <summary>
/// Look for special keys being pressed and does specific processing based on the key. /// Look for special keys being pressed and does specific processing based on the key.
/// </summary> /// </summary>
@ -570,7 +582,12 @@ public class SourceTextView : NSTextView
this.Formatter.Reformat(); this.Formatter.Reformat();
//Console.WriteLine ("Key: {0}", (int)theEvent.Characters[0]); this.InputTimoutTimer?.Stop();
this.InputTimoutTimer?.Close();
this.InputTimoutTimer = new Timer(this.InputTimeoutInterval);
this.InputTimoutTimer.AutoReset = false;
this.InputTimoutTimer.Elapsed += this.OnFinishedTyping;
this.InputTimoutTimer.Start();
} }
/// <summary> /// <summary>