[playground] Add diff view toggle
Quick hack to show a diff view comparing previous pass to current. Default is the output view  
Lauren Tan committed
Jan 31, 2023 at 17:37 UTC
e8650951ea652e26979319ba5eb56a7daa05f682
2 files changed
+100
-21
compiler/forget/packages/playground/components/Editor/Output.tsx
+99
-20
@@ -7,7 +7,7 @@
7
8
import generate from "@babel/generator";
9
import * as t from "@babel/types";
10
-import MonacoEditor from "@monaco-editor/react";
10
+import MonacoEditor, { DiffEditor } from "@monaco-editor/react";
11
import { type CompilerError } from "babel-plugin-react-forget";
12
import prettier from "prettier";
13
import prettierParserBabel from "prettier/parser-babel";
@@ -15,6 +15,12 @@ import { memo, useMemo, useState } from "react";
15
import { type Store } from "../../lib/stores";
16
import TabbedWindow from "../TabbedWindow";
17
import { monacoOptions } from "./monacoOptions";
18
+import {
19
+ CodeIcon,
20
+ DocumentAddIcon,
21
+ InformationCircleIcon,
22
+} from "@heroicons/react/outline";
23
+
24
const MemoizedOutput = memo(Output);
25
26
export default MemoizedOutput;
@@ -86,8 +92,17 @@ function tabify(source: string, compilerOutput: CompilerOutput) {
92
}
93
}
94
}
95
+ let lastPassOutput: string | null = null;
96
for (const [passName, text] of concattedResults) {
90
- tabs.set(passName, <TextTabContent output={text}></TextTabContent>);
97
+ tabs.set(
98
+ passName,
99
+ <TextTabContent
100
+ output={text}
101
+ diff={lastPassOutput ?? null}
102
+ showInfoPanel={true}
103
+ ></TextTabContent>
104
+ );
105
+ lastPassOutput = text;
106
}
107
// Ensure that JS and the JS source map come first
108
if (topLevelFnDecls.length > 0) {
@@ -95,7 +110,14 @@ function tabify(source: string, compilerOutput: CompilerOutput) {
110
// FunctionDeclarations
111
const ast = t.program(topLevelFnDecls);
112
const { code, sourceMapUrl } = codegen(ast, source);
98
- reorderedTabs.set("JS", <TextTabContent output={code}></TextTabContent>);
113
+ reorderedTabs.set(
114
+ "JS",
115
+ <TextTabContent
116
+ output={code}
117
+ diff={null}
118
+ showInfoPanel={false}
119
+ ></TextTabContent>
120
+ );
121
if (sourceMapUrl) {
122
reorderedTabs.set(
123
"SourceMap",
@@ -164,13 +186,16 @@ function Output({ store, compilerOutput }: Props) {
186
tabs={tabs}
187
/>
188
{compilerOutput.kind === "err" ? (
167
- <div className="flex flex-wrap w-full absolute bottom-0 bg-white grow w-screen border-y border-grey-200 transition-all ease-in">
189
+ <div
190
+ className="flex flex-wrap absolute bottom-0 bg-white grow border-y border-grey-200 transition-all ease-in"
191
+ style={{ width: "calc(100vw - 650px)" }}
192
+ >
193
<div className="w-full p-4 basis-full border-b">
194
<h2>COMPILER ERRORS</h2>
195
</div>
196
<pre
172
- className="p-4 basis-full text-red-600"
173
- style={{ maxHeight: "20vh", overflowY: "scroll" }}
197
+ className="p-4 basis-full text-red-600 overflow-x-hidden"
198
+ style={{ maxHeight: "20vh" }}
199
>
200
{compilerOutput.error.toString()}
201
</pre>
@@ -180,24 +205,78 @@ function Output({ store, compilerOutput }: Props) {
205
);
206
}
207
183
-function TextTabContent({ output }: { output: string }) {
208
+function TextTabContent({
209
+ output,
210
+ diff,
211
+ showInfoPanel,
212
+}: {
213
+ output: string;
214
+ diff: string | null;
215
+ showInfoPanel: boolean;
216
+}) {
217
+ const [value, setValue] = useState(output);
218
return (
219
// Restrict MonacoEditor's height, since the config autoLayout:true
220
// will grow the editor to fit within parent element
221
<div className="w-full h-monaco_small sm:h-monaco">
188
- <MonacoEditor
189
- defaultLanguage="javascript"
190
- value={output}
191
- options={{
192
- ...monacoOptions,
193
- readOnly: true,
194
- lineNumbers: "off",
195
- glyphMargin: false,
196
- // Undocumented see https://github.com/Microsoft/vscode/issues/30795#issuecomment-410998882
197
- lineDecorationsWidth: 0,
198
- lineNumbersMinChars: 0,
199
- }}
200
- />
222
+ {showInfoPanel ? (
223
+ <div className="flex items-center gap-1 bg-amber-50 p-2">
224
+ {diff != null && output !== diff ? (
225
+ <button
226
+ className="flex items-center gap-1 transition-colors duration-150 ease-in text-secondary hover:text-link"
227
+ onClick={() =>
228
+ value === output ? setValue(diff) : setValue(output)
229
+ }
230
+ >
231
+ {value === output ? (
232
+ <>
233
+ <DocumentAddIcon className="w-5 h-5" /> Show Diff
234
+ </>
235
+ ) : (
236
+ <>
237
+ <CodeIcon className="w-5 h-5" /> Show Output
238
+ </>
239
+ )}
240
+ </button>
241
+ ) : (
242
+ <>
243
+ <span className="flex items-center gap-1">
244
+ <InformationCircleIcon className="w-5 h-5" /> No changes from
245
+ previous pass
246
+ </span>
247
+ </>
248
+ )}
249
+ </div>
250
+ ) : null}
251
+ {diff != null && value !== output ? (
252
+ <DiffEditor
253
+ original={diff}
254
+ modified={output}
255
+ options={{
256
+ ...monacoOptions,
257
+ readOnly: true,
258
+ lineNumbers: "off",
259
+ glyphMargin: false,
260
+ // Undocumented see https://github.com/Microsoft/vscode/issues/30795#issuecomment-410998882
261
+ lineDecorationsWidth: 0,
262
+ lineNumbersMinChars: 0,
263
+ }}
264
+ />
265
+ ) : (
266
+ <MonacoEditor
267
+ defaultLanguage="javascript"
268
+ value={output}
269
+ options={{
270
+ ...monacoOptions,
271
+ readOnly: true,
272
+ lineNumbers: "off",
273
+ glyphMargin: false,
274
+ // Undocumented see https://github.com/Microsoft/vscode/issues/30795#issuecomment-410998882
275
+ lineDecorationsWidth: 0,
276
+ lineNumbersMinChars: 0,
277
+ }}
278
+ />
279
+ )}
280
</div>
281
);
282
}
compiler/forget/packages/playground/components/TabbedWindow.tsx
+1
-1
@@ -68,7 +68,7 @@ function TabbedWindowItem({
68
return (
69
<div key={name} className="flex flex-row">
70
{isShow ? (
71
- <div style={{ minWidth: 550, overflow: "hidden" }}>
71
+ <div className="border-r" style={{ minWidth: 550, overflow: "hidden" }}>
72
<h2
73
onClick={toggleTabs}
74
className="p-4 duration-150 ease-in border-b cursor-pointer border-grey-200 text-secondary hover:text-link"