mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-11 17:46:41 -05:00
Add variable highlighting widgets
This commit is contained in:
146
package-lock.json
generated
146
package-lock.json
generated
@@ -12,7 +12,11 @@
|
||||
"@codemirror/lang-html": "^6.4.2",
|
||||
"@codemirror/lang-javascript": "^6.1.4",
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/language": "^6.6.0",
|
||||
"@codemirror/search": "^6.2.3",
|
||||
"@lezer/generator": "^1.2.2",
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
"@lezer/lr": "^1.3.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.2",
|
||||
"@radix-ui/react-icons": "^1.2.0",
|
||||
"@radix-ui/react-popover": "1.0.3",
|
||||
@@ -21,6 +25,7 @@
|
||||
"classnames": "^2.3.2",
|
||||
"codemirror": "^6.0.1",
|
||||
"framer-motion": "^9.0.4",
|
||||
"parse-json": "^6.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
@@ -29,6 +34,7 @@
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.2",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||
@@ -67,7 +73,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.18.6"
|
||||
},
|
||||
@@ -272,7 +277,6 @@
|
||||
"version": "7.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -304,7 +308,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"chalk": "^2.0.0",
|
||||
@@ -1067,6 +1070,18 @@
|
||||
"@lezer/lr": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/generator": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.2.2.tgz",
|
||||
"integrity": "sha512-O//eH9jTPM1GnbZruuD23xU68Pkuragonn1DEIom4Kt/eJN/QFt7Vzvp1YjV/XBmoUKC+2ySPgrA5fMF9FMM2g==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.0.2",
|
||||
"@lezer/lr": "^1.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"lezer-generator": "dist/lezer-generator.cjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/highlight": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz",
|
||||
@@ -2043,6 +2058,12 @@
|
||||
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -2457,7 +2478,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
@@ -2786,7 +2806,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -2872,7 +2891,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -2880,8 +2898,7 @@
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -3209,6 +3226,14 @@
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.21.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
|
||||
@@ -3366,7 +3391,6 @@
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
@@ -4275,7 +4299,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -4438,6 +4461,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"node_modules/is-bigint": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
|
||||
@@ -4772,6 +4800,11 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
@@ -4846,6 +4879,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz",
|
||||
"integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@@ -5200,6 +5241,23 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-6.0.2.tgz",
|
||||
"integrity": "sha512-SA5aMiaIjXkAiBrW/yPgLgQAQg42f7K3ACO+2l/zOvtQBwX58DMUsFJXelW2fx3yMBmWOVkR6j1MGsdSbCA4UA==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.16.0",
|
||||
"error-ex": "^1.3.2",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"lines-and-columns": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -6035,7 +6093,6 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
@@ -6672,7 +6729,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.18.6"
|
||||
}
|
||||
@@ -6826,8 +6882,7 @@
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
|
||||
},
|
||||
"@babel/helper-validator-option": {
|
||||
"version": "7.18.6",
|
||||
@@ -6850,7 +6905,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"chalk": "^2.0.0",
|
||||
@@ -7343,6 +7397,15 @@
|
||||
"@lezer/lr": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@lezer/generator": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.2.2.tgz",
|
||||
"integrity": "sha512-O//eH9jTPM1GnbZruuD23xU68Pkuragonn1DEIom4Kt/eJN/QFt7Vzvp1YjV/XBmoUKC+2ySPgrA5fMF9FMM2g==",
|
||||
"requires": {
|
||||
"@lezer/common": "^1.0.2",
|
||||
"@lezer/lr": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@lezer/highlight": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz",
|
||||
@@ -8012,6 +8075,12 @@
|
||||
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -8292,7 +8361,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
@@ -8515,7 +8583,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -8583,7 +8650,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -8591,8 +8657,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -8839,6 +8904,14 @@
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.21.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
|
||||
@@ -8967,8 +9040,7 @@
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.34.0",
|
||||
@@ -9652,8 +9724,7 @@
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"has-property-descriptors": {
|
||||
"version": "1.0.0",
|
||||
@@ -9768,6 +9839,11 @@
|
||||
"is-typed-array": "^1.1.10"
|
||||
}
|
||||
},
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"is-bigint": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
|
||||
@@ -9993,6 +10069,11 @@
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true
|
||||
},
|
||||
"json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
@@ -10052,6 +10133,11 @@
|
||||
"integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==",
|
||||
"dev": true
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz",
|
||||
"integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w=="
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@@ -10310,6 +10396,17 @@
|
||||
"callsites": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-6.0.2.tgz",
|
||||
"integrity": "sha512-SA5aMiaIjXkAiBrW/yPgLgQAQg42f7K3ACO+2l/zOvtQBwX58DMUsFJXelW2fx3yMBmWOVkR6j1MGsdSbCA4UA==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.16.0",
|
||||
"error-ex": "^1.3.2",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"lines-and-columns": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -10867,7 +10964,6 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
|
||||
16
package.json
16
package.json
@@ -16,7 +16,11 @@
|
||||
"@codemirror/lang-html": "^6.4.2",
|
||||
"@codemirror/lang-javascript": "^6.1.4",
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/language": "^6.6.0",
|
||||
"@codemirror/search": "^6.2.3",
|
||||
"@lezer/generator": "^1.2.2",
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
"@lezer/lr": "^1.3.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.2",
|
||||
"@radix-ui/react-icons": "^1.2.0",
|
||||
"@radix-ui/react-popover": "1.0.3",
|
||||
@@ -25,6 +29,7 @@
|
||||
"classnames": "^2.3.2",
|
||||
"codemirror": "^6.0.1",
|
||||
"framer-motion": "^9.0.4",
|
||||
"parse-json": "^6.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
@@ -33,20 +38,21 @@
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.2",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||
"@typescript-eslint/parser": "^5.52.0",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"concurrently": "^7.6.0",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||
"@typescript-eslint/parser": "^5.52.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"prettier": "^2.8.4",
|
||||
"concurrently": "^7.6.0",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.4",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^4.0.0",
|
||||
|
||||
@@ -54,6 +54,7 @@ function App() {
|
||||
/>
|
||||
<Editor
|
||||
key={request.id}
|
||||
useTemplating
|
||||
defaultValue={request.body}
|
||||
contentType="application/json"
|
||||
onChange={(body) => updateRequest.mutate({ body })}
|
||||
|
||||
@@ -11,10 +11,22 @@
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
font-size: 0.9rem;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.cm-editor .cm-tooltip {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.cm-editor .placeholder-widget {
|
||||
background-color: hsl(var(--color-blue-400));
|
||||
padding: 0.05em 0.3em;
|
||||
border-radius: 0.2em;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cm-editor .cm-scroller {
|
||||
border: 1px solid hsl(var(--color-gray-50));
|
||||
border-radius: var(--border-radius-lg);
|
||||
background-color: hsl(var(--color-gray-50));
|
||||
}
|
||||
@@ -24,7 +36,7 @@
|
||||
}
|
||||
|
||||
.cm-editor.cm-focused .cm-scroller {
|
||||
border-color: hsl(var(--color-blue-400)/0.4);
|
||||
box-shadow: 0 0 0 1px hsl(var(--color-blue-400)/0.4);
|
||||
}
|
||||
|
||||
.cm-editor .cm-line {
|
||||
@@ -77,10 +89,6 @@
|
||||
color: hsl(var(--color-gray-300));
|
||||
}
|
||||
|
||||
.cm-editor .cm-content {
|
||||
padding-top: 0.4rem;
|
||||
}
|
||||
|
||||
.cm-editor .cm-foldPlaceholder {
|
||||
background-color: hsl(var(--color-gray-100));
|
||||
border: 1px solid hsl(var(--color-gray-200));
|
||||
@@ -102,7 +110,7 @@
|
||||
}
|
||||
|
||||
.cm-editor .cm-cursor {
|
||||
border-left: 2px solid red;
|
||||
border-left: 2px solid hsl(var(--color-gray-900));
|
||||
}
|
||||
|
||||
.cm-editor .cm-selectionBackground {
|
||||
@@ -112,3 +120,16 @@
|
||||
.cm-editor.cm-focused .cm-selectionBackground {
|
||||
background-color: hsl(var(--color-gray-200));
|
||||
}
|
||||
|
||||
/* --> Add padding to container. For some reason, using padding on both adds an extra
|
||||
* 1px offset so we need to use a combination of padding and margin.
|
||||
*/
|
||||
.cm-editor .cm-gutters {
|
||||
padding-top: 0.2em;
|
||||
}
|
||||
|
||||
.cm-editor .cm-content {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
/* <-- */
|
||||
|
||||
@@ -6,14 +6,15 @@ import { EditorState } from '@codemirror/state';
|
||||
|
||||
interface Props {
|
||||
contentType: string;
|
||||
useTemplating?: boolean;
|
||||
defaultValue?: string | null;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export default function Editor({ contentType, defaultValue, onChange }: Props) {
|
||||
export default function Editor({ contentType, useTemplating, defaultValue, onChange }: Props) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const extensions = useMemo(() => {
|
||||
const ext = syntaxExtension(contentType);
|
||||
const ext = syntaxExtension({ contentType, useTemplating });
|
||||
return [
|
||||
...baseExtensions,
|
||||
...(ext ? [ext] : []),
|
||||
@@ -28,13 +29,18 @@ export default function Editor({ contentType, defaultValue, onChange }: Props) {
|
||||
useEffect(() => {
|
||||
if (ref.current === null) return;
|
||||
|
||||
const view = new EditorView({
|
||||
state: EditorState.create({
|
||||
doc: defaultValue ?? '',
|
||||
extensions: extensions,
|
||||
}),
|
||||
parent: ref.current,
|
||||
});
|
||||
let view: EditorView;
|
||||
try {
|
||||
view = new EditorView({
|
||||
state: EditorState.create({
|
||||
doc: defaultValue ?? '',
|
||||
extensions: extensions,
|
||||
}),
|
||||
parent: ref.current,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return () => view?.destroy();
|
||||
}, [ref.current]);
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { parser as twigParser } from './twig/twig';
|
||||
import {
|
||||
bracketMatching,
|
||||
defaultHighlightStyle,
|
||||
foldGutter,
|
||||
foldInside,
|
||||
foldKeymap,
|
||||
foldNodeProp,
|
||||
HighlightStyle,
|
||||
indentNodeProp,
|
||||
indentOnInput,
|
||||
LanguageSupport,
|
||||
LRLanguage,
|
||||
syntaxHighlighting,
|
||||
} from '@codemirror/language';
|
||||
import { lintKeymap } from '@codemirror/lint';
|
||||
import {
|
||||
crosshairCursor,
|
||||
drawSelection,
|
||||
@@ -19,6 +24,12 @@ import {
|
||||
lineNumbers,
|
||||
rectangularSelection,
|
||||
} from '@codemirror/view';
|
||||
import { html } from '@codemirror/lang-html';
|
||||
import { parseMixed } from '@lezer/common';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { json } from '@codemirror/lang-json';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
|
||||
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
|
||||
import {
|
||||
@@ -27,35 +38,86 @@ import {
|
||||
closeBracketsKeymap,
|
||||
completionKeymap,
|
||||
} from '@codemirror/autocomplete';
|
||||
import { lintKeymap } from '@codemirror/lint';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { json } from '@codemirror/lang-json';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { html } from '@codemirror/lang-html';
|
||||
import { tags } from '@lezer/highlight';
|
||||
import { placeholders } from './widgets';
|
||||
|
||||
export const myHighlightStyle = HighlightStyle.define([
|
||||
{
|
||||
tag: [tags.documentMeta, tags.blockComment, tags.lineComment, tags.docComment, tags.comment],
|
||||
tag: [t.documentMeta, t.blockComment, t.lineComment, t.docComment, t.comment],
|
||||
color: '#757b93',
|
||||
},
|
||||
{ tag: tags.name, color: '#4699de' },
|
||||
{ tag: tags.variableName, color: '#31c434' },
|
||||
{ tag: tags.bool, color: '#e864f6' },
|
||||
{ tag: tags.attributeName, color: '#8f68ff' },
|
||||
{ tag: tags.attributeValue, color: '#ff964b' },
|
||||
{ tag: [tags.keyword, tags.string], color: '#e8b045' },
|
||||
{ tag: tags.comment, color: '#cec4cc', fontStyle: 'italic' },
|
||||
{ tag: [t.name], color: '#4699de' },
|
||||
{ tag: [t.variableName], color: '#31c434' },
|
||||
{ tag: [t.bool], color: '#e864f6' },
|
||||
{ tag: [t.attributeName], color: '#8f68ff' },
|
||||
{ tag: [t.attributeValue], color: '#ff964b' },
|
||||
{ tag: [t.string], color: '#e8b045' },
|
||||
{ tag: [t.keyword, t.meta], color: '#45e8a4' },
|
||||
{ tag: [t.comment], color: '#cec4cc', fontStyle: 'italic' },
|
||||
]);
|
||||
|
||||
const syntaxExtensions: Record<string, LanguageSupport> = {
|
||||
'application/json': json(),
|
||||
'application/javascript': javascript(),
|
||||
'text/html': html(),
|
||||
// export const defaultHighlightStyle = HighlightStyle.define([
|
||||
// { tag: t.meta, color: '#404740' },
|
||||
// { tag: t.link, textDecoration: 'underline' },
|
||||
// { tag: t.heading, textDecoration: 'underline', fontWeight: 'bold' },
|
||||
// { tag: t.emphasis, fontStyle: 'italic' },
|
||||
// { tag: t.strong, fontWeight: 'bold' },
|
||||
// { tag: t.strikethrough, textDecoration: 'line-through' },
|
||||
// { tag: t.keyword, color: '#708' },
|
||||
// { tag: [t.atom, t.bool, t.url, t.contentSeparator, t.labelName], color: '#219' },
|
||||
// { tag: [t.literal, t.inserted], color: '#164' },
|
||||
// { tag: [t.string, t.deleted], color: '#a11' },
|
||||
// { tag: [t.regexp, t.escape, t.special(t.string)], color: '#e40' },
|
||||
// { tag: t.definition(t.variableName), color: '#00f' },
|
||||
// { tag: t.local(t.variableName), color: '#30a' },
|
||||
// { tag: [t.typeName, t.namespace], color: '#085' },
|
||||
// { tag: t.className, color: '#167' },
|
||||
// { tag: [t.special(t.variableName), t.macroName], color: '#256' },
|
||||
// { tag: t.definition(t.propertyName), color: '#00c' },
|
||||
// { tag: t.comment, color: '#940' },
|
||||
// { tag: t.invalid, color: '#f00' },
|
||||
// ]);
|
||||
|
||||
const syntaxExtensions: Record<string, { base: LanguageSupport; ext: any[] }> = {
|
||||
'application/json': { base: json(), ext: [] },
|
||||
'application/javascript': { base: javascript(), ext: [] },
|
||||
'text/html': { base: html(), ext: [] },
|
||||
};
|
||||
|
||||
export function syntaxExtension(contentType: string): LanguageSupport | undefined {
|
||||
return syntaxExtensions[contentType];
|
||||
export function syntaxExtension({
|
||||
contentType,
|
||||
useTemplating,
|
||||
}: {
|
||||
contentType: string;
|
||||
useTemplating?: boolean;
|
||||
}) {
|
||||
const { base, ext } = syntaxExtensions[contentType] ?? { base: json(), ext: [] };
|
||||
if (!useTemplating) {
|
||||
return [base];
|
||||
}
|
||||
|
||||
const mixedTwigParser = twigParser.configure({
|
||||
props: [
|
||||
// Add basic folding/indent metadata
|
||||
foldNodeProp.add({ Conditional: foldInside }),
|
||||
indentNodeProp.add({
|
||||
Conditional: (cx) => {
|
||||
const closed = /^\s*\{% endif/.test(cx.textAfter);
|
||||
return cx.lineIndent(cx.node.from) + (closed ? 0 : cx.unit);
|
||||
},
|
||||
}),
|
||||
],
|
||||
wrap: parseMixed((node) => {
|
||||
return node.type.isTop
|
||||
? {
|
||||
parser: base.language.parser,
|
||||
overlay: (node) => node.type.name == 'Text',
|
||||
}
|
||||
: null;
|
||||
}),
|
||||
});
|
||||
|
||||
const twigLanguage = LRLanguage.define({ parser: mixedTwigParser });
|
||||
return [twigLanguage, placeholders, base.support, ...ext];
|
||||
}
|
||||
|
||||
export const baseExtensions = [
|
||||
@@ -78,7 +140,6 @@ export const baseExtensions = [
|
||||
dropCursor(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion(),
|
||||
|
||||
7
src-web/components/Editor/twig/twig-highlight.ts
Normal file
7
src-web/components/Editor/twig/twig-highlight.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { styleTags, tags as t } from '@lezer/highlight';
|
||||
|
||||
export const twigHighlight = styleTags({
|
||||
'if endif': t.controlKeyword,
|
||||
'{{ }} {% %}': t.meta,
|
||||
DirectiveContent: t.variableName,
|
||||
});
|
||||
28
src-web/components/Editor/twig/twig.grammar
Normal file
28
src-web/components/Editor/twig/twig.grammar
Normal file
@@ -0,0 +1,28 @@
|
||||
// Very crude grammar for a subset of Twig templating syntax
|
||||
|
||||
@top Template { (directive | Text)* }
|
||||
|
||||
directive {
|
||||
// Insert |
|
||||
// Conditional { ConditionalOpen (directive | Text)* ConditionalClose }
|
||||
Insert
|
||||
}
|
||||
|
||||
@skip {space} {
|
||||
Insert { "{{" DirectiveContent "}}" }
|
||||
// ConditionalOpen { "{%" kw<"if"> DirectiveContent "%}" }
|
||||
// ConditionalClose { "{%" kw<"endif"> "%}" }
|
||||
}
|
||||
|
||||
kw<word> { @specialize[@name={word}]<Identifier, word> }
|
||||
|
||||
@tokens {
|
||||
Identifier { @asciiLetter+ }
|
||||
Text { ![{] Text? | "{" (@eof | ![%{] Text?) }
|
||||
space { @whitespace+ }
|
||||
DirectiveContent { ![%}] DirectiveContent? | $[%}] (@eof | ![}] DirectiveContent?) }
|
||||
@precedence { space DirectiveContent }
|
||||
"{{" "}}" // "{%" "%}"
|
||||
}
|
||||
|
||||
@external propSource twigHighlight from "./twig-highlight.ts"
|
||||
6
src-web/components/Editor/twig/twig.terms.ts
Normal file
6
src-web/components/Editor/twig/twig.terms.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
||||
export const
|
||||
Template = 1,
|
||||
Insert = 2,
|
||||
DirectiveContent = 4,
|
||||
Text = 6
|
||||
19
src-web/components/Editor/twig/twig.ts
Normal file
19
src-web/components/Editor/twig/twig.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
||||
import { LRParser } from '@lezer/lr';
|
||||
import { twigHighlight } from './twig-highlight';
|
||||
export const parser = LRParser.deserialize({
|
||||
version: 14,
|
||||
states: "zQVOPOOO_QQO'#C^OOOO'#Cc'#CcQVOPOOOdQQO,58xOOOO-E6a-E6aOOOO1G.d1G.d",
|
||||
stateData: 'l~OYOS~ORPOUQO~OSSO~OTUO~OYS~',
|
||||
goto: 'cWPPXPPPP]TQORQRORTR',
|
||||
nodeNames: '⚠ Template Insert {{ DirectiveContent }} Text',
|
||||
maxTerm: 10,
|
||||
propSources: [twigHighlight],
|
||||
skippedNodes: [0],
|
||||
repeatNodeCount: 1,
|
||||
tokenData:
|
||||
",gRRmOX!|X^'u^p!|pq'uqu!|uv#pv#o!|#o#p)y#p#q!|#q#r+_#r#y!|#y#z'u#z$f!|$f$g'u$g#BY!|#BY#BZ'u#BZ$IS!|$IS$I_'u$I_$I|!|$I|$JO'u$JO$JT!|$JT$JU'u$JU$KV!|$KV$KW'u$KW&FU!|&FU&FV'u&FV;'S!|;'S;=`&f<%lO!|R#TXUPSQOu!|uv#pv#o!|#o#p$b#p#q!|#q#r#p#r;'S!|;'S;=`&f<%lO!|R#uXUPO#o!|#o#p$b#p#q!|#q#r&q#r;'S!|;'S;=`&f<%l~!|~O!|~~&aR$gZSQOu!|uv%Yv#o!|#o#p%o#p#q!|#q#r#p#r;'S!|;'S;=`&f<%l~!|~O!|~~&lQ%]UO#q%o#r;'S%o;'S;=`&Z<%l~%o~O%o~~&aQ%tVSQOu%ouv%Yv#q%o#q#r%Y#r;'S%o;'S;=`&Z<%lO%oQ&^P;=`<%l%oQ&fOSQR&iP;=`<%l!|P&qOUPP&vTUPO#o&q#o#p'V#p;'S&q;'S;=`'o<%lO&qP'YVOu&qv#o&q#p;'S&q;'S;=`'o<%l~&q~O&q~~&lP'rP;=`<%l&qR(OmUPYQSQOX!|X^'u^p!|pq'uqu!|uv#pv#o!|#o#p$b#p#q!|#q#r#p#r#y!|#y#z'u#z$f!|$f$g'u$g#BY!|#BY#BZ'u#BZ$IS!|$IS$I_'u$I_$I|!|$I|$JO'u$JO$JT!|$JT$JU'u$JU$KV!|$KV$KW'u$KW&FU!|&FU&FV'u&FV;'S!|;'S;=`&f<%lO!|R*OZSQOu!|uv%Yv#o!|#o#p*q#p#q!|#q#r#p#r;'S!|;'S;=`&f<%l~!|~O!|~~&lR*xVRPSQOu%ouv%Yv#q%o#q#r%Y#r;'S%o;'S;=`&Z<%lO%oR+dXUPO#o!|#o#p$b#p#q!|#q#r,P#r;'S!|;'S;=`&f<%l~!|~O!|~~&aR,WTTQUPO#o&q#o#p'V#p;'S&q;'S;=`'o<%lO&q",
|
||||
tokenizers: [0, 1],
|
||||
topRules: { Template: [0, 1] },
|
||||
tokenPrec: 25,
|
||||
});
|
||||
84
src-web/components/Editor/widgets.ts
Normal file
84
src-web/components/Editor/widgets.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import {
|
||||
Decoration,
|
||||
DecorationSet,
|
||||
EditorView,
|
||||
MatchDecorator,
|
||||
ViewPlugin,
|
||||
ViewUpdate,
|
||||
WidgetType,
|
||||
} from '@codemirror/view';
|
||||
|
||||
class PlaceholderWidget extends WidgetType {
|
||||
constructor(readonly name: string) {
|
||||
super();
|
||||
}
|
||||
eq(other: PlaceholderWidget) {
|
||||
return this.name == other.name;
|
||||
}
|
||||
toDOM() {
|
||||
const elt = document.createElement('span');
|
||||
elt.className = 'placeholder-widget';
|
||||
elt.textContent = this.name;
|
||||
return elt;
|
||||
}
|
||||
ignoreEvent() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a custom MatchDecorator that will not decorate a match if the selection is inside it
|
||||
*/
|
||||
class BetterMatchDecorator extends MatchDecorator {
|
||||
updateDeco(update: ViewUpdate, deco: DecorationSet): DecorationSet {
|
||||
if (!update.startState.selection.eq(update.state.selection)) {
|
||||
return super.createDeco(update.view);
|
||||
} else {
|
||||
return super.updateDeco(update, deco);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const placeholderMatcher = new BetterMatchDecorator({
|
||||
regexp: /\{\{\s*([^}\s]+)\s*}}/g,
|
||||
decoration(match, view, matchStartPos) {
|
||||
const matchEndPos = matchStartPos + match[0].length - 1;
|
||||
|
||||
// Don't decorate if the cursor is inside the match
|
||||
for (const r of view.state.selection.ranges) {
|
||||
if (r.from > matchStartPos && r.to <= matchEndPos) return null;
|
||||
}
|
||||
|
||||
const groupMatch = match[1];
|
||||
if (groupMatch == null) {
|
||||
// Should never happen, but make TS happy
|
||||
console.warn('Group match was empty', match);
|
||||
return null;
|
||||
}
|
||||
|
||||
return Decoration.replace({
|
||||
inclusive: true,
|
||||
widget: new PlaceholderWidget(groupMatch),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const placeholders = ViewPlugin.fromClass(
|
||||
class {
|
||||
placeholders: DecorationSet;
|
||||
constructor(view: EditorView) {
|
||||
this.placeholders = placeholderMatcher.createDeco(view);
|
||||
}
|
||||
update(update: ViewUpdate) {
|
||||
console.log('VIEW UPDATE', update);
|
||||
this.placeholders = placeholderMatcher.updateDeco(update, this.placeholders);
|
||||
}
|
||||
},
|
||||
{
|
||||
decorations: (instance) => instance.placeholders,
|
||||
provide: (plugin) =>
|
||||
EditorView.atomicRanges.of((view) => {
|
||||
return view.plugin(plugin)?.placeholders || Decoration.none;
|
||||
}),
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user