2023-07-19 22:09:25 +00:00
|
|
|
|
using System;
|
2023-07-22 00:20:46 +00:00
|
|
|
|
using System.Collections.Generic;
|
2023-07-19 22:09:25 +00:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2023-07-22 00:20:46 +00:00
|
|
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
2023-07-21 20:11:56 +00:00
|
|
|
|
using Cauldron.Core;
|
2023-07-24 18:37:09 +00:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
2023-07-24 23:29:46 +00:00
|
|
|
|
using System.IO;
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
2023-07-21 20:11:56 +00:00
|
|
|
|
namespace Cauldron.Macos;
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
|
|
|
|
public static class ScriptRunner
|
|
|
|
|
{
|
2023-07-26 18:46:15 +00:00
|
|
|
|
public static void BuildScript(MainWindow window)
|
2023-07-19 22:09:25 +00:00
|
|
|
|
{
|
2023-07-26 18:46:15 +00:00
|
|
|
|
string script = "";
|
|
|
|
|
window.BeginInvokeOnMainThread(() => script = window.ScriptText);
|
2023-07-22 00:20:46 +00:00
|
|
|
|
|
|
|
|
|
TagBuilder body = new("body");
|
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
RoslynHostGlobals globals = new(null);
|
|
|
|
|
window.BeginInvokeOnMainThread(() => globals = new RoslynHostGlobals(CreateCauldronWriter(window, body)));
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
Task task = Task
|
|
|
|
|
.Run(() => RoslynHost.BuildScript(script, Array.Empty<string>(), globals))
|
|
|
|
|
.ContinueWith(t => window.BeginInvokeOnMainThread(
|
|
|
|
|
() => window.UpdateScriptDiagnostics(t.Result)));
|
|
|
|
|
}
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
public static void RunScript(MainWindow window)
|
|
|
|
|
{
|
|
|
|
|
window.SetScriptRunState(true);
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
TagBuilder body = new("body");
|
|
|
|
|
string script = window.ScriptText;
|
2023-07-19 22:09:25 +00:00
|
|
|
|
window.ScriptCancellationTokenSource = new CancellationTokenSource();
|
2023-07-26 18:46:15 +00:00
|
|
|
|
TaskScheduler uiThread = TaskScheduler.FromCurrentSynchronizationContext();
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
// Clear the output for the new run
|
|
|
|
|
window.ScriptOutputWebView.SetOutputPanelContent(body);
|
2023-07-19 22:09:25 +00:00
|
|
|
|
|
|
|
|
|
Task task = Task
|
|
|
|
|
.Run(async () =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await RoslynHost.RunScript(script, Array.Empty<string>(),
|
2023-07-26 18:46:15 +00:00
|
|
|
|
new RoslynHostGlobals(CreateCauldronWriter(window, body)),
|
2023-07-19 22:09:25 +00:00
|
|
|
|
window.ScriptCancellationTokenSource.Token);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
window.BeginInvokeOnMainThread(() =>
|
2023-07-22 00:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
TagBuilder exTag = new("pre");
|
|
|
|
|
exTag.InnerHtml.Append(ex.ToString());
|
|
|
|
|
body.InnerHtml.AppendHtml(exTag);
|
|
|
|
|
|
|
|
|
|
window.ScriptOutputWebView.SetOutputPanelContent(body);
|
|
|
|
|
});
|
2023-07-19 22:09:25 +00:00
|
|
|
|
}
|
|
|
|
|
}, window.ScriptCancellationTokenSource.Token)
|
2023-07-24 18:37:09 +00:00
|
|
|
|
.ContinueWith((t) => window.SetScriptRunState(false), uiThread);
|
2023-07-19 22:09:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-26 18:46:15 +00:00
|
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-22 00:20:46 +00:00
|
|
|
|
private static TagBuilder GenerateValueOutput(object value)
|
|
|
|
|
{
|
2023-07-24 18:37:09 +00:00
|
|
|
|
if (value is null)
|
2023-07-22 00:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
TagBuilder tag = new("p");
|
2023-07-24 18:37:09 +00:00
|
|
|
|
TagBuilder code = new("code");
|
|
|
|
|
code.InnerHtml.Append("null");
|
|
|
|
|
tag.InnerHtml.AppendHtml(code);
|
2023-07-22 00:20:46 +00:00
|
|
|
|
return tag;
|
|
|
|
|
}
|
2023-07-24 18:37:09 +00:00
|
|
|
|
if (value.GetType().IsPrimitive || value is string)
|
2023-07-22 00:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
TagBuilder tag = new("p");
|
|
|
|
|
tag.InnerHtml.Append(value.ToString());
|
|
|
|
|
return tag;
|
|
|
|
|
}
|
2023-07-24 18:37:09 +00:00
|
|
|
|
if (value is IEnumerable<object> enumerable)
|
2023-07-22 00:20:46 +00:00
|
|
|
|
{
|
2023-07-24 18:37:09 +00:00
|
|
|
|
return GenerateTable(enumerable);
|
2023-07-22 00:20:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 18:37:09 +00:00
|
|
|
|
TagBuilder defaultTag = new("p");
|
|
|
|
|
defaultTag.InnerHtml.Append(value.ToString());
|
|
|
|
|
return defaultTag;
|
2023-07-22 00:20:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 18:37:09 +00:00
|
|
|
|
private static void SetOutputPanelContent(this WebKit.WKWebView webView, TagBuilder body)
|
2023-07-22 00:20:46 +00:00
|
|
|
|
{
|
|
|
|
|
TagBuilder head = new("head");
|
2023-07-24 17:07:44 +00:00
|
|
|
|
TagBuilder style = new("style");
|
2023-07-24 23:29:46 +00:00
|
|
|
|
style.InnerHtml.AppendHtml(OutputCss);
|
2023-07-24 17:07:44 +00:00
|
|
|
|
head.InnerHtml.AppendHtml(style);
|
2023-07-22 00:20:46 +00:00
|
|
|
|
|
|
|
|
|
string contents = "<!DOCTYPE html>"
|
|
|
|
|
+ head.RenderAsString()
|
|
|
|
|
+ body.RenderAsString();
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Contents: " + contents);
|
|
|
|
|
|
|
|
|
|
webView.LoadHtmlString(new Foundation.NSString(contents), null);
|
|
|
|
|
}
|
2023-07-24 17:07:44 +00:00
|
|
|
|
|
2023-07-24 18:37:09 +00:00
|
|
|
|
private static TagBuilder GenerateTable(IEnumerable<object> enumerable)
|
|
|
|
|
{
|
|
|
|
|
var listType = enumerable.GetType().GenericTypeArguments[0];
|
|
|
|
|
|
|
|
|
|
if (enumerable.GetType().GenericTypeArguments[0].IsPrimitive
|
|
|
|
|
|| enumerable.GetType().GenericTypeArguments[0] == typeof(string))
|
|
|
|
|
return GenerateSimpleTable(enumerable);
|
|
|
|
|
|
|
|
|
|
TagBuilder output = new("table");
|
|
|
|
|
|
|
|
|
|
IList<PropertyInfo> properties = enumerable.GetType()
|
|
|
|
|
.GenericTypeArguments[0].GetProperties()
|
|
|
|
|
.Where(p => !p.GetCustomAttributes<DisplayAttribute>(false)
|
|
|
|
|
.Any(a => a.GetAutoGenerateField() == false))
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
// Caption
|
|
|
|
|
TagBuilder caption = new("caption");
|
|
|
|
|
caption.InnerHtml.Append(enumerable.GetType().GetCSharpName());
|
|
|
|
|
output.InnerHtml.AppendHtml(caption);
|
|
|
|
|
|
|
|
|
|
// Header Row
|
|
|
|
|
List<TagBuilder> tableHeadCells = properties
|
|
|
|
|
.Select(p =>
|
|
|
|
|
{
|
|
|
|
|
string displayName = p.GetCustomAttributes<DisplayAttribute>(false)
|
|
|
|
|
.Where(a => !string.IsNullOrEmpty(a.GetName()))
|
|
|
|
|
.FirstOrDefault()
|
|
|
|
|
?.GetName()
|
|
|
|
|
?? p.Name;
|
|
|
|
|
|
|
|
|
|
TagBuilder th = new("th");
|
|
|
|
|
th.InnerHtml.Append(displayName);
|
|
|
|
|
|
|
|
|
|
return th;
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
TagBuilder theadTr = new("tr");
|
|
|
|
|
tableHeadCells.ForEach(th => theadTr.InnerHtml.AppendHtml(th));
|
|
|
|
|
|
|
|
|
|
TagBuilder thead = new("thead");
|
|
|
|
|
thead.InnerHtml.AppendHtml(theadTr);
|
|
|
|
|
output.InnerHtml.AppendHtml(thead);
|
|
|
|
|
|
|
|
|
|
// Content Rows
|
|
|
|
|
List<TagBuilder> tableRows = enumerable
|
|
|
|
|
.Select(item =>
|
|
|
|
|
{
|
|
|
|
|
List<TagBuilder> cells = properties
|
|
|
|
|
.Select(p =>
|
|
|
|
|
{
|
|
|
|
|
var content = p.GetValue(item);
|
|
|
|
|
|
|
|
|
|
TagBuilder td = new("td");
|
|
|
|
|
td.InnerHtml.AppendHtml(GenerateValueOutput(content));
|
|
|
|
|
return td;
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
TagBuilder tr = new("tr");
|
|
|
|
|
cells.ForEach(td => tr.InnerHtml.AppendHtml(td));
|
|
|
|
|
return tr;
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
TagBuilder tbody = new("tbody");
|
|
|
|
|
tableRows.ForEach(tr => tbody.InnerHtml.AppendHtml(tr));
|
|
|
|
|
output.InnerHtml.AppendHtml(tbody);
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static TagBuilder GenerateSimpleTable(IEnumerable<object> enumerable)
|
|
|
|
|
{
|
|
|
|
|
TagBuilder output = new("table");
|
|
|
|
|
|
|
|
|
|
// Caption
|
|
|
|
|
TagBuilder caption = new("caption");
|
|
|
|
|
caption.InnerHtml.Append(enumerable.GetType().GetCSharpName());
|
|
|
|
|
output.InnerHtml.AppendHtml(caption);
|
|
|
|
|
|
|
|
|
|
// Content Rows
|
|
|
|
|
List<TagBuilder> tableRows = enumerable
|
|
|
|
|
.Select(item =>
|
|
|
|
|
{
|
|
|
|
|
List<TagBuilder> cells = enumerable
|
|
|
|
|
.Select(v =>
|
|
|
|
|
{
|
|
|
|
|
TagBuilder td = new("td");
|
|
|
|
|
td.InnerHtml.AppendHtml(v.ToString());
|
|
|
|
|
return td;
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
TagBuilder tr = new("tr");
|
|
|
|
|
cells.ForEach(td => tr.InnerHtml.AppendHtml(td));
|
|
|
|
|
return tr;
|
|
|
|
|
})
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
TagBuilder tbody = new("tbody");
|
|
|
|
|
tableRows.ForEach(tr => tbody.InnerHtml.AppendHtml(tr));
|
|
|
|
|
output.InnerHtml.AppendHtml(tbody);
|
|
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 23:29:46 +00:00
|
|
|
|
private static string _outputCss = null;
|
|
|
|
|
private static string OutputCss
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_outputCss is null)
|
|
|
|
|
{
|
|
|
|
|
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../Resources/ScriptOutput.css");
|
|
|
|
|
_outputCss = File.ReadAllText(path);
|
2023-07-24 17:07:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 23:29:46 +00:00
|
|
|
|
return _outputCss;
|
2023-07-24 17:07:44 +00:00
|
|
|
|
}
|
2023-07-24 23:29:46 +00:00
|
|
|
|
}
|
2023-07-22 00:20:46 +00:00
|
|
|
|
}
|