Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Web: UI refresh, new representation selector/renderers #402

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Agents/Xamarin.Interactive/Logging/LogEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

using System;

using Newtonsoft.Json;

namespace Xamarin.Interactive.Logging
{
[Serializable]
[JsonObject]
public struct LogEntry
{
internal string OwnerId { get; }
Expand All @@ -23,6 +25,7 @@ public struct LogEntry
public string CallerFilePath { get; }
public int CallerLineNumber { get; }

[JsonConstructor]
internal LogEntry (
string ownerId,
DateTime time,
Expand Down
5 changes: 5 additions & 0 deletions Agents/Xamarin.Interactive/Protocol/AgentFeaturesRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ namespace Xamarin.Interactive.Protocol
[JsonObject]
sealed class AgentFeaturesRequest : MainThreadRequest<AgentFeatures>
{
[JsonConstructor]
public AgentFeaturesRequest ()
{
}

protected override Task<AgentFeatures> HandleAsync (Agent agent)
=> Task.FromResult(new AgentFeatures (agent
.ViewHierarchyHandlerManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
using System;
using System.Threading.Tasks;

using Newtonsoft.Json;

using Xamarin.Interactive.CodeAnalysis;
using Xamarin.Interactive.Core;

namespace Xamarin.Interactive.Protocol
{
[Serializable]
[JsonObject]
sealed class EvaluationContextInitializeRequest : MainThreadRequest<TargetCompilationConfiguration>
{
public TargetCompilationConfiguration Configuration { get; }

[JsonConstructor]
public EvaluationContextInitializeRequest (TargetCompilationConfiguration configuration)
=> Configuration = configuration
?? throw new ArgumentNullException (nameof (configuration));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,14 @@ public InteractiveJsonContractResolver ()
};
}

static CustomAttributeData GetCustomAttributeNamed (MemberInfo member, string name)
=> member.CustomAttributes.FirstOrDefault (a => a.AttributeType.Name == name);

static ConstructorInfo GetAttributeConstructor (Type objectType)
=> objectType
.GetConstructors (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where (c => GetCustomAttributeNamed (c, "JsonConstructorAttribute") != null)
.SingleOrDefault ();

#if EXTERNAL_INTERACTIVE_JSON_SERIALIZER_SETTINGS

protected override JsonObjectContract CreateObjectContract (Type objectType)
{
var contract = base.CreateObjectContract (objectType);

if (contract.OverrideCreator == null && !objectType.IsAbstract && !objectType.IsInterface) {
var ctor = GetAttributeConstructor (objectType);
var ctor = InteractiveJsonBinder.GetJsonConstructor (objectType);
if (ctor != null) {
contract.OverrideCreator = args => ctor.Invoke (args);
contract.CreatorParameters.Clear ();
Expand All @@ -89,6 +80,9 @@ protected override JsonProperty CreateProperty (

sealed class InteractiveJsonBinder : ISerializationBinder
{
readonly Dictionary<(string assemblyName, string typeName), Type> bindToTypeCache
= new Dictionary<(string, string), Type> ();

public void BindToName (Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
Expand All @@ -100,7 +94,44 @@ public void BindToName (Type serializedType, out string assemblyName, out string
}

public Type BindToType (string assemblyName, string typeName)
=> RepresentedType.GetType (typeName);
{
// Bind only to types explicitly marked with [JsonObject].
// These attributed types imply they are safe for deserialization.

if (bindToTypeCache.TryGetValue ((assemblyName, typeName), out var type))
return type;

type = RepresentedType.GetType (typeName);
if (type == null)
return null;

foreach (var customAttribute in type.CustomAttributes) {
switch (customAttribute.AttributeType.FullName) {
case "Xamarin.Interactive.Json.JsonObjectAttribute":
case "Newtonsoft.Json.JsonObjectAttribute":
if (GetJsonConstructor (type) != null) {
bindToTypeCache [(assemblyName, typeName)] = type;
return type;
}

throw new InvalidOperationException (
$"Not binding to '{typeName}, {assemblyName}'. " +
"It is marked [JsonObject] but does not have a [JsonConstructor].");
}
}

throw new InvalidOperationException (
$"Not binding to '{typeName}, {assemblyName}'. It is not marked [JsonObject].");
}

static CustomAttributeData GetCustomAttributeNamed (MemberInfo member, string name)
=> member.CustomAttributes.FirstOrDefault (a => a.AttributeType.Name == name);

public static ConstructorInfo GetJsonConstructor (Type objectType)
=> objectType
.GetConstructors (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where (c => GetCustomAttributeNamed (c, "JsonConstructorAttribute") != null)
.SingleOrDefault ();
}

public
Expand Down
12 changes: 12 additions & 0 deletions Clients/Xamarin.Interactive.Client.Mac.SimChecker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
using Xamarin.Interactive.Logging;
using Xamarin.Interactive.MTouch;

// Define these for LogEntry since we do not actually need Newtonsoft.Json in simchecker.
namespace Newtonsoft.Json
{
sealed class JsonObjectAttribute : Attribute
{
}

sealed class JsonConstructorAttribute : Attribute
{
}
}

namespace Xamarin.Interactive.Mac.SimChecker
{
public class Program
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@import '../css/theme.scss';

button.ActionButton {
&.Small {
$hitBounds: 4px;
$visibleSize: 16px;
$size: 2 * $hitBounds + $visibleSize;

width: $size;
height: $size;
padding: $hitBounds;
margin-bottom: -$hitBounds;
margin-right: -$hitBounds;
}

cursor: pointer;
color: $themePrimary;
background: transparent;
border: none;
margin: 0;
outline: none;

&:active {
outline: 1px dashed rgba($themePrimary, 0.4);
}

svg {
fill: currentColor;
stroke: currentColor;
width: 100%;
height: 100%;

@keyframes spin-cw {
100% { transform: rotate(360deg); }
}

@keyframes spin-ccw {
100% { transform: rotate(-360deg); }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import * as React from 'react'

import './ActionButton.scss'

export class ActionButton extends React.PureComponent<{
iconName: string
title: string
onClick?: () => void
}> {
render() {
return (
<button
className="ActionButton Small"
title={this.props.title}
onClick={this.props.onClick}>
<svg className={`ActionButton-${this.props.iconName}`} viewBox="0 0 16 16">
{this.renderIcon()}
</svg>
</button>
)
}

private renderIcon() {
switch (this.props.iconName) {
case "CodeCell-Running":
return (
<g>
<g stroke="none" className="CodeCell-Running-Group">
<path className="CodeCell-Running-Ring1" d="M8,0 C3.581722,0 0,3.581722 0,8 C0,12.418278 3.581722,16 8,16 C12.418278,16 16,12.418278 16,8 L15,8 C15,11.8659932 11.8659932,15 8,15 C4.13400675,15 1,11.8659932 1,8 C1,4.13400675 4.13400675,1 8,1 L8,0 Z"/>
<path className="CodeCell-Running-Ring2" d="M2,8 C2,4.6862915 4.6862915,2 8,2 C11.3137085,2 14,4.6862915 14,8 C14,11.3137085 11.3137085,14 8,14 L8,13 C10.7614237,13 13,10.7614237 13,8 C13,5.23857625 10.7614237,3 8,3 C5.23857625,3 3,5.23857625 3,8 L2,8 Z"/>
<path className="CodeCell-Running-Ring3" d="M8,4 C5.790861,4 4,5.790861 4,8 C4,10.209139 5.790861,12 8,12 C10.209139,12 12,10.209139 12,8 L11,8 C11,9.65685425 9.65685425,11 8,11 C6.34314575,11 5,9.65685425 5,8 C5,6.34314575 6.34314575,5 8,5 L8,4 Z"/>
</g>
<g stroke="none" className="CodeCell-Running-Cancel-Group">
<path d="M8,6.58578644 L10.1245748,4.46121168 C10.5133017,4.07248475 11.142287,4.07121914 11.5355339,4.46446609 C11.9260582,4.85499039 11.9204373,5.49377626 11.5387883,5.87542525 L9.41421356,8 L11.5387883,10.1245748 C11.9275152,10.5133017 11.9287809,11.142287 11.5355339,11.5355339 C11.1450096,11.9260582 10.5062237,11.9204373 10.1245748,11.5387883 L8,9.41421356 L5.87542525,11.5387883 C5.48669832,11.9275152 4.85771305,11.9287809 4.46446609,11.5355339 C4.0739418,11.1450096 4.0795627,10.5062237 4.46121168,10.1245748 L6.58578644,8 L4.46121168,5.87542525 C4.07248475,5.48669832 4.07121914,4.85771305 4.46446609,4.46446609 C4.85499039,4.0739418 5.49377626,4.0795627 5.87542525,4.46121168 L8,6.58578644 Z M8,16 C3.581722,16 0,12.418278 0,8 C0,3.581722 3.581722,0 8,0 C12.418278,0 16,3.581722 16,8 C16,12.418278 12.418278,16 8,16 Z M8,15 C11.8659932,15 15,11.8659932 15,8 C15,4.13400675 11.8659932,1 8,1 C4.13400675,1 1,4.13400675 1,8 C1,11.8659932 4.13400675,15 8,15 Z"></path>
</g>
</g>
)
case "CodeCell-Run":
return (
<g stroke="none">
<path d="M8,16 C3.581722,16 0,12.418278 0,8 C0,3.581722 3.581722,0 8,0 C12.418278,0 16,3.581722 16,8 C16,12.418278 12.418278,16 8,16 Z M8,15 C11.8659932,15 15,11.8659932 15,8 C15,4.13400675 11.8659932,1 8,1 C4.13400675,1 1,4.13400675 1,8 C1,11.8659932 4.13400675,15 8,15 Z M11,8 L6,12 L6,4 L11,8 Z"/>
</g>
)
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import { MonacoCellEditor, MonacoCellEditorProps } from './MonacoCellEditor'
import { ContentBlock } from 'draft-js';
import { EditorMessage } from '../utils/EditorMessages'
import { WorkbookShellContext } from './WorkbookShell'
import { ResultRendererRepresentation } from '../rendering';
import { ResultRendererRegistry } from '../ResultRendererRegistry'
import { RepresentationRegistry } from '../rendering'
import { MonacoCellMapper } from '../utils/MonacoUtils'

import {
Expand All @@ -37,7 +36,7 @@ import {
interface CodeCellProps extends CodeCellViewProps {
blockProps: {
shellContext: WorkbookShellContext
rendererRegistry: ResultRendererRegistry
representationRegistry: RepresentationRegistry
sendEditorMessage: (message: EditorMessage) => void
cellMapper: MonacoCellMapper
codeCellId: string
Expand Down Expand Up @@ -100,8 +99,8 @@ export class CodeCell extends CodeCellView<CodeCellProps, CodeCellState> {
}
}

protected getRendererRegistry(): ResultRendererRegistry {
return this.props.blockProps.rendererRegistry
protected getRepresentationRegistry(): RepresentationRegistry {
return this.props.blockProps.representationRegistry
}

protected sendEditorMessage(message: EditorMessage) {
Expand Down
Loading