Skip to content

Commit fc216b0

Browse files
jonsequiturshyamnamboodiripad
authored andcommitted
add DisplayTable method
1 parent e2cfa87 commit fc216b0

File tree

16 files changed

+166
-163
lines changed

16 files changed

+166
-163
lines changed

src/Microsoft.DotNet.Interactive.ApiCompatibility.Tests/ApiCompatibilityTests.Interactive_api_is_not_changed.approved.txt

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ Microsoft.DotNet.Interactive
6464
public System.String ToString()
6565
public Diagnostic WithLinePositionSpan(LinePositionSpan linePositionSpan)
6666
public class DisplayedValue
67-
.ctor(System.String displayId, System.String mimeType, KernelInvocationContext context)
68-
.ctor(System.String displayId, System.String[] mimeTypes, KernelInvocationContext context)
69-
public System.Collections.Generic.IReadOnlyCollection<System.String> MimeTypes { get;}
67+
.ctor(System.Collections.Generic.IReadOnlyList<FormattedValue> formattedValues, KernelInvocationContext context)
68+
public System.String DisplayId { get;}
69+
public System.Collections.Generic.IReadOnlyList<FormattedValue> FormattedValues { get;}
7070
public System.Void Update(System.Object updatedValue)
7171
public class EventRoutingSlip : RoutingSlip
7272
.ctor()
@@ -672,10 +672,6 @@ Microsoft.DotNet.Interactive.Http
672672
Microsoft.DotNet.Interactive.Parsing
673673
public class ActionDirectiveNode : DirectiveNode
674674
public System.String ParentKernelName { get;}
675-
public class Diagnostic
676-
public Location Location { get;}
677-
public System.String Message { get;}
678-
public DiagnosticSeverity Severity { get;}
679675
public enum DiagnosticSeverity : System.Enum, System.IComparable, System.IConvertible, System.IFormattable
680676
Hidden=0
681677
Info=1
@@ -687,22 +683,19 @@ Microsoft.DotNet.Interactive.Parsing
687683
public System.String GetHelpForSymbol(System.CommandLine.Symbol symbol)
688684
public System.Void Write(System.CommandLine.Help.HelpContext context)
689685
public abstract class DirectiveNode : LanguageNode
690-
public System.Collections.Generic.IEnumerable<Diagnostic> GetDiagnostics()
686+
public System.Collections.Generic.IEnumerable<Microsoft.DotNet.Interactive.Diagnostic> GetDiagnostics()
691687
public System.CommandLine.Parsing.ParseResult GetDirectiveParseResult()
692688
public class DirectiveToken : SyntaxToken
693689
public System.String DirectiveName { get;}
694690
public class KernelNameDirectiveNode : DirectiveNode
695691
public class LanguageNode : SyntaxNode
696692
public System.String Name { get;}
697-
public System.Collections.Generic.IEnumerable<Diagnostic> GetDiagnostics()
693+
public System.Collections.Generic.IEnumerable<Microsoft.DotNet.Interactive.Diagnostic> GetDiagnostics()
698694
public class LanguageSpecificParseResult
699695
public static LanguageSpecificParseResult None { get;}
700696
.ctor()
701-
public System.Collections.Generic.IEnumerable<Diagnostic> GetDiagnostics()
697+
public System.Collections.Generic.IEnumerable<Microsoft.DotNet.Interactive.Diagnostic> GetDiagnostics()
702698
public class LanguageToken : SyntaxToken
703-
public class Location
704-
public Microsoft.CodeAnalysis.Text.TextSpan SourceSpan { get;}
705-
public PolyglotSyntaxTree SourceTree { get;}
706699
public class PolyglotSubmissionNode : SyntaxNode
707700
public System.String DefaultLanguage { get;}
708701
public class PolyglotSyntaxTree
@@ -731,7 +724,7 @@ Microsoft.DotNet.Interactive.Parsing
731724
public SyntaxNode FindNode(Microsoft.CodeAnalysis.Text.TextSpan span)
732725
public SyntaxNode FindNode(System.Int32 position)
733726
public SyntaxToken FindToken(System.Int32 position)
734-
public System.Collections.Generic.IEnumerable<Diagnostic> GetDiagnostics()
727+
public System.Collections.Generic.IEnumerable<Microsoft.DotNet.Interactive.Diagnostic> GetDiagnostics()
735728
public abstract class SyntaxNodeOrToken
736729
public SyntaxNode Parent { get;}
737730
public Microsoft.CodeAnalysis.Text.TextSpan Span { get;}
@@ -944,3 +937,4 @@ System
944937
public static class DisplayExtensions
945938
public static Microsoft.DotNet.Interactive.DisplayedValue Display(String[] mimeTypes)
946939
public static Microsoft.DotNet.Interactive.DisplayedValue DisplayAs(String mimeType)
940+
public static Microsoft.DotNet.Interactive.DisplayedValue DisplayTable<T>(String[] mimeTypes)

src/Microsoft.DotNet.Interactive.Formatting.Tests/AssertionExtensions.cs renamed to src/Microsoft.DotNet.Interactive.Formatting.Tests/Utility/AssertionExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
using Assent;
55
using FluentAssertions;
66
using FluentAssertions.Primitives;
7-
using Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
87
using System.Linq;
98
using System;
109

11-
namespace Microsoft.DotNet.Interactive.Formatting.Tests;
10+
namespace Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
1211

1312
public static class AssertionExtensions
1413
{

src/Microsoft.DotNet.Interactive.Formatting/HtmlFormatter.cs

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ internal static PocketView TagWithPlainTextStyling(
6262
internal static FormatterMapByType FormattersForAnyObject;
6363

6464
internal static FormatterMapByType FormattersForAnyEnumerable =
65-
new(typeof(HtmlFormatter<>), nameof(HtmlFormatter<object>.CreateTableFormatterForAnyEnumerable));
65+
new(typeof(HtmlFormatter<>), nameof(HtmlFormatter<object>.CreateTreeViewFormatterForAnyEnumerable));
6666

6767
internal static readonly ITypeFormatter[] DefaultFormatters =
6868
{
@@ -212,11 +212,11 @@ type.FullName is not null &&
212212
return true;
213213
}),
214214

215-
new HtmlFormatter<decimal>((value, context) =>
216-
{
217-
FormatAndStyleAsPlainText(value, context);
218-
return true;
219-
}),
215+
new HtmlFormatter<decimal>((value, context) =>
216+
{
217+
FormatAndStyleAsPlainText(value, context);
218+
return true;
219+
}),
220220

221221
new HtmlFormatter<object>((value, context) =>
222222
{
@@ -226,22 +226,7 @@ type.FullName is not null &&
226226
var formatter = GetDefaultFormatterForAnyObject(type);
227227
return formatter.Format(value, context);
228228
}),
229-
230-
// Final last resort is to convert to plain text
231-
new HtmlFormatter<object>((value, context) =>
232-
{
233-
if (value is null)
234-
{
235-
FormatAndStyleAsPlainText(Formatter.NullString, context);
236-
}
237-
else
238-
{
239-
FormatAndStyleAsPlainText(value, context);
240-
}
241-
242-
return true;
243-
}),
244-
229+
245230
new HtmlFormatter<JsonDocument>((doc, context) =>
246231
{
247232
doc.RootElement.FormatTo(context, MimeType);

src/Microsoft.DotNet.Interactive.Formatting/HtmlFormatter{T}.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections;
66
using System.Collections.Generic;
77
using System.Linq;
8+
using System.Reflection;
89
using Microsoft.AspNetCore.Html;
910
using Microsoft.DotNet.Interactive.Utility;
1011
using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags;
@@ -55,7 +56,7 @@ public override bool Format(
5556

5657
public override string MimeType => HtmlFormatter.MimeType;
5758

58-
internal static HtmlFormatter<T> CreateTableFormatterForAnyEnumerable()
59+
internal static HtmlFormatter<T> CreateTreeViewFormatterForAnyEnumerable()
5960
{
6061
Func<T, IEnumerable> getKeys = null;
6162
Func<T, IEnumerable> getValues = instance => (IEnumerable)instance;

src/Microsoft.DotNet.Interactive.Formatting/TabularData/TabularDataFormatterSource.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,7 @@ internal class TabularDataFormatterSource : ITypeFormatterSource
1414
{
1515
public IEnumerable<ITypeFormatter> CreateTypeFormatters()
1616
{
17-
yield return new HtmlFormatter<TabularDataResource>((value, context) =>
18-
{
19-
context.RequireDefaultStyles();
20-
21-
IReadOnlyList<IHtmlContent> headers =
22-
value.Schema
23-
.Fields
24-
.Select(f => (IHtmlContent)td(span(f.Name)))
25-
.ToArray();
26-
27-
var (rowData, remainingCount) = value.Data
28-
.TakeAndCountRemaining(Formatter.ListExpansionLimit, true);
29-
30-
var rows =
31-
rowData
32-
.Select(d => (IHtmlContent)tr(d.Select(v => td(v.Value))))
33-
.ToList();
34-
35-
if (remainingCount > 0)
36-
{
37-
rows.Add(tr(td[colspan: $"{headers.Count}"](i($"({remainingCount} more)"))));
38-
}
39-
40-
Html.Table(headers, rows).WriteTo(context);
41-
});
17+
yield return new HtmlFormatter<TabularDataResource>((value, context) => FormatHtml(context, value));
4218

4319
yield return new JsonFormatter<TabularDataResource>((value, context) =>
4420
{
@@ -66,4 +42,29 @@ public IEnumerable<ITypeFormatter> CreateTypeFormatters()
6642
}, context);
6743
});
6844
}
45+
46+
internal static void FormatHtml(FormatContext context, TabularDataResource value)
47+
{
48+
context.RequireDefaultStyles();
49+
50+
IReadOnlyList<IHtmlContent> headers =
51+
value.Schema
52+
.Fields
53+
.Select(f => (IHtmlContent)td(span(f.Name)))
54+
.ToArray();
55+
56+
var (rowData, remainingCount) = value.Data.TakeAndCountRemaining(Formatter.ListExpansionLimit, true);
57+
58+
var rows =
59+
rowData
60+
.Select(d => (IHtmlContent)tr(d.Select(v => td(v.Value))))
61+
.ToList();
62+
63+
if (remainingCount > 0)
64+
{
65+
rows.Add(tr(td[colspan: $"{headers.Count}"](i($"({remainingCount} more)"))));
66+
}
67+
68+
Html.Table(headers, rows).WriteTo(context);
69+
}
6970
}

src/Microsoft.DotNet.Interactive.HttpRequest.Tests/HttpRequestKernelTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
using Microsoft.DotNet.Interactive.Commands;
1414
using Microsoft.DotNet.Interactive.Events;
1515
using Microsoft.DotNet.Interactive.Formatting;
16-
using Microsoft.DotNet.Interactive.Formatting.Tests;
16+
using Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
1717
using Microsoft.DotNet.Interactive.Tests.Utility;
1818
using Xunit;
1919

src/Microsoft.DotNet.Interactive.Jupyter.Tests/MagicCommandTests.who_and_whos.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Microsoft.DotNet.Interactive.Commands;
77
using Microsoft.DotNet.Interactive.CSharp;
88
using Microsoft.DotNet.Interactive.Events;
9-
using Microsoft.DotNet.Interactive.Formatting.Tests;
109
using Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
1110
using Microsoft.DotNet.Interactive.FSharp;
1211
using Microsoft.DotNet.Interactive.Tests;

src/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Microsoft.DotNet.Interactive.Commands;
1111
using Microsoft.DotNet.Interactive.Events;
1212
using Microsoft.DotNet.Interactive.Formatting;
13-
using Microsoft.DotNet.Interactive.Formatting.Tests;
1413
using Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
1514
using Microsoft.DotNet.Interactive.Tests;
1615
using Microsoft.DotNet.Interactive.Tests.Utility;

src/Microsoft.DotNet.Interactive.Tests/LanguageKernelFormattingTests.cs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using System;
45
using System.Linq;
5-
using System.Reactive.Linq;
66
using System.Threading.Tasks;
77
using FluentAssertions;
88
using Microsoft.DotNet.Interactive.Commands;
99
using Microsoft.DotNet.Interactive.CSharp;
1010
using Microsoft.DotNet.Interactive.Events;
1111
using Microsoft.DotNet.Interactive.Formatting;
1212
using Microsoft.DotNet.Interactive.Tests.Utility;
13+
using Microsoft.DotNet.Interactive.Formatting.Tests.Utility;
1314
using Xunit;
1415
using Xunit.Abstractions;
1516
using static Microsoft.DotNet.Interactive.Formatting.Tests.Tags;
@@ -116,7 +117,7 @@ public async Task String_is_rendered_as_plain_text_via_implicit_return(
116117
[Theory]
117118
[InlineData(Language.CSharp, "{ \"hello\": 123 ", "application/json")]
118119
[InlineData(Language.CSharp, "<span class=\"test\">hello!&nbsp;</span>", "text/html")]
119-
public async Task String_is_rendered_as_specified_mime_type_DisplayAs(
120+
public async Task DisplayAs_renders_string_as_specified_mime_type(
120121
Language language,
121122
string stringValue,
122123
string mimeType)
@@ -145,7 +146,69 @@ await kernel.FindKernelByName("csharp").As<CSharpKernel>()
145146
[Theory]
146147
[InlineData(Language.CSharp)]
147148
[InlineData(Language.FSharp)]
148-
public async Task Display_helper_can_be_called_without_specifying_class_name(Language language)
149+
public async Task DisplayTable_produces_tabular_HTML_output_for_IEnumerable_T(Language language)
150+
{
151+
var kernel = CreateKernel(language, openTestingNamespaces: true);
152+
153+
var code = language switch
154+
{
155+
Language.CSharp => """
156+
new[] {
157+
new { Title = "Troll 2", Stars = 0.25 },
158+
new { Title = "The Room", Stars = 0.4 } }.DisplayTable();
159+
""",
160+
Language.FSharp => """
161+
type MovieRating = { Title: string; Stars: float }
162+
let ratings =
163+
[ { Title = "Troll 2"; Stars = 0.25 };
164+
{ Title = "The Room"; Stars = 0.4 } ]
165+
ratings.DisplayTable()
166+
"""
167+
};
168+
169+
var result = await kernel.SendAsync(new SubmitCode(code));
170+
171+
result.Events.Should().NotContainErrors();
172+
173+
result.Events
174+
.Should().ContainSingle<DisplayedValueProduced>()
175+
.Which
176+
.FormattedValues.Should().ContainSingle()
177+
.Which
178+
.Value.Should().ContainEquivalentHtmlFragments("""
179+
<table>
180+
<thead>
181+
<tr>
182+
<td><span>Title</span></td>
183+
<td><span>Stars</span></td>
184+
</tr>
185+
</thead>
186+
<tbody>
187+
<tr>
188+
<td>Troll 2</td>
189+
<td>
190+
<div class="dni-plaintext">
191+
<pre>0.25</pre>
192+
</div>
193+
</td>
194+
</tr>
195+
<tr>
196+
<td>The Room</td>
197+
<td>
198+
<div class="dni-plaintext">
199+
<pre>0.4</pre>
200+
</div>
201+
</td>
202+
</tr>
203+
</tbody>
204+
</table>
205+
""");
206+
}
207+
208+
[Theory]
209+
[InlineData(Language.CSharp)]
210+
[InlineData(Language.FSharp)]
211+
public async Task display_can_be_called_without_specifying_class_name(Language language)
149212
{
150213
var kernel = CreateKernel(language, openTestingNamespaces: true);
151214

@@ -189,7 +252,6 @@ public async Task Displayed_value_can_be_updated(Language language)
189252
v.MimeType == "text/html" &&
190253
v.Value.ToString().Contains("<b>hello</b>"));
191254

192-
193255
KernelEvents
194256
.OfType<DisplayedValueUpdated>()
195257
.SelectMany(v => v.FormattedValues)

src/Microsoft.DotNet.Interactive.Tests/Parsing/SubmissionParserTests.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,24 @@ public void Directive_parsing_errors_are_available_as_diagnostics()
134134
.Should()
135135
.ContainSingle<DirectiveNode>()
136136
.Which;
137-
node
138-
.GetDiagnostics()
137+
138+
var diagnostics = node.GetDiagnostics();
139+
140+
diagnostics
141+
.Should()
142+
.ContainSingle(d => d.Severity == CodeAnalysis.DiagnosticSeverity.Error)
143+
.Which
144+
.LinePositionSpan.End.Character
145+
.Should()
146+
.Be(node.Span.End);
147+
148+
diagnostics
139149
.Should()
140-
.ContainSingle(d => d.Severity == DiagnosticSeverity.Error)
150+
.ContainSingle(d => d.Severity == CodeAnalysis.DiagnosticSeverity.Error)
141151
.Which
142-
.Location
143-
.SourceSpan
152+
.LinePositionSpan.Start.Character
144153
.Should()
145-
.BeEquivalentTo(node.Span);
154+
.Be(node.Span.Start);
146155
}
147156

148157
[Theory]

0 commit comments

Comments
 (0)