From a5418218f8252e70bb8d1ef0f64e0e73b7793607 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sat, 24 Oct 2026 06:12:59 +0000 Subject: [PATCH] Register the notebook LaTeX formatters by reflection, and drop polyfill.io AngouriMath's extension.dib, the C# script NuGet loads with the package, began `using AngouriMath;`. An F# notebook loads it into the C# kernel, which has no reference to AngouriMath, so the first output of every F# notebook was CS0246. It now finds ILatexizeable, EDecimal, EInteger and ERational among the loaded assemblies and registers its formatters on those types, which works from either kernel. Measured in the binder/Dockerfile image with the packages packed locally: from F#, the script loads and says so, and derivative "x" "x^3" is 3 x^2 in LaTeX; from C#, an entity and an ERational render as before. And both this script and AngouriMath.Interactive's F# extension put +static void RegisterLatex(Type type, Func latexer) +{ + Formatter.Register(type, (o, writer) => writer.Write($"$${latexer(o)}$$"), "text/latex"); + Formatter.Register(type, (o, writer) => writer.Write($@" -\[{latexer(t)}\]", - "text/html" - ); - - Formatter.SetPreferredMimeTypesFor(typeof(T), "text/latex"); +\[{latexer(o)}\]"), "text/html"); + Formatter.SetPreferredMimeTypesFor(type, "text/latex"); } -Formatter.SetPreferredMimeTypesFor(typeof(PeterO.Numbers.EDecimal), "text/plain"); -Formatter.Register(o => o.ToString(), "text/plain"); +foreach (var name in new[] { "PeterO.Numbers.EDecimal", "PeterO.Numbers.EInteger" }) + if (FindType("Numbers", name) is { } plain) + { + Formatter.SetPreferredMimeTypesFor(plain, "text/plain"); + Formatter.Register(plain, (o, writer) => writer.Write(o.ToString()), "text/plain"); + } -Formatter.SetPreferredMimeTypesFor(typeof(PeterO.Numbers.EInteger), "text/plain"); -Formatter.Register(o => o.ToString(), "text/plain"); +if (FindType("AngouriMath", "AngouriMath.Core.ILatexizeable") is { } latexizeable + && latexizeable.GetMethod("Latexize", Type.EmptyTypes) is { } latexize) + RegisterLatex(latexizeable, o => (string)latexize.Invoke(o, null)); -RegisterLatex(o => o.Latexize()); - -RegisterLatex(o => $@"\frac{{{o.Numerator}}}{{{o.Denominator}}}"); +if (FindType("Numbers", "PeterO.Numbers.ERational") is { } rational) + RegisterLatex(rational, o => $@"\frac{{{rational.GetProperty("Numerator").GetValue(o)}}}{{{rational.GetProperty("Denominator").GetValue(o)}}}"); "Extensions for LaTeX loaded!" - diff --git a/Sources/Tests/InteractiveWrapperUnitTests/HtmlOutput.fs b/Sources/Tests/InteractiveWrapperUnitTests/HtmlOutput.fs index e7d9673aa..17a7869e4 100644 --- a/Sources/Tests/InteractiveWrapperUnitTests/HtmlOutput.fs +++ b/Sources/Tests/InteractiveWrapperUnitTests/HtmlOutput.fs @@ -18,7 +18,6 @@ let ``Latex with magic ILatexizeable html`` () = let entity = parsed "x / 2" let html = entity.ToDisplayString("text/html") Assert.Equal(@" - \[\frac{x}{2}\]", html) @@ -29,7 +28,6 @@ let ``Latex with magic ERational for html`` () = let entity = (("2 / 3" |> asNumber) :?> Entity.Number.Rational).ERational let html = entity.ToDisplayString("text/html") Assert.Equal(@" - \[\frac{2}{3}\]", html) @@ -40,7 +38,6 @@ let ``Latex with magic ERational multi-char for html`` () = let entity = (("23 / 36" |> asNumber) :?> Entity.Number.Rational).ERational let html = entity.ToDisplayString("text/html") Assert.Equal(@" - \[\frac{23}{36}\]", html) diff --git a/Sources/Wrappers/AngouriMath.Interactive/KernelExtension.fs b/Sources/Wrappers/AngouriMath.Interactive/KernelExtension.fs index e7dd23f72..b12e0af82 100644 --- a/Sources/Wrappers/AngouriMath.Interactive/KernelExtension.fs +++ b/Sources/Wrappers/AngouriMath.Interactive/KernelExtension.fs @@ -20,7 +20,6 @@ type KernelExtension() = // register text/html (fun o -> $@" - \[{latexizer o}\]") |> (fun f -> new Func<'a, string>(f))