diff --git a/web/e2e/smoke.spec.ts b/web/e2e/smoke.spec.ts index 7979ae5..8a79f09 100644 --- a/web/e2e/smoke.spec.ts +++ b/web/e2e/smoke.spec.ts @@ -39,6 +39,12 @@ test.describe("Compiler Explorer smoke", () => { await expect(page.getByText(/cycle 0 \/ \d+/)).toBeVisible(); }); + test("choosing an example replaces the editor's source", async ({ page }) => { + await page.goto("/app"); + await page.getByLabel("example").selectOption("mlp_gpu"); + await expect(page.getByRole("textbox", { name: "source" })).toContainText("H = relu(X @ W1 + b1)"); + }); + test("a rejected program is shown as an error, not a crash", async ({ page }) => { await page.goto("/app"); await page.getByLabel("source").fill("input A : i8[2, 2]\nC = A @ A +\noutput C\n"); diff --git a/web/package.json b/web/package.json index ddc3106..7762f97 100644 --- a/web/package.json +++ b/web/package.json @@ -16,7 +16,9 @@ }, "dependencies": { "@astrojs/react": "^4.0.0", + "@codemirror/state": "^6.7.6", "astro": "^5.0.0", + "codemirror": "^6.0.2", "framer-motion": "^12.43.0", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index bad0aad..742244d 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -11,9 +11,15 @@ importers: '@astrojs/react': specifier: ^4.0.0 version: 4.4.2(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(supports-color@7.2.0)(yaml@2.9.1) + '@codemirror/state': + specifier: ^6.7.6 + version: 6.7.6 astro: specifier: ^5.0.0 version: 5.18.2(rollup@4.65.0)(supports-color@7.2.0)(typescript@5.9.3)(yaml@2.9.1) + codemirror: + specifier: ^6.0.2 + version: 6.0.2 framer-motion: specifier: ^12.43.0 version: 12.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -192,6 +198,30 @@ packages: resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} engines: {node: '>=18'} + '@codemirror/autocomplete@6.20.4': + resolution: {integrity: sha512-yF8RhOf2SXlg00+qtupzLhrglcas61boqaONiNcbPIebHCpJocpqTBA6dyrtUrQO47hqyTdeob/3XnYilT7TaQ==} + + '@codemirror/commands@6.11.1': + resolution: {integrity: sha512-O/4hG3SC1YwcmQ0d2UVNDs+AsaNWd1iHVxbTeEBuqH+6bExAiPK3iS/BvpY6rZGURALv4ZD3sIgcCmRvw3ehBg==} + + '@codemirror/language@6.13.1': + resolution: {integrity: sha512-zfvU2r3TyylQLMj/te+5CnQ0rSqZi8B1oTCBbQkagcLW4Xc6imab6qN+pEJhsuNOLaJqiRyBXp9UhWA1DhVvDw==} + + '@codemirror/lint@6.9.7': + resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} + + '@codemirror/search@6.7.2': + resolution: {integrity: sha512-gUYkYhT2+n/+VGZ+8EzE5WFkYZUZYm1VOKDudIsNqh42uRVQJ0a6Yss9sdKT3MeOYfuL1N6AZA57oza0Oyr0LA==} + + '@codemirror/state@6.7.6': + resolution: {integrity: sha512-kAz+AncRtKuIknedxT1bq4XwXv4UowhbkHU1myPrtVb/jZtImWuV5BXzv5vK6i3kYACsdiZiQKFQQ5Mq7elW8w==} + + '@codemirror/streamparser@6.0.0': + resolution: {integrity: sha512-JTFPF6xrfjt0mnfGPgzcLiMwYmvIyNaoizp8BYzv8FE8KrT6GBGDZ190rtt+O7Wke3gG/MFHyiY9YGNeimof4w==} + + '@codemirror/view@6.43.15': + resolution: {integrity: sha512-HHsfpqFeHyXLs983pSRe38Xajs0vFWZQ2BuX0m7Ki8w3jZ5iD8cuR3lBz2/5/X53Dhf32SBHKh6rtSTB6tKeGw==} + '@emmetio/abbreviation@2.3.3': resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} @@ -899,6 +929,18 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@lezer/common@1.5.4': + resolution: {integrity: sha512-xt3Q4z64xM+xhg4M7NXqw1N//1O74bUFo5kz6fwMeC4qwxSuRdwkYSmjcqCEEKYkNw5e67f2hcNqBoNERAEU0w==} + + '@lezer/highlight@1.2.5': + resolution: {integrity: sha512-O1GMVKgtf5YspFaRzpmqkVgMtIk2HG9uMAbH6wdAIdNh3TVzCsch/+cRi+6l2//UGDKe6NB9BW3cvuR5ezMQ0w==} + + '@lezer/lr@1.4.11': + resolution: {integrity: sha512-UwgZcl1R66H2hDzBrA7kWyYmX6s8p5TQ+e/t7CuvgCtBEPxbEPaHYHu+pJBvTvDotEJpuQkJjbXuHiw5Cixxgw==} + + '@marijn/find-cluster-break@1.0.4': + resolution: {integrity: sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} engines: {node: ^22.20 || ^24.12 || >=25} @@ -1455,6 +1497,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + codemirror@6.0.2: + resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1485,6 +1530,9 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2452,6 +2500,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + style-mod@4.1.4: + resolution: {integrity: sha512-XXWIQt633/EpAFx8aZDOTjBzrCaGmhvEQlQo6MVPfa2OzO2cWo+4hV9h+6UkHYlXGfy+ODXKUdP7Pthmcu5ATw==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2885,6 +2936,9 @@ packages: vscode-uri@3.2.0: resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -3218,6 +3272,55 @@ snapshots: dependencies: fontkitten: 1.0.3 + '@codemirror/autocomplete@6.20.4': + dependencies: + '@codemirror/language': 6.13.1 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.4 + + '@codemirror/commands@6.11.1': + dependencies: + '@codemirror/language': 6.13.1 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.4 + + '@codemirror/language@6.13.1': + dependencies: + '@codemirror/state': 6.7.6 + '@codemirror/streamparser': 6.0.0 + '@codemirror/view': 6.43.15 + '@lezer/common': 1.5.4 + '@lezer/highlight': 1.2.5 + '@lezer/lr': 1.4.11 + style-mod: 4.1.4 + + '@codemirror/lint@6.9.7': + dependencies: + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + crelt: 1.0.7 + + '@codemirror/search@6.7.2': + dependencies: + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + crelt: 1.0.7 + + '@codemirror/state@6.7.6': + dependencies: + '@marijn/find-cluster-break': 1.0.4 + + '@codemirror/streamparser@6.0.0': {} + + '@codemirror/view@6.43.15': + dependencies: + '@codemirror/state': 6.7.6 + crelt: 1.0.7 + style-mod: 4.1.4 + w3c-keyname: 2.2.8 + '@emmetio/abbreviation@2.3.3': dependencies: '@emmetio/scanner': 1.0.4 @@ -3657,6 +3760,18 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 + '@lezer/common@1.5.4': {} + + '@lezer/highlight@1.2.5': + dependencies: + '@lezer/common': 1.5.4 + + '@lezer/lr@1.4.11': + dependencies: + '@lezer/common': 1.5.4 + + '@marijn/find-cluster-break@1.0.4': {} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true @@ -4300,6 +4415,16 @@ snapshots: clsx@2.1.1: {} + codemirror@6.0.2: + dependencies: + '@codemirror/autocomplete': 6.20.4 + '@codemirror/commands': 6.11.1 + '@codemirror/language': 6.13.1 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.2 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.15 + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4320,6 +4445,8 @@ snapshots: cookie@1.1.1: {} + crelt@1.0.7: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -5617,6 +5744,8 @@ snapshots: strip-json-comments@3.1.1: {} + style-mod@4.1.4: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -5974,6 +6103,8 @@ snapshots: vscode-uri@3.2.0: {} + w3c-keyname@2.2.8: {} + web-namespaces@2.0.1: {} which-pm-runs@1.1.0: {} diff --git a/web/src/components/Explorer.tsx b/web/src/components/Explorer.tsx index c82779e..0270e67 100644 --- a/web/src/components/Explorer.tsx +++ b/web/src/components/Explorer.tsx @@ -3,6 +3,7 @@ import { analyze } from "../lib/compiler"; import { EXAMPLES } from "../lib/examples.generated"; import { runTpu, type TpuRun } from "../lib/tpu"; import TpuSchedule from "./TpuSchedule"; +import SourceEditor from "./SourceEditor"; import { tpuExact } from "../lib/verify"; import type { Analysis, GpuRun } from "../lib/types"; @@ -106,13 +107,7 @@ export default function Explorer() {