diff --git a/package-lock.json b/package-lock.json index d1fa9db6..718a01b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9193,6 +9193,7 @@ } }, "packages/serial": { + "name": "@strudel.cycles/serial", "version": "0.0.6", "license": "GPL-3.0-or-later" }, diff --git a/repl/package-lock.json b/repl/package-lock.json index e58864b3..fbc6293a 100644 --- a/repl/package-lock.json +++ b/repl/package-lock.json @@ -8,15 +8,17 @@ "name": "@strudel.cycles/repl", "version": "0.1.0", "dependencies": { + "@codemirror/lang-javascript": "^0.19.0", "@testing-library/jest-dom": "^5.16.3", "@testing-library/react": "^12.1.4", "@testing-library/user-event": "^13.5.0", - "codemirror": "^5.65.2", + "codemirror6-themes": "^0.1.2", "events": "^3.3.0", "gh-pages": "^3.2.3", "react": "^17.0.2", - "react-codemirror2": "^7.2.1", + "react-codemirror6": "^1.1.0", "react-dom": "^17.0.2", + "react-hook-inview": "^4.4.1", "react-scripts": "5.0.0", "tone": "^14.7.77", "web-vitals": "^2.1.4" @@ -28,6 +30,7 @@ "autoprefixer": "^10.4.4", "parcel": "^2.3.1", "postcss": "^8.4.12", + "process": "^0.11.10", "serve": "^13.0.2", "tailwindcss": "^3.0.23" } @@ -1857,6 +1860,223 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "node_modules/@codemirror/autocomplete": { + "version": "0.19.15", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.19.15.tgz", + "integrity": "sha512-GQWzvvuXxNUyaEk+5gawbAD8s51/v2Chb++nx0e2eGWrphWk42isBtzOMdc3DxrxrZtPZ55q2ldNp+6G8KJLIQ==", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/state": "^0.19.4", + "@codemirror/text": "^0.19.2", + "@codemirror/tooltip": "^0.19.12", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@codemirror/closebrackets": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/closebrackets/-/closebrackets-0.19.2.tgz", + "integrity": "sha512-ClMPzPcPP0eQiDcVjtVPl6OLxgdtZSYDazsvT0AKl70V1OJva0eHgl4/6kCW3RZ0pb2n34i9nJz4eXCmK+TYDA==", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.2", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.44" + } + }, + "node_modules/@codemirror/commands": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.19.8.tgz", + "integrity": "sha512-65LIMSGUGGpY3oH6mzV46YWRrgao6NmfJ+AuC7jNz3K5NPnH6GCV1H5I6SwOFyVbkiygGyd0EFwrWqywTBD1aw==", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/matchbrackets": "^0.19.0", + "@codemirror/state": "^0.19.2", + "@codemirror/text": "^0.19.6", + "@codemirror/view": "^0.19.22", + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@codemirror/comment": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@codemirror/comment/-/comment-0.19.1.tgz", + "integrity": "sha512-uGKteBuVWAC6fW+Yt8u27DOnXMT/xV4Ekk2Z5mRsiADCZDqYvryrJd6PLL5+8t64BVyocwQwNfz1UswYS2CtFQ==", + "dependencies": { + "@codemirror/state": "^0.19.9", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "node_modules/@codemirror/fold": { + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/fold/-/fold-0.19.4.tgz", + "integrity": "sha512-0SNSkRSOa6gymD6GauHa3sxiysjPhUC0SRVyTlvL52o0gz9GHdc8kNqNQskm3fBtGGOiSriGwF/kAsajRiGhVw==", + "dependencies": { + "@codemirror/gutter": "^0.19.0", + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.22" + } + }, + "node_modules/@codemirror/gutter": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.19.9.tgz", + "integrity": "sha512-PFrtmilahin1g6uL27aG5tM/rqR9DZzZYZsIrCXA5Uc2OFTFqx4owuhoU9hqfYxHp5ovfvBwQ+txFzqS4vog6Q==", + "dependencies": { + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.23" + } + }, + "node_modules/@codemirror/highlight": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.19.8.tgz", + "integrity": "sha512-v/lzuHjrYR8MN2mEJcUD6fHSTXXli9C1XGYpr+ElV6fLBIUhMTNKR3qThp611xuWfXfwDxeL7ppcbkM/MzPV3A==", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.3", + "@codemirror/view": "^0.19.39", + "@lezer/common": "^0.15.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/history": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/history/-/history-0.19.2.tgz", + "integrity": "sha512-unhP4t3N2smzmHoo/Yio6ueWi+il8gm9VKrvi6wlcdGH5fOfVDNkmjHQ495SiR+EdOG35+3iNebSPYww0vN7ow==", + "dependencies": { + "@codemirror/state": "^0.19.2", + "@codemirror/view": "^0.19.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-0.19.7.tgz", + "integrity": "sha512-DL9f3JLqOEHH9cIwEqqjnP5bkjdVXeECksLtV+/MbPm+l4H+AG+PkwZaJQ2oR1GfPZKh8MVSIE94aGWNkJP8WQ==", + "dependencies": { + "@codemirror/autocomplete": "^0.19.0", + "@codemirror/highlight": "^0.19.7", + "@codemirror/language": "^0.19.0", + "@codemirror/lint": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/javascript": "^0.15.1" + } + }, + "node_modules/@codemirror/language": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.19.10.tgz", + "integrity": "sha512-yA0DZ3RYn2CqAAGW62VrU8c4YxscMQn45y/I9sjBlqB1e2OTQLg4CCkMBuMSLXk4xaqjlsgazeOQWaJQOKfV8Q==", + "dependencies": { + "@codemirror/state": "^0.19.0", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.5", + "@lezer/lr": "^0.15.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.19.6.tgz", + "integrity": "sha512-Pbw1Y5kHVs2J+itQ0uez3dI4qY9ApYVap7eNfV81x1/3/BXgBkKfadaw0gqJ4h4FDG7OnJwb0VbPsjJQllHjaA==", + "dependencies": { + "@codemirror/gutter": "^0.19.4", + "@codemirror/panel": "^0.19.0", + "@codemirror/rangeset": "^0.19.1", + "@codemirror/state": "^0.19.4", + "@codemirror/tooltip": "^0.19.16", + "@codemirror/view": "^0.19.22", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/matchbrackets": { + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/matchbrackets/-/matchbrackets-0.19.4.tgz", + "integrity": "sha512-VFkaOKPNudAA5sGP1zikRHCEKU0hjYmkKpr04pybUpQvfTvNJXlReCyP0rvH/1iEwAGPL990ZTT+QrLdu4MeEA==", + "dependencies": { + "@codemirror/language": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@codemirror/panel": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@codemirror/panel/-/panel-0.19.1.tgz", + "integrity": "sha512-sYeOCMA3KRYxZYJYn5PNlt9yNsjy3zTNTrbYSfVgjgL9QomIVgOJWPO5hZ2sTN8lufO6lw0vTBsIPL9MSidmBg==", + "dependencies": { + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "node_modules/@codemirror/rangeset": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", + "integrity": "sha512-V8YUuOvK+ew87Xem+71nKcqu1SXd5QROMRLMS/ljT5/3MCxtgrRie1Cvild0G/Z2f1fpWxzX78V0U4jjXBorBQ==", + "dependencies": { + "@codemirror/state": "^0.19.0" + } + }, + "node_modules/@codemirror/rectangular-selection": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/rectangular-selection/-/rectangular-selection-0.19.2.tgz", + "integrity": "sha512-AXK/p5eGwFJ9GJcLfntqN4dgY+XiIF7eHfXNQJX5HhQLSped2wJE6WuC1rMEaOlcpOqlb9mrNi/ZdUjSIj9mbA==", + "dependencies": { + "@codemirror/state": "^0.19.0", + "@codemirror/text": "^0.19.4", + "@codemirror/view": "^0.19.48" + } + }, + "node_modules/@codemirror/search": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.19.10.tgz", + "integrity": "sha512-qjubm69HJixPBWzI6HeEghTWOOD8NXiHOTRNvdizqs8xWRuFChq9zkjD3XiAJ7GXSTzCuQJnAP9DBBGCLq4ZIA==", + "dependencies": { + "@codemirror/panel": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.34", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "dependencies": { + "@codemirror/text": "^0.19.0" + } + }, + "node_modules/@codemirror/text": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.19.6.tgz", + "integrity": "sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==" + }, + "node_modules/@codemirror/tooltip": { + "version": "0.19.16", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.16.tgz", + "integrity": "sha512-zxKDHryUV5/RS45AQL+wOeN+i7/l81wK56OMnUPoTSzCWNITfxHn7BToDsjtrRKbzHqUxKYmBnn/4hPjpZ4WJQ==", + "dependencies": { + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "node_modules/@codemirror/view": { + "version": "0.19.48", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.19.48.tgz", + "integrity": "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw==", + "dependencies": { + "@codemirror/rangeset": "^0.19.5", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@csstools/normalize.css": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", @@ -2729,6 +2949,27 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==" + }, + "node_modules/@lezer/javascript": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-0.15.3.tgz", + "integrity": "sha512-8jA2NpOfpWwSPZxRhd9BxK2ZPvGd7nLE3LFTJ5AbMhXAzMHeMjneV6GEVd7dAIee85dtap0jdb6bgOSO0+lfwA==", + "dependencies": { + "@lezer/lr": "^0.15.0" + } + }, + "node_modules/@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "dependencies": { + "@lezer/common": "^0.15.0" + } + }, "node_modules/@mdx-js/mdx": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", @@ -7570,10 +7811,15 @@ "node": ">= 4.0" } }, - "node_modules/codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" + "node_modules/codemirror6-themes": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/codemirror6-themes/-/codemirror6-themes-0.1.2.tgz", + "integrity": "sha512-MlXaa3Bx3iz4Bh9DK7+Xy+aPqbRHRsPG1iogoe6W/5f6JJqTER5QroZfKTz+ACfTqpjk2OHahv6XMl8KRi6h0w==", + "dependencies": { + "@codemirror/highlight": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } }, "node_modules/collapse-white-space": { "version": "1.0.6", @@ -7839,6 +8085,11 @@ "node": ">=10" } }, + "node_modules/crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -16179,6 +16430,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -16434,13 +16694,31 @@ "node": ">=14" } }, - "node_modules/react-codemirror2": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.2.1.tgz", - "integrity": "sha512-t7YFmz1AXdlImgHXA9Ja0T6AWuopilub24jRaQdPVbzUJVNKIYuy3uCFZYa7CE5S3UW6SrSa5nAqVQvtzRF9gw==", + "node_modules/react-codemirror6": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-codemirror6/-/react-codemirror6-1.1.0.tgz", + "integrity": "sha512-xoXBMrnD4ZikGc3pJSXvjcy8HXuFHMOID1CTf3oJZzfh25MtkLaJxSd3gBz/hqy3rqlGXJH3BMVYDsFsfnHwQQ==", + "dependencies": { + "@babel/runtime": "^7.14.8", + "@codemirror/autocomplete": "^0.19.15", + "@codemirror/closebrackets": "^0.19.1", + "@codemirror/commands": "^0.19.8", + "@codemirror/comment": "^0.19.1", + "@codemirror/fold": "^0.19.3", + "@codemirror/gutter": "^0.19.9", + "@codemirror/highlight": "^0.19.8", + "@codemirror/history": "^0.19.2", + "@codemirror/language": "^0.19.10", + "@codemirror/lint": "^0.19.6", + "@codemirror/matchbrackets": "^0.19.4", + "@codemirror/rectangular-selection": "^0.19.2", + "@codemirror/search": "^0.19.9", + "@codemirror/state": "^0.19.9", + "@codemirror/view": "^0.19.48" + }, "peerDependencies": { - "codemirror": "5.x", - "react": ">=15.5 <=16.x" + "react": "^17.0.2", + "react-dom": "^17.0.2" } }, "node_modules/react-dev-utils": { @@ -16578,6 +16856,15 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "node_modules/react-hook-inview": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-hook-inview/-/react-hook-inview-4.4.1.tgz", + "integrity": "sha512-JKx0+aWCna0YUfTCKSaphGbaMp25S/YjpWtfk5VbqhlESesOEAPr7TCGMRLS3Cv6I1mEDhWYIhz2YLHgnHX4Yw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18095,6 +18382,11 @@ "webpack": "^5.0.0" } }, + "node_modules/style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "node_modules/style-to-object": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", @@ -19148,6 +19440,11 @@ "browser-process-hrtime": "^1.0.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", + "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" + }, "node_modules/w3c-xmlserializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", @@ -21343,6 +21640,223 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "@codemirror/autocomplete": { + "version": "0.19.15", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.19.15.tgz", + "integrity": "sha512-GQWzvvuXxNUyaEk+5gawbAD8s51/v2Chb++nx0e2eGWrphWk42isBtzOMdc3DxrxrZtPZ55q2ldNp+6G8KJLIQ==", + "requires": { + "@codemirror/language": "^0.19.0", + "@codemirror/state": "^0.19.4", + "@codemirror/text": "^0.19.2", + "@codemirror/tooltip": "^0.19.12", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.0" + } + }, + "@codemirror/closebrackets": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/closebrackets/-/closebrackets-0.19.2.tgz", + "integrity": "sha512-ClMPzPcPP0eQiDcVjtVPl6OLxgdtZSYDazsvT0AKl70V1OJva0eHgl4/6kCW3RZ0pb2n34i9nJz4eXCmK+TYDA==", + "requires": { + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.2", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.44" + } + }, + "@codemirror/commands": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.19.8.tgz", + "integrity": "sha512-65LIMSGUGGpY3oH6mzV46YWRrgao6NmfJ+AuC7jNz3K5NPnH6GCV1H5I6SwOFyVbkiygGyd0EFwrWqywTBD1aw==", + "requires": { + "@codemirror/language": "^0.19.0", + "@codemirror/matchbrackets": "^0.19.0", + "@codemirror/state": "^0.19.2", + "@codemirror/text": "^0.19.6", + "@codemirror/view": "^0.19.22", + "@lezer/common": "^0.15.0" + } + }, + "@codemirror/comment": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@codemirror/comment/-/comment-0.19.1.tgz", + "integrity": "sha512-uGKteBuVWAC6fW+Yt8u27DOnXMT/xV4Ekk2Z5mRsiADCZDqYvryrJd6PLL5+8t64BVyocwQwNfz1UswYS2CtFQ==", + "requires": { + "@codemirror/state": "^0.19.9", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "@codemirror/fold": { + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/fold/-/fold-0.19.4.tgz", + "integrity": "sha512-0SNSkRSOa6gymD6GauHa3sxiysjPhUC0SRVyTlvL52o0gz9GHdc8kNqNQskm3fBtGGOiSriGwF/kAsajRiGhVw==", + "requires": { + "@codemirror/gutter": "^0.19.0", + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.22" + } + }, + "@codemirror/gutter": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.19.9.tgz", + "integrity": "sha512-PFrtmilahin1g6uL27aG5tM/rqR9DZzZYZsIrCXA5Uc2OFTFqx4owuhoU9hqfYxHp5ovfvBwQ+txFzqS4vog6Q==", + "requires": { + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.23" + } + }, + "@codemirror/highlight": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.19.8.tgz", + "integrity": "sha512-v/lzuHjrYR8MN2mEJcUD6fHSTXXli9C1XGYpr+ElV6fLBIUhMTNKR3qThp611xuWfXfwDxeL7ppcbkM/MzPV3A==", + "requires": { + "@codemirror/language": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.3", + "@codemirror/view": "^0.19.39", + "@lezer/common": "^0.15.0", + "style-mod": "^4.0.0" + } + }, + "@codemirror/history": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/history/-/history-0.19.2.tgz", + "integrity": "sha512-unhP4t3N2smzmHoo/Yio6ueWi+il8gm9VKrvi6wlcdGH5fOfVDNkmjHQ495SiR+EdOG35+3iNebSPYww0vN7ow==", + "requires": { + "@codemirror/state": "^0.19.2", + "@codemirror/view": "^0.19.0" + } + }, + "@codemirror/lang-javascript": { + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-0.19.7.tgz", + "integrity": "sha512-DL9f3JLqOEHH9cIwEqqjnP5bkjdVXeECksLtV+/MbPm+l4H+AG+PkwZaJQ2oR1GfPZKh8MVSIE94aGWNkJP8WQ==", + "requires": { + "@codemirror/autocomplete": "^0.19.0", + "@codemirror/highlight": "^0.19.7", + "@codemirror/language": "^0.19.0", + "@codemirror/lint": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/javascript": "^0.15.1" + } + }, + "@codemirror/language": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.19.10.tgz", + "integrity": "sha512-yA0DZ3RYn2CqAAGW62VrU8c4YxscMQn45y/I9sjBlqB1e2OTQLg4CCkMBuMSLXk4xaqjlsgazeOQWaJQOKfV8Q==", + "requires": { + "@codemirror/state": "^0.19.0", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.5", + "@lezer/lr": "^0.15.0" + } + }, + "@codemirror/lint": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.19.6.tgz", + "integrity": "sha512-Pbw1Y5kHVs2J+itQ0uez3dI4qY9ApYVap7eNfV81x1/3/BXgBkKfadaw0gqJ4h4FDG7OnJwb0VbPsjJQllHjaA==", + "requires": { + "@codemirror/gutter": "^0.19.4", + "@codemirror/panel": "^0.19.0", + "@codemirror/rangeset": "^0.19.1", + "@codemirror/state": "^0.19.4", + "@codemirror/tooltip": "^0.19.16", + "@codemirror/view": "^0.19.22", + "crelt": "^1.0.5" + } + }, + "@codemirror/matchbrackets": { + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@codemirror/matchbrackets/-/matchbrackets-0.19.4.tgz", + "integrity": "sha512-VFkaOKPNudAA5sGP1zikRHCEKU0hjYmkKpr04pybUpQvfTvNJXlReCyP0rvH/1iEwAGPL990ZTT+QrLdu4MeEA==", + "requires": { + "@codemirror/language": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0", + "@lezer/common": "^0.15.0" + } + }, + "@codemirror/panel": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@codemirror/panel/-/panel-0.19.1.tgz", + "integrity": "sha512-sYeOCMA3KRYxZYJYn5PNlt9yNsjy3zTNTrbYSfVgjgL9QomIVgOJWPO5hZ2sTN8lufO6lw0vTBsIPL9MSidmBg==", + "requires": { + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "@codemirror/rangeset": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.9.tgz", + "integrity": "sha512-V8YUuOvK+ew87Xem+71nKcqu1SXd5QROMRLMS/ljT5/3MCxtgrRie1Cvild0G/Z2f1fpWxzX78V0U4jjXBorBQ==", + "requires": { + "@codemirror/state": "^0.19.0" + } + }, + "@codemirror/rectangular-selection": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@codemirror/rectangular-selection/-/rectangular-selection-0.19.2.tgz", + "integrity": "sha512-AXK/p5eGwFJ9GJcLfntqN4dgY+XiIF7eHfXNQJX5HhQLSped2wJE6WuC1rMEaOlcpOqlb9mrNi/ZdUjSIj9mbA==", + "requires": { + "@codemirror/state": "^0.19.0", + "@codemirror/text": "^0.19.4", + "@codemirror/view": "^0.19.48" + } + }, + "@codemirror/search": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.19.10.tgz", + "integrity": "sha512-qjubm69HJixPBWzI6HeEghTWOOD8NXiHOTRNvdizqs8xWRuFChq9zkjD3XiAJ7GXSTzCuQJnAP9DBBGCLq4ZIA==", + "requires": { + "@codemirror/panel": "^0.19.0", + "@codemirror/rangeset": "^0.19.0", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "@codemirror/view": "^0.19.34", + "crelt": "^1.0.5" + } + }, + "@codemirror/state": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.19.9.tgz", + "integrity": "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw==", + "requires": { + "@codemirror/text": "^0.19.0" + } + }, + "@codemirror/text": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.19.6.tgz", + "integrity": "sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==" + }, + "@codemirror/tooltip": { + "version": "0.19.16", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.19.16.tgz", + "integrity": "sha512-zxKDHryUV5/RS45AQL+wOeN+i7/l81wK56OMnUPoTSzCWNITfxHn7BToDsjtrRKbzHqUxKYmBnn/4hPjpZ4WJQ==", + "requires": { + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } + }, + "@codemirror/view": { + "version": "0.19.48", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.19.48.tgz", + "integrity": "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw==", + "requires": { + "@codemirror/rangeset": "^0.19.5", + "@codemirror/state": "^0.19.3", + "@codemirror/text": "^0.19.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, "@csstools/normalize.css": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", @@ -21972,6 +22486,27 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==" + }, + "@lezer/javascript": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-0.15.3.tgz", + "integrity": "sha512-8jA2NpOfpWwSPZxRhd9BxK2ZPvGd7nLE3LFTJ5AbMhXAzMHeMjneV6GEVd7dAIee85dtap0jdb6bgOSO0+lfwA==", + "requires": { + "@lezer/lr": "^0.15.0" + } + }, + "@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "requires": { + "@lezer/common": "^0.15.0" + } + }, "@mdx-js/mdx": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", @@ -25354,10 +25889,15 @@ "q": "^1.1.2" } }, - "codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" + "codemirror6-themes": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/codemirror6-themes/-/codemirror6-themes-0.1.2.tgz", + "integrity": "sha512-MlXaa3Bx3iz4Bh9DK7+Xy+aPqbRHRsPG1iogoe6W/5f6JJqTER5QroZfKTz+ACfTqpjk2OHahv6XMl8KRi6h0w==", + "requires": { + "@codemirror/highlight": "^0.19.0", + "@codemirror/state": "^0.19.0", + "@codemirror/view": "^0.19.0" + } }, "collapse-white-space": { "version": "1.0.6", @@ -25560,6 +26100,11 @@ "yaml": "^1.10.0" } }, + "crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -31448,6 +31993,12 @@ } } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -31641,11 +32192,28 @@ "whatwg-fetch": "^3.6.2" } }, - "react-codemirror2": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.2.1.tgz", - "integrity": "sha512-t7YFmz1AXdlImgHXA9Ja0T6AWuopilub24jRaQdPVbzUJVNKIYuy3uCFZYa7CE5S3UW6SrSa5nAqVQvtzRF9gw==", - "requires": {} + "react-codemirror6": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-codemirror6/-/react-codemirror6-1.1.0.tgz", + "integrity": "sha512-xoXBMrnD4ZikGc3pJSXvjcy8HXuFHMOID1CTf3oJZzfh25MtkLaJxSd3gBz/hqy3rqlGXJH3BMVYDsFsfnHwQQ==", + "requires": { + "@babel/runtime": "^7.14.8", + "@codemirror/autocomplete": "^0.19.15", + "@codemirror/closebrackets": "^0.19.1", + "@codemirror/commands": "^0.19.8", + "@codemirror/comment": "^0.19.1", + "@codemirror/fold": "^0.19.3", + "@codemirror/gutter": "^0.19.9", + "@codemirror/highlight": "^0.19.8", + "@codemirror/history": "^0.19.2", + "@codemirror/language": "^0.19.10", + "@codemirror/lint": "^0.19.6", + "@codemirror/matchbrackets": "^0.19.4", + "@codemirror/rectangular-selection": "^0.19.2", + "@codemirror/search": "^0.19.9", + "@codemirror/state": "^0.19.9", + "@codemirror/view": "^0.19.48" + } }, "react-dev-utils": { "version": "12.0.0", @@ -31748,6 +32316,12 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "react-hook-inview": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-hook-inview/-/react-hook-inview-4.4.1.tgz", + "integrity": "sha512-JKx0+aWCna0YUfTCKSaphGbaMp25S/YjpWtfk5VbqhlESesOEAPr7TCGMRLS3Cv6I1mEDhWYIhz2YLHgnHX4Yw==", + "requires": {} + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -32899,6 +33473,11 @@ "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", "requires": {} }, + "style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "style-to-object": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", @@ -33677,6 +34256,11 @@ "browser-process-hrtime": "^1.0.0" } }, + "w3c-keyname": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", + "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" + }, "w3c-xmlserializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", diff --git a/repl/package.json b/repl/package.json index 58a65c61..eceed51b 100644 --- a/repl/package.json +++ b/repl/package.json @@ -4,15 +4,17 @@ "private": true, "homepage": "https://strudel.tidalcycles.org", "dependencies": { + "@codemirror/lang-javascript": "^0.19.0", "@testing-library/jest-dom": "^5.16.3", "@testing-library/react": "^12.1.4", "@testing-library/user-event": "^13.5.0", - "codemirror": "^5.65.2", + "codemirror6-themes": "^0.1.2", "events": "^3.3.0", "gh-pages": "^3.2.3", "react": "^17.0.2", - "react-codemirror2": "^7.2.1", + "react-codemirror6": "^1.1.0", "react-dom": "^17.0.2", + "react-hook-inview": "^4.4.1", "react-scripts": "5.0.0", "tone": "^14.7.77", "web-vitals": "^2.1.4" @@ -53,6 +55,7 @@ "autoprefixer": "^10.4.4", "parcel": "^2.3.1", "postcss": "^8.4.12", + "process": "^0.11.10", "serve": "^13.0.2", "tailwindcss": "^3.0.23" } diff --git a/repl/src/App.js b/repl/src/App.js index 1e3f3241..85ab9a64 100644 --- a/repl/src/App.js +++ b/repl/src/App.js @@ -4,8 +4,8 @@ Copyright (C) 2022 Strudel contributors - see . */ +import CodeMirror6, { setHighlights } from './CodeMirror6'; import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'; -import CodeMirror, { markEvent, markParens } from './CodeMirror'; import cx from './cx'; import logo from './logo.svg'; import playStatic from './static.mjs'; @@ -39,6 +39,7 @@ import '@strudel.cycles/osc/osc.mjs'; import '@strudel.cycles/webaudio/webaudio.mjs'; import '@strudel.cycles/serial/serial.mjs'; import controls from '@strudel.cycles/core/controls.mjs'; +import useHighlighting from './useHighlighting'; extend( Tone, @@ -56,7 +57,6 @@ extend( Tone, }, ); -// eval stuff end const codeParam = window.location.href.split('#')[1]; let decoded; @@ -76,14 +76,27 @@ const randomTune = getRandomTune(); const defaultSynth = getDefaultSynth(); function App() { - const [editor, setEditor] = useState(); - const { setCode, setPattern, error, code, cycle, dirty, log, togglePlay, activateCode, pattern, pushLog, pending } = - useRepl({ - tune: decoded || randomTune, - defaultSynth, - onDraw: useCallback((time, event) => markEvent(editor)(time, event), [editor]), - }); - const [uiHidden, setUiHidden] = useState(false); + // const [editor, setEditor] = useState(); + const [view, setView] = useState(); + const { + setCode, + setPattern, + error, + code, + cycle, + dirty, + log, + togglePlay, + activeCode, + setActiveCode, + activateCode, + pattern, + pushLog, + pending, + } = useRepl({ + tune: decoded || randomTune, + defaultSynth, + }); const logBox = useRef(); // scroll log box to bottom when log changes useLayoutEffect(() => { @@ -108,6 +121,8 @@ function App() { return () => window.removeEventListener('keydown', handleKeyPress); }, [pattern, code, activateCode, cycle]); + useHighlighting({ view, pattern, active: cycle.started && !activeCode?.includes('strudel disable-highlighting') }); + useWebMidi({ ready: useCallback( ({ outputs }) => { @@ -133,17 +148,14 @@ function App() {
-
-
- setCode(value)} - /> - - {!cycle.started ? `press ctrl+enter to play\n` : dirty ? `ctrl+enter to update\n` : 'no changes\n'} - -
+
+ {/* onCursor={markParens} */} + + + {!cycle.started ? `press ctrl+enter to play\n` : dirty ? `ctrl+enter to update\n` : 'no changes\n'} + {error && (
{error?.message || 'unknown error'} diff --git a/repl/src/CodeMirror.jsx b/repl/src/CodeMirror6.jsx similarity index 51% rename from repl/src/CodeMirror.jsx rename to repl/src/CodeMirror6.jsx index a659e3ee..942843d7 100644 --- a/repl/src/CodeMirror.jsx +++ b/repl/src/CodeMirror6.jsx @@ -1,53 +1,72 @@ import React from 'react'; -import { Controlled as CodeMirror2 } from 'react-codemirror2'; -import 'codemirror/mode/javascript/javascript'; -import 'codemirror/mode/pegjs/pegjs'; -// import 'codemirror/theme/material.css'; -import 'codemirror/lib/codemirror.css'; -import 'codemirror/theme/material.css'; +import { CodeMirror as _CodeMirror } from 'react-codemirror6'; +import { EditorView, Decoration } from '@codemirror/view'; +import { StateField, StateEffect } from '@codemirror/state'; +import { javascript } from '@codemirror/lang-javascript'; +// import { materialPalenight } from 'codemirror6-themes'; +import { materialPalenight } from './themes/material-palenight'; -export default function CodeMirror({ value, onChange, onCursor, options, editorDidMount }) { - options = options || { - mode: 'javascript', - theme: 'material', - lineNumbers: true, - styleSelectedText: true, - cursorBlinkRate: 500, - }; +export const setHighlights = StateEffect.define(); +const highlightField = StateField.define({ + create() { + return Decoration.none; + }, + update(highlights, tr) { + try { + for (let e of tr.effects) { + if (e.is(setHighlights)) { + highlights = Decoration.set( + e.value + .flatMap((hap) => + (hap.context.locations || []).map(({ start, end }) => { + const color = hap.context.color || '#FFCA28'; + let from = tr.newDoc.line(start.line).from + start.column; + let to = tr.newDoc.line(end.line).from + end.column; + const l = tr.newDoc.length; + if (from > l || to > l) { + return; // dont mark outside of range, as it will throw an error + } + const mark = Decoration.mark({ attributes: { style: `outline: 1px solid ${color}` } }); + return mark.range(from, to); + }), + ) + .filter(Boolean), + true, + ); + } + } + return highlights; + } catch (err) { + // console.warn('highlighting error', err); + return highlights; + } + }, + provide: (f) => EditorView.decorations.from(f), +}); + +export default function CodeMirror({ value, onChange, onViewChanged, onCursor, options, editorDidMount }) { return ( - onCursor?.(editor, data)} - /> + <> + <_CodeMirror + onViewChange={onViewChanged} + style={{ + display: 'flex', + flexDirection: 'column', + flex: '1 0 auto', + }} + value={value} + onChange={onChange} + extensions={[ + javascript(), + materialPalenight, + highlightField, + // theme, language, ... + ]} + /> + ); } -export const markEvent = (editor) => (time, event) => { - const locs = event.context.locations; - if (!locs || !editor) { - return; - } - const col = event.context?.color || '#FFCA28'; - // mark active event - const marks = locs.map(({ start, end }) => - editor.getDoc().markText( - { line: start.line - 1, ch: start.column }, - { line: end.line - 1, ch: end.column }, - //{ css: 'background-color: #FFCA28; color: black' } // background-color is now used by parent marking - { css: 'outline: 1px solid ' + col + '; box-sizing:border-box' }, - //{ css: `background-color: ${col};border-radius:5px` }, - ), - ); - //Tone.Transport.schedule(() => { // problem: this can be cleared by scheduler... - setTimeout(() => { - marks.forEach((mark) => mark.clear()); - // }, '+' + event.duration.valueOf() * 0.5); - }, event.duration.valueOf() /* * 0.9 */ * 1000); -}; - let parenMark; export const markParens = (editor, data) => { const v = editor.getDoc().getValue(); @@ -75,6 +94,10 @@ export function offsetToPosition(offset, code) { // returns absolute character offset from { line, ch } export function positionToOffset(position, code) { const lines = code.split('\n'); + if (position.line > lines.length) { + // throw new Error('positionToOffset: position.line > lines.length'); + return 0; + } let offset = 0; for (let i = 0; i < position.line; i++) { offset += lines[i].length + 1; @@ -119,3 +142,27 @@ export function getCurrentParenArea(code, caretPosition) { end = i; return [begin, end].map((o) => offsetToPosition(o, code)); } + +/* +export const markEvent = (editor) => (time, event) => { + const locs = event.context.locations; + if (!locs || !editor) { + return; + } + const col = event.context?.color || '#FFCA28'; + // mark active event + const marks = locs.map(({ start, end }) => + editor.getDoc().markText( + { line: start.line - 1, ch: start.column }, + { line: end.line - 1, ch: end.column }, + //{ css: 'background-color: #FFCA28; color: black' } // background-color is now used by parent marking + { css: 'outline: 1px solid ' + col + '; box-sizing:border-box' }, + //{ css: `background-color: ${col};border-radius:5px` }, + ), + ); + //Tone.Transport.schedule(() => { // problem: this can be cleared by scheduler... + setTimeout(() => { + marks.forEach((mark) => mark.clear()); + // }, '+' + event.duration * 0.5); + }, event.duration * 1000); +}; */ diff --git a/repl/src/themes/material-palenight.js b/repl/src/themes/material-palenight.js new file mode 100644 index 00000000..5ee559c9 --- /dev/null +++ b/repl/src/themes/material-palenight.js @@ -0,0 +1,135 @@ +import { EditorView } from '@codemirror/view'; +import { HighlightStyle, tags as t } from '@codemirror/highlight'; + +/* + Credits for color palette: + + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://material-theme.site/ +*/ + +const ivory = '#abb2bf', + stone = '#7d8799', // Brightened compared to original to increase contrast + invalid = '#ffffff', + darkBackground = '#21252b', + highlightBackground = 'rgba(0, 0, 0, 0.5)', + // background = '#292d3e', + background = 'transparent', + tooltipBackground = '#353a42', + selection = 'rgba(128, 203, 196, 0.2)', + cursor = '#ffcc00'; + +/// The editor theme styles for Material Palenight. +export const materialPalenightTheme = EditorView.theme( + { + // done + '&': { + color: '#ffffff', + backgroundColor: background, + fontSize: '15px', + 'z-index': 11, + }, + + // done + '.cm-content': { + caretColor: cursor, + lineHeight: '22px', + }, + '.cm-line': { + background: '#2C323699', + }, + // done + '&.cm-focused .cm-cursor': { + borderLeftColor: cursor, + }, + + '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': { + backgroundColor: selection, + }, + + '.cm-panels': { backgroundColor: darkBackground, color: '#ffffff' }, + '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' }, + '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' }, + + // done, use onedarktheme + '.cm-searchMatch': { + backgroundColor: '#72a1ff59', + outline: '1px solid #457dff', + }, + '.cm-searchMatch.cm-searchMatch-selected': { + backgroundColor: '#6199ff2f', + }, + + '.cm-activeLine': { backgroundColor: highlightBackground }, + '.cm-selectionMatch': { backgroundColor: '#aafe661a' }, + + '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { + backgroundColor: '#bad0f847', + outline: '1px solid #515a6b', + }, + + // done + '.cm-gutters': { + background: '#2C323699', + color: '#676e95', + border: 'none', + }, + + '.cm-activeLineGutter': { + backgroundColor: highlightBackground, + }, + + '.cm-foldPlaceholder': { + backgroundColor: 'transparent', + border: 'none', + color: '#ddd', + }, + + '.cm-tooltip': { + border: 'none', + backgroundColor: tooltipBackground, + }, + '.cm-tooltip .cm-tooltip-arrow:before': { + borderTopColor: 'transparent', + borderBottomColor: 'transparent', + }, + '.cm-tooltip .cm-tooltip-arrow:after': { + borderTopColor: tooltipBackground, + borderBottomColor: tooltipBackground, + }, + '.cm-tooltip-autocomplete': { + '& > ul > li[aria-selected]': { + backgroundColor: highlightBackground, + color: ivory, + }, + }, + }, + { dark: true }, +); + +/// The highlighting style for code in the Material Palenight theme. +export const materialPalenightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: '#c792ea' }, + { tag: t.operator, color: '#89ddff' }, + { tag: t.special(t.variableName), color: '#eeffff' }, + { tag: t.typeName, color: '#f07178' }, + { tag: t.atom, color: '#f78c6c' }, + { tag: t.number, color: '#ff5370' }, + { tag: t.definition(t.variableName), color: '#82aaff' }, + { tag: t.string, color: '#c3e88d' }, + { tag: t.special(t.string), color: '#f07178' }, + { tag: t.comment, color: stone }, + { tag: t.variableName, color: '#f07178' }, + { tag: t.tagName, color: '#ff5370' }, + { tag: t.bracket, color: '#a2a1a4' }, + { tag: t.meta, color: '#ffcb6b' }, + { tag: t.attributeName, color: '#c792ea' }, + { tag: t.propertyName, color: '#c792ea' }, + { tag: t.className, color: '#decb6b' }, + { tag: t.invalid, color: invalid }, +]); + +/// Extension to enable the Material Palenight theme (both the editor theme and +/// the highlight style). +// : Extension +export const materialPalenight = [materialPalenightTheme, materialPalenightHighlightStyle]; diff --git a/repl/src/tutorial/MiniRepl.jsx b/repl/src/tutorial/MiniRepl.jsx index 7d49c9d5..fae330a5 100644 --- a/repl/src/tutorial/MiniRepl.jsx +++ b/repl/src/tutorial/MiniRepl.jsx @@ -1,8 +1,9 @@ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useState } from 'react'; import { Tone } from '@strudel.cycles/tone'; import useRepl from '../useRepl.mjs'; -import CodeMirror, { markEvent } from '../CodeMirror'; import cx from '../cx'; +import useHighlighting from '../useHighlighting'; +import { useInView } from 'react-hook-inview'; // eval stuff start import { extend } from '@strudel.cycles/eval'; @@ -24,6 +25,7 @@ import '@strudel.cycles/xen/tune.mjs'; import '@strudel.cycles/core/euclid.mjs'; import '@strudel.cycles/tone/pianoroll.mjs'; import '@strudel.cycles/tone/draw.mjs'; +import CodeMirror6 from '../CodeMirror6'; extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { gist, @@ -43,17 +45,19 @@ const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destina // "balanced" | "interactive" | "playback"; // Tone.setContext(new Tone.Context({ latencyHint: 'playback', lookAhead: 1 })); function MiniRepl({ tune, maxHeight = 500 }) { - const [editor, setEditor] = useState(); - const { code, setCode, activateCode, activeCode, setPattern, error, cycle, dirty, log, togglePlay, hash } = useRepl({ + const { code, setCode, pattern, activateCode, error, cycle, dirty, togglePlay } = useRepl({ tune, defaultSynth, autolink: false, - onDraw: useCallback(markEvent(editor), [editor]), }); const lines = code.split('\n').length; - const height = Math.min(lines * 30 + 30, maxHeight); + const [view, setView] = useState(); + const [ref, isVisible] = useInView({ + threshold: 0.01, + }); + useHighlighting({ view, pattern, active: cycle.started }); return ( -
+
-
- setCode(value)} - /> +
+ {isVisible && }
{/*
diff --git a/repl/src/tutorial/style.css b/repl/src/tutorial/style.css index 2a2e1d06..e7a3d9ed 100644 --- a/repl/src/tutorial/style.css +++ b/repl/src/tutorial/style.css @@ -2,10 +2,8 @@ @tailwind components; @tailwind utilities; -.react-codemirror2, -.CodeMirror { - width: 100% !important; - height: inherit !important; +.cm-editor { + background-color: transparent !important; } main { diff --git a/repl/src/useHighlighting.js b/repl/src/useHighlighting.js new file mode 100644 index 00000000..855fb5d6 --- /dev/null +++ b/repl/src/useHighlighting.js @@ -0,0 +1,41 @@ +import { useEffect } from 'react'; +import { setHighlights } from './CodeMirror6'; +import { Tone } from '@strudel.cycles/tone'; + +let highlights = []; // actively highlighted events +let lastEnd; + +function useHighlighting({ view, pattern, active }) { + useEffect(() => { + if (view) { + if (pattern && active) { + let frame = requestAnimationFrame(updateHighlights); + + function updateHighlights() { + try { + const audioTime = Tone.getTransport().seconds; + const span = [lastEnd || audioTime, audioTime + 1 / 60]; + lastEnd = audioTime + 1 / 60; + highlights = highlights.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active + const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset()); + highlights = highlights.concat(haps); // add potential new onsets + view.dispatch({ effects: setHighlights.of(highlights) }); // highlight all still active + new active haps + } catch (err) { + // console.log('error in updateHighlights', err); + view.dispatch({ effects: setHighlights.of([]) }); + } + frame = requestAnimationFrame(updateHighlights); + } + + return () => { + cancelAnimationFrame(frame); + }; + } else { + highlights = []; + view.dispatch({ effects: setHighlights.of([]) }); + } + } + }, [pattern, active, view]); +} + +export default useHighlighting; diff --git a/repl/src/useRepl.mjs b/repl/src/useRepl.mjs index 9246374c..4f3791d6 100644 --- a/repl/src/useRepl.mjs +++ b/repl/src/useRepl.mjs @@ -17,7 +17,7 @@ let s4 = () => { }; const generateHash = (code) => encodeURIComponent(btoa(code)); -function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { +function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawProp }) { const id = useMemo(() => s4(), []); const [code, setCode] = useState(tune); const [activeCode, setActiveCode] = useState(); @@ -30,11 +30,11 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { const pushLog = useCallback((message) => setLog((log) => log + `${log ? '\n\n' : ''}${message}`), []); // below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment) - onDraw = useMemo(() => { + const onDraw = useMemo(() => { if (activeCode && !activeCode.includes('strudel disable-highlighting')) { - return onDraw; + return (time, event) => onDrawProp?.(time, event, activeCode); } - }, [activeCode, onDraw]); + }, [activeCode, onDrawProp]); // cycle hook to control scheduling const cycle = useCycle({ @@ -146,6 +146,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { dirty, log, togglePlay, + setActiveCode, activateCode, activeCode, pushLog,