Add basic CompletionViewer

This commit is contained in:
2020-09-28 12:42:48 +05:30
parent 73dcd7851c
commit dae87ba6cc
12 changed files with 218 additions and 33 deletions
+12 -2
View File
@@ -1,8 +1,10 @@
import React, { useState, useLayoutEffect } from "react";
import React, { useState } from "react";
import { SourceViewer } from "./components/SourceViewer";
import { CompletionViewer } from "./components/CompletionViewer";
import { completionMapping } from "./logic/completionMapping";
import { sourceMapping } from "./logic/sourceMapping";
import { runEngine } from "./logic/runEngine";
import "./tailwind.output.css";
@@ -19,12 +21,20 @@ function App() {
// }, [inputCode]);
return (
<div>
<div className="flex flex-col justify-between md:flex-row">
<div className="flex-1 max-w-half">
<SourceViewer code={inputCode} onChangeCode={setInputCode} />
</div>
<div className="flex-1 max-w-half">
{/* Separator */}
{/* <div className="w-2 mx-1 bg-gray-800"></div> */}
<CompletionViewer
code={inputCode}
completionDetails={completionMapping.completionDetails}
sourceMapping={sourceMapping}
/>
</div>
</div>
);
}
@@ -0,0 +1,84 @@
import React from "react";
import { ICompletionDetail } from "../../logic/completionMapping";
import { TSourceMapping } from "../../logic/sourceMapping";
import { CompletionTypes } from "../../types/engine262-stubs";
import { InlineResultViewer } from "../InlineResultViewer";
import { CompletionIcon } from "./CompletionIcon";
function getCompletionClassname(inputCompletion: ICompletionDetail) {
const typeToClassnameMapping: { [key in CompletionTypes]: string } = {
[CompletionTypes.Normal]: "bg-gray-300",
[CompletionTypes.Return]: "bg-green-200",
[CompletionTypes.Continue]: "bg-yellow-100",
[CompletionTypes.Break]: "bg-yellow-300",
[CompletionTypes.Throw]: "bg-red-300",
};
return typeToClassnameMapping[inputCompletion.completionType];
}
function getCodeTextFromCompletion(
code: string,
completion: ICompletionDetail
) {
return code.substring(completion.start, completion.end);
}
export interface ICompletionCardProps {
completionDetail: ICompletionDetail;
code: string;
}
export function CompletionCard(props: ICompletionCardProps) {
const { completionDetail, code } = props;
// TODO: have diff version to be shown as tooltip over source code
return (
<div
className={`px-4 py-1 my-1 rounded-md ${getCompletionClassname(
completionDetail
)}`}
>
<div className="flex items-center my-1">
<div className="flex-initial flex-shrink-0">
<CompletionIcon completionDetail={completionDetail} />
</div>
<div className="flex-initial min-w-0">
<InlineResultViewer
className="px-1 rounded"
code={completionDetail.completionValueString || "// No value"}
/>
</div>
</div>
<div className="">
<div className="my-1">From source </div>
<InlineResultViewer
className="px-1 py-1 my-1 rounded md:w-fit-content"
code={getCodeTextFromCompletion(code, completionDetail)}
/>
</div>
<div className="">
<div className="my-1">Full completion record </div>
<table className="border border-gray-800">
<tr className="border-b border-gray-800">
<td className="p-1 border-r border-gray-800">[[Type]]</td>
<td className="px-2 py-1">{completionDetail.completionType}</td>
</tr>
<tr className="border-b border-gray-800">
<td className="p-1 border-r border-gray-800">[[Value]]</td>
<td className="px-2 py-1">
{completionDetail.completionValueString}
</td>
</tr>
<tr className="border-b border-gray-800">
<td className="p-1 border-r border-gray-800">[[Target]]</td>
<td className="px-2 py-1">
{completionDetail.completionTargetString}
</td>
</tr>
</table>
</div>
</div>
);
}
@@ -0,0 +1,29 @@
import React from "react";
import { ICompletionDetail } from "../../logic/completionMapping";
import { CompletionTypes } from "../../types/engine262-stubs";
export interface ICompletionIconProps {
completionDetail: ICompletionDetail;
}
export const typeToLetterMapping: {
[key in CompletionTypes]: string;
} = {
[CompletionTypes.Normal]: "N",
[CompletionTypes.Return]: "R",
[CompletionTypes.Continue]: "C",
[CompletionTypes.Break]: "B",
[CompletionTypes.Throw]: "T",
};
export function CompletionIcon(props: ICompletionIconProps) {
const { completionDetail } = props;
const tmpLetter = typeToLetterMapping[completionDetail.completionType];
return (
// Icon container
<div className="flex items-center justify-center w-8 h-8 mr-2 text-base font-semibold align-middle bg-white rounded-circle ">
<div>{tmpLetter}</div>
</div>
);
}
+3
View File
@@ -0,0 +1,3 @@
import { CompletionCard } from "./CompletionCard";
export { CompletionCard };
@@ -1,7 +1,32 @@
import React from "react";
import { ICompletionDetail } from "../../logic/completionMapping";
import { TSourceMapping } from "../../logic/sourceMapping";
import { CompletionCard } from "../CompletionCard";
export function CompletionViewer(props: {
code: string;
completionDetails: ICompletionDetail[];
sourceMapping: TSourceMapping;
}) {
return null;
const { code, completionDetails } = props;
// function renderCompletionResult(inputCompletion: ICompletionDetail) {}
return (
<div className="">
{/* Title for completion section */}
<div className="px-4 py-1 bg-gray-200 ">Completion Records</div>
{/* Completion list */}
<div className="ml-1 mr-1">
{completionDetails.map((tmpCompletion) => (
// Card for each completion record
<CompletionCard
completionDetail={tmpCompletion}
code={code}
></CompletionCard>
))}
</div>
</div>
);
}
@@ -0,0 +1,29 @@
import React from "react";
import Highlight, { defaultProps } from "prism-react-renderer";
interface IInlineResultViewerProps {
code: string;
className: string;
}
export function InlineResultViewer(props: IInlineResultViewerProps) {
const { code, className: classNameFromProps } = props;
return (
<Highlight {...defaultProps} code={code} language="javascript">
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre
className={`${className} ${classNameFromProps} overflow-auto`}
style={style}
>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
);
}
@@ -0,0 +1,3 @@
import { InlineResultViewer } from "./InlineResultViewer";
export { InlineResultViewer };
+6 -3
View File
@@ -3,8 +3,6 @@ import Highlight, { defaultProps } from "prism-react-renderer";
import { sourceMapping } from "../../logic/sourceMapping";
import "./SourceViewer.css";
interface ISourceViewerProps {
code: string;
onChangeCode(newCode: string): void;
@@ -13,12 +11,16 @@ interface ISourceViewerProps {
export function SourceViewer(props: ISourceViewerProps) {
const { code } = props;
return (
<div>
{/* Title of code section */}
<div className="px-4 py-1 bg-gray-200 ">Code</div>
{/* Code viewer */}
<Highlight {...defaultProps} code={code} language="jsx">
{({ className, style, tokens, getLineProps, getTokenProps }) => (
// eslint-disable-next-line no-sequences
sourceMapping.reset(),
(
<pre className={className} style={style}>
<pre className={`${className} px-4 py-2 overflow-auto`} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map(function (token, key) {
@@ -34,5 +36,6 @@ export function SourceViewer(props: ISourceViewerProps) {
)
)}
</Highlight>
</div>
);
}
-1
View File
@@ -5,7 +5,6 @@ body {
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 24px;
}
code {
+2 -2
View File
@@ -1,12 +1,12 @@
import { Token } from "../types/prism-types";
interface TMappingELement {
export interface TMappingELement {
start: number;
end: number;
ref: { current: HTMLElement | null };
}
interface TSourceMapping {
export interface TSourceMapping {
mappingArray: Array<TMappingELement>;
lastEnd: number;
registerToken(t: Token): (ele: HTMLElement | null) => void;