diff options
Diffstat (limited to 'extension/react-app')
27 files changed, 1865 insertions, 1318 deletions
| diff --git a/extension/react-app/index.html b/extension/react-app/index.html index e0d1c840..043c307e 100644 --- a/extension/react-app/index.html +++ b/extension/react-app/index.html @@ -2,7 +2,7 @@  <html lang="en">    <head>      <meta charset="UTF-8" /> -    <link rel="icon" type="image/svg+xml" href="/vite.svg" /> +    <link rel="icon" type="image/svg+xml" href="/play_button.png" />      <meta name="viewport" content="width=device-width, initial-scale=1.0" />      <title>Vite + React + TS</title>    </head> diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index 7316581d..13e02e86 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -11,12 +11,12 @@          "@styled-icons/heroicons-outline": "^10.47.0",          "@styled-icons/heroicons-solid": "^10.47.0",          "@types/vscode-webview": "^1.57.1", +        "@uiw/react-markdown-preview": "^4.1.13",          "downshift": "^7.6.0",          "posthog-js": "^1.58.0",          "prismjs": "^1.29.0",          "react": "^18.2.0",          "react-dom": "^18.2.0", -        "react-markdown": "^8.0.5",          "react-redux": "^8.0.5",          "react-switch": "^7.0.0",          "react-syntax-highlighter": "^15.5.0", @@ -963,6 +963,16 @@        "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",        "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="      }, +    "node_modules/@types/parse5": { +      "version": "6.0.3", +      "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", +      "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" +    }, +    "node_modules/@types/prismjs": { +      "version": "1.26.0", +      "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz", +      "integrity": "sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==" +    },      "node_modules/@types/prop-types": {        "version": "15.7.5",        "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -1027,6 +1037,34 @@        "resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz",        "integrity": "sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ=="      }, +    "node_modules/@uiw/copy-to-clipboard": { +      "version": "1.0.15", +      "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.15.tgz", +      "integrity": "sha512-1bbGZ3T+SGmA07BoVPK4UCUDcowDN/moctviJGQexfOc9qL8TMLDQPr7mTPvDKhgJkgnlKkAQNFU8PiarIi9sQ==" +    }, +    "node_modules/@uiw/react-markdown-preview": { +      "version": "4.1.13", +      "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-4.1.13.tgz", +      "integrity": "sha512-fmIGvBpK6HJyDFf7EokjZSIS0713Bq5KwhOsZ8IkbCMYDcDThFlmMkTTqyzGjL3phrkP9ED5O63WSILzefqe6A==", +      "dependencies": { +        "@babel/runtime": "^7.17.2", +        "@uiw/copy-to-clipboard": "~1.0.12", +        "react-markdown": "~8.0.0", +        "rehype-attr": "~2.1.0", +        "rehype-autolink-headings": "~6.1.1", +        "rehype-ignore": "^1.0.1", +        "rehype-prism-plus": "~1.5.0", +        "rehype-raw": "^6.1.1", +        "rehype-rewrite": "~3.0.6", +        "rehype-slug": "~5.1.0", +        "remark-gfm": "~3.0.1", +        "unist-util-visit": "^4.1.0" +      }, +      "peerDependencies": { +        "react": ">=16.8.0", +        "react-dom": ">=16.8.0" +      } +    },      "node_modules/@vitejs/plugin-react-swc": {        "version": "3.2.0",        "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz", @@ -1163,6 +1201,15 @@          "url": "https://github.com/sponsors/wooorm"        }      }, +    "node_modules/bcp-47-match": { +      "version": "2.0.3", +      "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", +      "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/binary-extensions": {        "version": "2.2.0",        "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1172,6 +1219,11 @@          "node": ">=8"        }      }, +    "node_modules/boolbase": { +      "version": "1.0.0", +      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", +      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" +    },      "node_modules/braces": {        "version": "3.0.2",        "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -1245,6 +1297,15 @@          }        ]      }, +    "node_modules/ccount": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", +      "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/chalk": {        "version": "2.4.2",        "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1370,6 +1431,11 @@          "node": ">=4"        }      }, +    "node_modules/css-selector-parser": { +      "version": "1.4.1", +      "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", +      "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==" +    },      "node_modules/css-to-react-native": {        "version": "3.2.0",        "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", @@ -1473,6 +1539,18 @@          "node": ">=0.3.1"        }      }, +    "node_modules/direction": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", +      "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", +      "bin": { +        "direction": "cli.js" +      }, +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/dlv": {        "version": "1.1.3",        "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -1684,6 +1762,11 @@        "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",        "dev": true      }, +    "node_modules/github-slugger": { +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", +      "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" +    },      "node_modules/glob-parent": {        "version": "6.0.2",        "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1729,6 +1812,86 @@          "node": ">=4"        }      }, +    "node_modules/hast-util-from-parse5": { +      "version": "7.1.2", +      "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", +      "integrity": "sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0", +        "hastscript": "^7.0.0", +        "property-information": "^6.0.0", +        "vfile": "^5.0.0", +        "vfile-location": "^4.0.0", +        "web-namespaces": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": { +      "version": "3.1.1", +      "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", +      "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", +      "dependencies": { +        "@types/hast": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-from-parse5/node_modules/hastscript": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", +      "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "hast-util-parse-selector": "^3.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-has-property": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-2.0.1.tgz", +      "integrity": "sha512-X2+RwZIMTMKpXUzlotatPzWj8bspCymtXH3cfG3iQKV+wPF53Vgaqxi/eLqGck0wKq1kS9nvoB1wchbCPEL8sg==", +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-heading-rank": { +      "version": "2.1.1", +      "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-2.1.1.tgz", +      "integrity": "sha512-iAuRp+ESgJoRFJbSyaqsfvJDY6zzmFoEnL1gtz1+U8gKtGGj1p0CVlysuUAUjq95qlZESHINLThwJzNGmgGZxA==", +      "dependencies": { +        "@types/hast": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-is-element": { +      "version": "2.1.3", +      "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz", +      "integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/hast-util-parse-selector": {        "version": "2.2.5",        "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", @@ -1738,6 +1901,83 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/hast-util-raw": { +      "version": "7.2.3", +      "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz", +      "integrity": "sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "@types/parse5": "^6.0.0", +        "hast-util-from-parse5": "^7.0.0", +        "hast-util-to-parse5": "^7.0.0", +        "html-void-elements": "^2.0.0", +        "parse5": "^6.0.0", +        "unist-util-position": "^4.0.0", +        "unist-util-visit": "^4.0.0", +        "vfile": "^5.0.0", +        "web-namespaces": "^2.0.0", +        "zwitch": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-select": { +      "version": "5.0.5", +      "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-5.0.5.tgz", +      "integrity": "sha512-QQhWMhgTFRhCaQdgTKzZ5g31GLQ9qRb1hZtDPMqQaOhpLBziWcshUS0uCR5IJ0U1jrK/mxg35fmcq+Dp/Cy2Aw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0", +        "bcp-47-match": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "css-selector-parser": "^1.0.0", +        "direction": "^2.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-to-string": "^2.0.0", +        "hast-util-whitespace": "^2.0.0", +        "not": "^0.1.0", +        "nth-check": "^2.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0", +        "unist-util-visit": "^4.0.0", +        "zwitch": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-to-parse5": { +      "version": "7.1.0", +      "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", +      "integrity": "sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0", +        "web-namespaces": "^2.0.0", +        "zwitch": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/hast-util-to-string": { +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-2.0.0.tgz", +      "integrity": "sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A==", +      "dependencies": { +        "@types/hast": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/hast-util-whitespace": {        "version": "2.0.1",        "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -1814,6 +2054,15 @@        "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",        "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="      }, +    "node_modules/html-void-elements": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", +      "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/inline-style-parser": {        "version": "0.1.1",        "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", @@ -1995,6 +2244,15 @@        "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",        "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="      }, +    "node_modules/longest-streak": { +      "version": "3.1.0", +      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", +      "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/loose-envify": {        "version": "1.4.0",        "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2019,6 +2277,15 @@          "url": "https://github.com/sponsors/wooorm"        }      }, +    "node_modules/markdown-table": { +      "version": "3.0.3", +      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", +      "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/mdast-util-definitions": {        "version": "5.1.2",        "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -2033,6 +2300,32 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/mdast-util-find-and-replace": { +      "version": "2.2.2", +      "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", +      "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "escape-string-regexp": "^5.0.0", +        "unist-util-is": "^5.0.0", +        "unist-util-visit-parents": "^5.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { +      "version": "5.0.0", +      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", +      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", +      "engines": { +        "node": ">=12" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    },      "node_modules/mdast-util-from-markdown": {        "version": "1.3.0",        "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz", @@ -2056,6 +2349,107 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/mdast-util-gfm": { +      "version": "2.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", +      "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", +      "dependencies": { +        "mdast-util-from-markdown": "^1.0.0", +        "mdast-util-gfm-autolink-literal": "^1.0.0", +        "mdast-util-gfm-footnote": "^1.0.0", +        "mdast-util-gfm-strikethrough": "^1.0.0", +        "mdast-util-gfm-table": "^1.0.0", +        "mdast-util-gfm-task-list-item": "^1.0.0", +        "mdast-util-to-markdown": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-gfm-autolink-literal": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", +      "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "ccount": "^2.0.0", +        "mdast-util-find-and-replace": "^2.0.0", +        "micromark-util-character": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-gfm-footnote": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", +      "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0", +        "micromark-util-normalize-identifier": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-gfm-strikethrough": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", +      "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-gfm-table": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", +      "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "markdown-table": "^3.0.0", +        "mdast-util-from-markdown": "^1.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-gfm-task-list-item": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", +      "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/mdast-util-phrasing": { +      "version": "3.0.1", +      "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", +      "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "unist-util-is": "^5.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/mdast-util-to-hast": {        "version": "12.3.0",        "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", @@ -2075,6 +2469,25 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/mdast-util-to-markdown": { +      "version": "1.5.0", +      "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", +      "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "@types/unist": "^2.0.0", +        "longest-streak": "^3.0.0", +        "mdast-util-phrasing": "^3.0.0", +        "mdast-util-to-string": "^3.0.0", +        "micromark-util-decode-string": "^1.0.0", +        "unist-util-visit": "^4.0.0", +        "zwitch": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/mdast-util-to-string": {        "version": "3.1.1",        "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz", @@ -2163,6 +2576,120 @@          "uvu": "^0.5.0"        }      }, +    "node_modules/micromark-extension-gfm": { +      "version": "2.0.3", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", +      "integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==", +      "dependencies": { +        "micromark-extension-gfm-autolink-literal": "^1.0.0", +        "micromark-extension-gfm-footnote": "^1.0.0", +        "micromark-extension-gfm-strikethrough": "^1.0.0", +        "micromark-extension-gfm-table": "^1.0.0", +        "micromark-extension-gfm-tagfilter": "^1.0.0", +        "micromark-extension-gfm-task-list-item": "^1.0.0", +        "micromark-util-combine-extensions": "^1.0.0", +        "micromark-util-types": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-autolink-literal": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz", +      "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", +      "dependencies": { +        "micromark-util-character": "^1.0.0", +        "micromark-util-sanitize-uri": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-footnote": { +      "version": "1.1.2", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", +      "integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==", +      "dependencies": { +        "micromark-core-commonmark": "^1.0.0", +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-normalize-identifier": "^1.0.0", +        "micromark-util-sanitize-uri": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-strikethrough": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", +      "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", +      "dependencies": { +        "micromark-util-chunked": "^1.0.0", +        "micromark-util-classify-character": "^1.0.0", +        "micromark-util-resolve-all": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-table": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", +      "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", +      "dependencies": { +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-tagfilter": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", +      "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", +      "dependencies": { +        "micromark-util-types": "^1.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/micromark-extension-gfm-task-list-item": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", +      "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", +      "dependencies": { +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/micromark-factory-destination": {        "version": "1.0.0",        "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", @@ -2589,6 +3116,22 @@          "node": ">=0.10.0"        }      }, +    "node_modules/not": { +      "version": "0.1.0", +      "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", +      "integrity": "sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA==" +    }, +    "node_modules/nth-check": { +      "version": "2.1.1", +      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", +      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", +      "dependencies": { +        "boolbase": "^1.0.0" +      }, +      "funding": { +        "url": "https://github.com/fb55/nth-check?sponsor=1" +      } +    },      "node_modules/object-assign": {        "version": "4.1.1",        "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2632,6 +3175,16 @@          "url": "https://github.com/sponsors/wooorm"        }      }, +    "node_modules/parse-numeric-range": { +      "version": "1.3.0", +      "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", +      "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" +    }, +    "node_modules/parse5": { +      "version": "6.0.1", +      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", +      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" +    },      "node_modules/path-parse": {        "version": "1.0.7",        "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -3047,6 +3600,257 @@        "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",        "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="      }, +    "node_modules/rehype-attr": { +      "version": "2.1.4", +      "resolved": "https://registry.npmjs.org/rehype-attr/-/rehype-attr-2.1.4.tgz", +      "integrity": "sha512-iAeaL5JyF4XxkcvWzpi/0SAF7iV7qOTaHS56tJuEsXziQc3+PEmMn65kV8OFgbO9mRVY7J1fRC/aLvot1PsNkg==", +      "dependencies": { +        "unified": "~10.1.1", +        "unist-util-visit": "~4.1.0" +      }, +      "engines": { +        "node": "^12.20.0 || ^14.13.1 || >=16.0.0" +      } +    }, +    "node_modules/rehype-autolink-headings": { +      "version": "6.1.1", +      "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-6.1.1.tgz", +      "integrity": "sha512-NMYzZIsHM3sA14nC5rAFuUPIOfg+DFmf9EY1YMhaNlB7+3kK/ZlE6kqPfuxr1tsJ1XWkTrMtMoyHosU70d35mA==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "extend": "^3.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-heading-rank": "^2.0.0", +        "hast-util-is-element": "^2.0.0", +        "unified": "^10.0.0", +        "unist-util-visit": "^4.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/rehype-ignore": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-1.0.5.tgz", +      "integrity": "sha512-JQXS5eDwXaYKwB8JEYFJJA/YvGi0sSNUOYuiURMtuPTg8tuWHFB91JMYLbImH1FyvyGQM4fIBqNMAPB50WR2Bw==", +      "dependencies": { +        "hast-util-select": "^5.0.5", +        "unified": "^10.1.2", +        "unist-util-visit": "^4.1.2" +      }, +      "engines": { +        "node": "^14.13.1 || >=16.0.0" +      } +    }, +    "node_modules/rehype-parse": { +      "version": "8.0.4", +      "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.4.tgz", +      "integrity": "sha512-MJJKONunHjoTh4kc3dsM1v3C9kGrrxvA3U8PxZlP2SjH8RNUSrb+lF7Y0KVaUDnGH2QZ5vAn7ulkiajM9ifuqg==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "hast-util-from-parse5": "^7.0.0", +        "parse5": "^6.0.0", +        "unified": "^10.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/rehype-prism-plus": { +      "version": "1.5.1", +      "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-1.5.1.tgz", +      "integrity": "sha512-mowYefSfrIkMMxkb0fwuEXlvc5nA9b1vQ6mzujM81Qx28RI0mo7jCHsBZ2tJ4eIJKXdFn+EdPkZZBGB10K02vg==", +      "dependencies": { +        "hast-util-to-string": "^2.0.0", +        "parse-numeric-range": "^1.3.0", +        "refractor": "^4.7.0", +        "rehype-parse": "^8.0.2", +        "unist-util-filter": "^4.0.0", +        "unist-util-visit": "^4.0.0" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/character-entities-legacy": { +      "version": "3.0.0", +      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", +      "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/character-reference-invalid": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", +      "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/hast-util-parse-selector": { +      "version": "3.1.1", +      "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", +      "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", +      "dependencies": { +        "@types/hast": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/hastscript": { +      "version": "7.2.0", +      "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", +      "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "hast-util-parse-selector": "^3.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/is-alphabetical": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", +      "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/is-alphanumerical": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", +      "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", +      "dependencies": { +        "is-alphabetical": "^2.0.0", +        "is-decimal": "^2.0.0" +      }, +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/is-decimal": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", +      "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/is-hexadecimal": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", +      "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/parse-entities": { +      "version": "4.0.1", +      "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", +      "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", +      "dependencies": { +        "@types/unist": "^2.0.0", +        "character-entities": "^2.0.0", +        "character-entities-legacy": "^3.0.0", +        "character-reference-invalid": "^2.0.0", +        "decode-named-character-reference": "^1.0.0", +        "is-alphanumerical": "^2.0.0", +        "is-decimal": "^2.0.0", +        "is-hexadecimal": "^2.0.0" +      }, +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-prism-plus/node_modules/refractor": { +      "version": "4.8.1", +      "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.8.1.tgz", +      "integrity": "sha512-/fk5sI0iTgFYlmVGYVew90AoYnNMP6pooClx/XKqyeeCQXrL0Kvgn8V0VEht5ccdljbzzF1i3Q213gcntkRExg==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "@types/prismjs": "^1.0.0", +        "hastscript": "^7.0.0", +        "parse-entities": "^4.0.0" +      }, +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    }, +    "node_modules/rehype-raw": { +      "version": "6.1.1", +      "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", +      "integrity": "sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "hast-util-raw": "^7.2.0", +        "unified": "^10.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/rehype-rewrite": { +      "version": "3.0.6", +      "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-3.0.6.tgz", +      "integrity": "sha512-REDTNCvsKcAazy8IQWzKp66AhSUDSOIKssSCqNqCcT9sN7JCwAAm3mWGTUdUzq80ABuy8d0D6RBwbnewu1aY1g==", +      "dependencies": { +        "hast-util-select": "~5.0.1", +        "unified": "~10.1.1", +        "unist-util-visit": "~4.1.0" +      }, +      "engines": { +        "node": "^12.20.0 || ^14.13.1 || >=16.0.0" +      } +    }, +    "node_modules/rehype-slug": { +      "version": "5.1.0", +      "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-5.1.0.tgz", +      "integrity": "sha512-Gf91dJoXneiorNEnn+Phx97CO7oRMrpi+6r155tTxzGuLtm+QrI4cTwCa9e1rtePdL4i9tSO58PeSS6HWfgsiw==", +      "dependencies": { +        "@types/hast": "^2.0.0", +        "github-slugger": "^2.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-heading-rank": "^2.0.0", +        "hast-util-to-string": "^2.0.0", +        "unified": "^10.0.0", +        "unist-util-visit": "^4.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    }, +    "node_modules/remark-gfm": { +      "version": "3.0.1", +      "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", +      "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", +      "dependencies": { +        "@types/mdast": "^3.0.0", +        "mdast-util-gfm": "^2.0.0", +        "micromark-extension-gfm": "^2.0.0", +        "unified": "^10.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/remark-parse": {        "version": "10.0.1",        "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -3365,6 +4169,16 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/unist-util-filter": { +      "version": "4.0.1", +      "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-4.0.1.tgz", +      "integrity": "sha512-RynicUM/vbOSTSiUK+BnaK9XMfmQUh6gyi7L6taNgc7FIf84GukXVV3ucGzEN/PhUUkdP5hb1MmXc+3cvPUm5Q==", +      "dependencies": { +        "@types/unist": "^2.0.0", +        "unist-util-is": "^5.0.0", +        "unist-util-visit-parents": "^5.0.0" +      } +    },      "node_modules/unist-util-generated": {        "version": "2.0.1",        "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", @@ -3517,6 +4331,19 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/vfile-location": { +      "version": "4.1.0", +      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz", +      "integrity": "sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==", +      "dependencies": { +        "@types/unist": "^2.0.0", +        "vfile": "^5.0.0" +      }, +      "funding": { +        "type": "opencollective", +        "url": "https://opencollective.com/unified" +      } +    },      "node_modules/vfile-message": {        "version": "3.1.4",        "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", @@ -3587,6 +4414,15 @@          "fs-extra": "^10.0.0"        }      }, +    "node_modules/web-namespaces": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", +      "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      } +    },      "node_modules/xtend": {        "version": "4.0.2",        "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -3603,6 +4439,15 @@        "engines": {          "node": ">= 6"        } +    }, +    "node_modules/zwitch": { +      "version": "2.0.4", +      "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", +      "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", +      "funding": { +        "type": "github", +        "url": "https://github.com/sponsors/wooorm" +      }      }    },    "dependencies": { @@ -4143,6 +4988,16 @@        "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",        "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="      }, +    "@types/parse5": { +      "version": "6.0.3", +      "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", +      "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" +    }, +    "@types/prismjs": { +      "version": "1.26.0", +      "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz", +      "integrity": "sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==" +    },      "@types/prop-types": {        "version": "15.7.5",        "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -4207,6 +5062,30 @@        "resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz",        "integrity": "sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ=="      }, +    "@uiw/copy-to-clipboard": { +      "version": "1.0.15", +      "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.15.tgz", +      "integrity": "sha512-1bbGZ3T+SGmA07BoVPK4UCUDcowDN/moctviJGQexfOc9qL8TMLDQPr7mTPvDKhgJkgnlKkAQNFU8PiarIi9sQ==" +    }, +    "@uiw/react-markdown-preview": { +      "version": "4.1.13", +      "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-4.1.13.tgz", +      "integrity": "sha512-fmIGvBpK6HJyDFf7EokjZSIS0713Bq5KwhOsZ8IkbCMYDcDThFlmMkTTqyzGjL3phrkP9ED5O63WSILzefqe6A==", +      "requires": { +        "@babel/runtime": "^7.17.2", +        "@uiw/copy-to-clipboard": "~1.0.12", +        "react-markdown": "~8.0.0", +        "rehype-attr": "~2.1.0", +        "rehype-autolink-headings": "~6.1.1", +        "rehype-ignore": "^1.0.1", +        "rehype-prism-plus": "~1.5.0", +        "rehype-raw": "^6.1.1", +        "rehype-rewrite": "~3.0.6", +        "rehype-slug": "~5.1.0", +        "remark-gfm": "~3.0.1", +        "unist-util-visit": "^4.1.0" +      } +    },      "@vitejs/plugin-react-swc": {        "version": "3.2.0",        "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz", @@ -4299,12 +5178,22 @@        "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",        "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="      }, +    "bcp-47-match": { +      "version": "2.0.3", +      "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", +      "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==" +    },      "binary-extensions": {        "version": "2.2.0",        "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",        "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",        "dev": true      }, +    "boolbase": { +      "version": "1.0.0", +      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", +      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" +    },      "braces": {        "version": "3.0.2",        "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -4343,6 +5232,11 @@        "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==",        "dev": true      }, +    "ccount": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", +      "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" +    },      "chalk": {        "version": "2.4.2",        "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -4436,6 +5330,11 @@        "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",        "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg=="      }, +    "css-selector-parser": { +      "version": "1.4.1", +      "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", +      "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==" +    },      "css-to-react-native": {        "version": "3.2.0",        "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", @@ -4506,6 +5405,11 @@        "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",        "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw=="      }, +    "direction": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", +      "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==" +    },      "dlv": {        "version": "1.1.3",        "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -4672,6 +5576,11 @@        "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",        "dev": true      }, +    "github-slugger": { +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", +      "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" +    },      "glob-parent": {        "version": "6.0.2",        "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4705,11 +5614,130 @@        "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",        "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="      }, +    "hast-util-from-parse5": { +      "version": "7.1.2", +      "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", +      "integrity": "sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==", +      "requires": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0", +        "hastscript": "^7.0.0", +        "property-information": "^6.0.0", +        "vfile": "^5.0.0", +        "vfile-location": "^4.0.0", +        "web-namespaces": "^2.0.0" +      }, +      "dependencies": { +        "hast-util-parse-selector": { +          "version": "3.1.1", +          "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", +          "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", +          "requires": { +            "@types/hast": "^2.0.0" +          } +        }, +        "hastscript": { +          "version": "7.2.0", +          "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", +          "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", +          "requires": { +            "@types/hast": "^2.0.0", +            "comma-separated-tokens": "^2.0.0", +            "hast-util-parse-selector": "^3.0.0", +            "property-information": "^6.0.0", +            "space-separated-tokens": "^2.0.0" +          } +        } +      } +    }, +    "hast-util-has-property": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-2.0.1.tgz", +      "integrity": "sha512-X2+RwZIMTMKpXUzlotatPzWj8bspCymtXH3cfG3iQKV+wPF53Vgaqxi/eLqGck0wKq1kS9nvoB1wchbCPEL8sg==" +    }, +    "hast-util-heading-rank": { +      "version": "2.1.1", +      "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-2.1.1.tgz", +      "integrity": "sha512-iAuRp+ESgJoRFJbSyaqsfvJDY6zzmFoEnL1gtz1+U8gKtGGj1p0CVlysuUAUjq95qlZESHINLThwJzNGmgGZxA==", +      "requires": { +        "@types/hast": "^2.0.0" +      } +    }, +    "hast-util-is-element": { +      "version": "2.1.3", +      "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz", +      "integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==", +      "requires": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0" +      } +    },      "hast-util-parse-selector": {        "version": "2.2.5",        "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",        "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ=="      }, +    "hast-util-raw": { +      "version": "7.2.3", +      "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz", +      "integrity": "sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==", +      "requires": { +        "@types/hast": "^2.0.0", +        "@types/parse5": "^6.0.0", +        "hast-util-from-parse5": "^7.0.0", +        "hast-util-to-parse5": "^7.0.0", +        "html-void-elements": "^2.0.0", +        "parse5": "^6.0.0", +        "unist-util-position": "^4.0.0", +        "unist-util-visit": "^4.0.0", +        "vfile": "^5.0.0", +        "web-namespaces": "^2.0.0", +        "zwitch": "^2.0.0" +      } +    }, +    "hast-util-select": { +      "version": "5.0.5", +      "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-5.0.5.tgz", +      "integrity": "sha512-QQhWMhgTFRhCaQdgTKzZ5g31GLQ9qRb1hZtDPMqQaOhpLBziWcshUS0uCR5IJ0U1jrK/mxg35fmcq+Dp/Cy2Aw==", +      "requires": { +        "@types/hast": "^2.0.0", +        "@types/unist": "^2.0.0", +        "bcp-47-match": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "css-selector-parser": "^1.0.0", +        "direction": "^2.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-to-string": "^2.0.0", +        "hast-util-whitespace": "^2.0.0", +        "not": "^0.1.0", +        "nth-check": "^2.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0", +        "unist-util-visit": "^4.0.0", +        "zwitch": "^2.0.0" +      } +    }, +    "hast-util-to-parse5": { +      "version": "7.1.0", +      "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", +      "integrity": "sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==", +      "requires": { +        "@types/hast": "^2.0.0", +        "comma-separated-tokens": "^2.0.0", +        "property-information": "^6.0.0", +        "space-separated-tokens": "^2.0.0", +        "web-namespaces": "^2.0.0", +        "zwitch": "^2.0.0" +      } +    }, +    "hast-util-to-string": { +      "version": "2.0.0", +      "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-2.0.0.tgz", +      "integrity": "sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A==", +      "requires": { +        "@types/hast": "^2.0.0" +      } +    },      "hast-util-whitespace": {        "version": "2.0.1",        "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -4767,6 +5795,11 @@          }        }      }, +    "html-void-elements": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", +      "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==" +    },      "inline-style-parser": {        "version": "0.1.1",        "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", @@ -4880,6 +5913,11 @@        "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",        "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="      }, +    "longest-streak": { +      "version": "3.1.0", +      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", +      "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==" +    },      "loose-envify": {        "version": "1.4.0",        "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4897,6 +5935,11 @@          "highlight.js": "~10.7.0"        }      }, +    "markdown-table": { +      "version": "3.0.3", +      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", +      "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==" +    },      "mdast-util-definitions": {        "version": "5.1.2",        "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -4907,6 +5950,24 @@          "unist-util-visit": "^4.0.0"        }      }, +    "mdast-util-find-and-replace": { +      "version": "2.2.2", +      "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", +      "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "escape-string-regexp": "^5.0.0", +        "unist-util-is": "^5.0.0", +        "unist-util-visit-parents": "^5.0.0" +      }, +      "dependencies": { +        "escape-string-regexp": { +          "version": "5.0.0", +          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", +          "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" +        } +      } +    },      "mdast-util-from-markdown": {        "version": "1.3.0",        "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz", @@ -4926,6 +5987,79 @@          "uvu": "^0.5.0"        }      }, +    "mdast-util-gfm": { +      "version": "2.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", +      "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", +      "requires": { +        "mdast-util-from-markdown": "^1.0.0", +        "mdast-util-gfm-autolink-literal": "^1.0.0", +        "mdast-util-gfm-footnote": "^1.0.0", +        "mdast-util-gfm-strikethrough": "^1.0.0", +        "mdast-util-gfm-table": "^1.0.0", +        "mdast-util-gfm-task-list-item": "^1.0.0", +        "mdast-util-to-markdown": "^1.0.0" +      } +    }, +    "mdast-util-gfm-autolink-literal": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", +      "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "ccount": "^2.0.0", +        "mdast-util-find-and-replace": "^2.0.0", +        "micromark-util-character": "^1.0.0" +      } +    }, +    "mdast-util-gfm-footnote": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", +      "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0", +        "micromark-util-normalize-identifier": "^1.0.0" +      } +    }, +    "mdast-util-gfm-strikethrough": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", +      "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      } +    }, +    "mdast-util-gfm-table": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", +      "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "markdown-table": "^3.0.0", +        "mdast-util-from-markdown": "^1.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      } +    }, +    "mdast-util-gfm-task-list-item": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", +      "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "mdast-util-to-markdown": "^1.3.0" +      } +    }, +    "mdast-util-phrasing": { +      "version": "3.0.1", +      "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", +      "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "unist-util-is": "^5.0.0" +      } +    },      "mdast-util-to-hast": {        "version": "12.3.0",        "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", @@ -4941,6 +6075,21 @@          "unist-util-visit": "^4.0.0"        }      }, +    "mdast-util-to-markdown": { +      "version": "1.5.0", +      "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", +      "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "@types/unist": "^2.0.0", +        "longest-streak": "^3.0.0", +        "mdast-util-phrasing": "^3.0.0", +        "mdast-util-to-string": "^3.0.0", +        "micromark-util-decode-string": "^1.0.0", +        "unist-util-visit": "^4.0.0", +        "zwitch": "^2.0.0" +      } +    },      "mdast-util-to-string": {        "version": "3.1.1",        "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz", @@ -5002,6 +6151,92 @@          "uvu": "^0.5.0"        }      }, +    "micromark-extension-gfm": { +      "version": "2.0.3", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", +      "integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==", +      "requires": { +        "micromark-extension-gfm-autolink-literal": "^1.0.0", +        "micromark-extension-gfm-footnote": "^1.0.0", +        "micromark-extension-gfm-strikethrough": "^1.0.0", +        "micromark-extension-gfm-table": "^1.0.0", +        "micromark-extension-gfm-tagfilter": "^1.0.0", +        "micromark-extension-gfm-task-list-item": "^1.0.0", +        "micromark-util-combine-extensions": "^1.0.0", +        "micromark-util-types": "^1.0.0" +      } +    }, +    "micromark-extension-gfm-autolink-literal": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz", +      "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", +      "requires": { +        "micromark-util-character": "^1.0.0", +        "micromark-util-sanitize-uri": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0" +      } +    }, +    "micromark-extension-gfm-footnote": { +      "version": "1.1.2", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", +      "integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==", +      "requires": { +        "micromark-core-commonmark": "^1.0.0", +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-normalize-identifier": "^1.0.0", +        "micromark-util-sanitize-uri": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      } +    }, +    "micromark-extension-gfm-strikethrough": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", +      "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", +      "requires": { +        "micromark-util-chunked": "^1.0.0", +        "micromark-util-classify-character": "^1.0.0", +        "micromark-util-resolve-all": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      } +    }, +    "micromark-extension-gfm-table": { +      "version": "1.0.7", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", +      "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", +      "requires": { +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      } +    }, +    "micromark-extension-gfm-tagfilter": { +      "version": "1.0.2", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", +      "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", +      "requires": { +        "micromark-util-types": "^1.0.0" +      } +    }, +    "micromark-extension-gfm-task-list-item": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", +      "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", +      "requires": { +        "micromark-factory-space": "^1.0.0", +        "micromark-util-character": "^1.0.0", +        "micromark-util-symbol": "^1.0.0", +        "micromark-util-types": "^1.0.0", +        "uvu": "^0.5.0" +      } +    },      "micromark-factory-destination": {        "version": "1.0.0",        "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", @@ -5217,6 +6452,19 @@        "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",        "dev": true      }, +    "not": { +      "version": "0.1.0", +      "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", +      "integrity": "sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA==" +    }, +    "nth-check": { +      "version": "2.1.1", +      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", +      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", +      "requires": { +        "boolbase": "^1.0.0" +      } +    },      "object-assign": {        "version": "4.1.1",        "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5248,6 +6496,16 @@          }        }      }, +    "parse-numeric-range": { +      "version": "1.3.0", +      "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", +      "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" +    }, +    "parse5": { +      "version": "6.0.1", +      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", +      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" +    },      "path-parse": {        "version": "1.0.7",        "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -5510,6 +6768,190 @@        "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",        "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="      }, +    "rehype-attr": { +      "version": "2.1.4", +      "resolved": "https://registry.npmjs.org/rehype-attr/-/rehype-attr-2.1.4.tgz", +      "integrity": "sha512-iAeaL5JyF4XxkcvWzpi/0SAF7iV7qOTaHS56tJuEsXziQc3+PEmMn65kV8OFgbO9mRVY7J1fRC/aLvot1PsNkg==", +      "requires": { +        "unified": "~10.1.1", +        "unist-util-visit": "~4.1.0" +      } +    }, +    "rehype-autolink-headings": { +      "version": "6.1.1", +      "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-6.1.1.tgz", +      "integrity": "sha512-NMYzZIsHM3sA14nC5rAFuUPIOfg+DFmf9EY1YMhaNlB7+3kK/ZlE6kqPfuxr1tsJ1XWkTrMtMoyHosU70d35mA==", +      "requires": { +        "@types/hast": "^2.0.0", +        "extend": "^3.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-heading-rank": "^2.0.0", +        "hast-util-is-element": "^2.0.0", +        "unified": "^10.0.0", +        "unist-util-visit": "^4.0.0" +      } +    }, +    "rehype-ignore": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-1.0.5.tgz", +      "integrity": "sha512-JQXS5eDwXaYKwB8JEYFJJA/YvGi0sSNUOYuiURMtuPTg8tuWHFB91JMYLbImH1FyvyGQM4fIBqNMAPB50WR2Bw==", +      "requires": { +        "hast-util-select": "^5.0.5", +        "unified": "^10.1.2", +        "unist-util-visit": "^4.1.2" +      } +    }, +    "rehype-parse": { +      "version": "8.0.4", +      "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.4.tgz", +      "integrity": "sha512-MJJKONunHjoTh4kc3dsM1v3C9kGrrxvA3U8PxZlP2SjH8RNUSrb+lF7Y0KVaUDnGH2QZ5vAn7ulkiajM9ifuqg==", +      "requires": { +        "@types/hast": "^2.0.0", +        "hast-util-from-parse5": "^7.0.0", +        "parse5": "^6.0.0", +        "unified": "^10.0.0" +      } +    }, +    "rehype-prism-plus": { +      "version": "1.5.1", +      "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-1.5.1.tgz", +      "integrity": "sha512-mowYefSfrIkMMxkb0fwuEXlvc5nA9b1vQ6mzujM81Qx28RI0mo7jCHsBZ2tJ4eIJKXdFn+EdPkZZBGB10K02vg==", +      "requires": { +        "hast-util-to-string": "^2.0.0", +        "parse-numeric-range": "^1.3.0", +        "refractor": "^4.7.0", +        "rehype-parse": "^8.0.2", +        "unist-util-filter": "^4.0.0", +        "unist-util-visit": "^4.0.0" +      }, +      "dependencies": { +        "character-entities-legacy": { +          "version": "3.0.0", +          "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", +          "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" +        }, +        "character-reference-invalid": { +          "version": "2.0.1", +          "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", +          "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" +        }, +        "hast-util-parse-selector": { +          "version": "3.1.1", +          "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", +          "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", +          "requires": { +            "@types/hast": "^2.0.0" +          } +        }, +        "hastscript": { +          "version": "7.2.0", +          "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", +          "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", +          "requires": { +            "@types/hast": "^2.0.0", +            "comma-separated-tokens": "^2.0.0", +            "hast-util-parse-selector": "^3.0.0", +            "property-information": "^6.0.0", +            "space-separated-tokens": "^2.0.0" +          } +        }, +        "is-alphabetical": { +          "version": "2.0.1", +          "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", +          "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==" +        }, +        "is-alphanumerical": { +          "version": "2.0.1", +          "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", +          "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", +          "requires": { +            "is-alphabetical": "^2.0.0", +            "is-decimal": "^2.0.0" +          } +        }, +        "is-decimal": { +          "version": "2.0.1", +          "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", +          "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==" +        }, +        "is-hexadecimal": { +          "version": "2.0.1", +          "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", +          "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==" +        }, +        "parse-entities": { +          "version": "4.0.1", +          "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", +          "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", +          "requires": { +            "@types/unist": "^2.0.0", +            "character-entities": "^2.0.0", +            "character-entities-legacy": "^3.0.0", +            "character-reference-invalid": "^2.0.0", +            "decode-named-character-reference": "^1.0.0", +            "is-alphanumerical": "^2.0.0", +            "is-decimal": "^2.0.0", +            "is-hexadecimal": "^2.0.0" +          } +        }, +        "refractor": { +          "version": "4.8.1", +          "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.8.1.tgz", +          "integrity": "sha512-/fk5sI0iTgFYlmVGYVew90AoYnNMP6pooClx/XKqyeeCQXrL0Kvgn8V0VEht5ccdljbzzF1i3Q213gcntkRExg==", +          "requires": { +            "@types/hast": "^2.0.0", +            "@types/prismjs": "^1.0.0", +            "hastscript": "^7.0.0", +            "parse-entities": "^4.0.0" +          } +        } +      } +    }, +    "rehype-raw": { +      "version": "6.1.1", +      "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", +      "integrity": "sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==", +      "requires": { +        "@types/hast": "^2.0.0", +        "hast-util-raw": "^7.2.0", +        "unified": "^10.0.0" +      } +    }, +    "rehype-rewrite": { +      "version": "3.0.6", +      "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-3.0.6.tgz", +      "integrity": "sha512-REDTNCvsKcAazy8IQWzKp66AhSUDSOIKssSCqNqCcT9sN7JCwAAm3mWGTUdUzq80ABuy8d0D6RBwbnewu1aY1g==", +      "requires": { +        "hast-util-select": "~5.0.1", +        "unified": "~10.1.1", +        "unist-util-visit": "~4.1.0" +      } +    }, +    "rehype-slug": { +      "version": "5.1.0", +      "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-5.1.0.tgz", +      "integrity": "sha512-Gf91dJoXneiorNEnn+Phx97CO7oRMrpi+6r155tTxzGuLtm+QrI4cTwCa9e1rtePdL4i9tSO58PeSS6HWfgsiw==", +      "requires": { +        "@types/hast": "^2.0.0", +        "github-slugger": "^2.0.0", +        "hast-util-has-property": "^2.0.0", +        "hast-util-heading-rank": "^2.0.0", +        "hast-util-to-string": "^2.0.0", +        "unified": "^10.0.0", +        "unist-util-visit": "^4.0.0" +      } +    }, +    "remark-gfm": { +      "version": "3.0.1", +      "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", +      "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", +      "requires": { +        "@types/mdast": "^3.0.0", +        "mdast-util-gfm": "^2.0.0", +        "micromark-extension-gfm": "^2.0.0", +        "unified": "^10.0.0" +      } +    },      "remark-parse": {        "version": "10.0.1",        "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -5722,6 +7164,16 @@          "vfile": "^5.0.0"        }      }, +    "unist-util-filter": { +      "version": "4.0.1", +      "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-4.0.1.tgz", +      "integrity": "sha512-RynicUM/vbOSTSiUK+BnaK9XMfmQUh6gyi7L6taNgc7FIf84GukXVV3ucGzEN/PhUUkdP5hb1MmXc+3cvPUm5Q==", +      "requires": { +        "@types/unist": "^2.0.0", +        "unist-util-is": "^5.0.0", +        "unist-util-visit-parents": "^5.0.0" +      } +    },      "unist-util-generated": {        "version": "2.0.1",        "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", @@ -5819,6 +7271,15 @@          "vfile-message": "^3.0.0"        }      }, +    "vfile-location": { +      "version": "4.1.0", +      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz", +      "integrity": "sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==", +      "requires": { +        "@types/unist": "^2.0.0", +        "vfile": "^5.0.0" +      } +    },      "vfile-message": {        "version": "3.1.4",        "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", @@ -5849,6 +7310,11 @@          "fs-extra": "^10.0.0"        }      }, +    "web-namespaces": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", +      "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" +    },      "xtend": {        "version": "4.0.2",        "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -5859,6 +7325,11 @@        "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",        "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",        "dev": true +    }, +    "zwitch": { +      "version": "2.0.4", +      "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", +      "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="      }    }  } diff --git a/extension/react-app/package.json b/extension/react-app/package.json index 4bedb813..704f520a 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -12,12 +12,12 @@      "@styled-icons/heroicons-outline": "^10.47.0",      "@styled-icons/heroicons-solid": "^10.47.0",      "@types/vscode-webview": "^1.57.1", +    "@uiw/react-markdown-preview": "^4.1.13",      "downshift": "^7.6.0",      "posthog-js": "^1.58.0",      "prismjs": "^1.29.0",      "react": "^18.2.0",      "react-dom": "^18.2.0", -    "react-markdown": "^8.0.5",      "react-redux": "^8.0.5",      "react-switch": "^7.0.0",      "react-syntax-highlighter": "^15.5.0", diff --git a/extension/react-app/public/vite.svg b/extension/react-app/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/extension/react-app/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index 8785f88f..c9bd42e0 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -1,8 +1,5 @@  import DebugPanel from "./components/DebugPanel"; -import MainTab from "./tabs/main"; -import WelcomeTab from "./tabs/welcome"; -import ChatTab from "./tabs/chat"; -import GUI from "./tabs/gui"; +import GUI from "./pages/gui";  import { createContext } from "react";  import useContinueGUIProtocol from "./hooks/useWebsocket";  import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; @@ -18,13 +15,7 @@ function App() {      <GUIClientContext.Provider value={client}>        <DebugPanel          tabs={[ -          { -            element: <GUI />, -            title: "GUI", -          }, -          // { element: <MainTab />, title: "Debug Panel" }, -          // { element: <WelcomeTab />, title: "Welcome" }, -          // { element: <ChatTab />, title: "Chat" }, +          { element: <GUI />, title: "GUI" }          ]}        />      </GUIClientContext.Provider> diff --git a/extension/react-app/src/TestPage.tsx b/extension/react-app/src/TestPage.tsx deleted file mode 100644 index d104980b..00000000 --- a/extension/react-app/src/TestPage.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -const SideBySideDiv = styled.div` -  display: grid; -  grid-template-columns: 1fr 1fr; -  grid-template-rows: 1fr; -  grid-template-areas: "left right"; -`; - -const LeftDiv = styled.div` -  grid-area: left; -`; - -const RightDiv = styled.div` -  grid-area: right; -`; - -function TestPage() { -  return ( -    <div> -      <h1>Continue</h1> -      <SideBySideDiv> -        <LeftDiv> -          <h2>Left</h2> -        </LeftDiv> -        <RightDiv> -          <h2>Right</h2> -        </RightDiv> -      </SideBySideDiv> -    </div> -  ); -} diff --git a/extension/react-app/src/assets/Hubot-Sans.woff2 b/extension/react-app/src/assets/Hubot-Sans.woff2Binary files differ deleted file mode 100644 index 5089fc47..00000000 --- a/extension/react-app/src/assets/Hubot-Sans.woff2 +++ /dev/null diff --git a/extension/react-app/src/assets/Mona-Sans.woff2 b/extension/react-app/src/assets/Mona-Sans.woff2Binary files differ deleted file mode 100644 index 8208a500..00000000 --- a/extension/react-app/src/assets/Mona-Sans.woff2 +++ /dev/null diff --git a/extension/react-app/src/assets/react.svg b/extension/react-app/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/extension/react-app/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
\ No newline at end of file diff --git a/extension/react-app/src/components/CodeMultiselect.tsx b/extension/react-app/src/components/CodeMultiselect.tsx deleted file mode 100644 index c0ab9400..00000000 --- a/extension/react-app/src/components/CodeMultiselect.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import React, { useEffect, useState } from "react"; -import styled from "styled-components"; -import { Button, buttonColor, defaultBorderRadius, secondaryDark } from "."; -import { useSelector } from "react-redux"; -import { -  selectDebugContext, -  selectAllRangesInFiles, -  selectRangesMask, -} from "../redux/selectors/debugContextSelectors"; -import "../highlight/dark.min.css"; -import hljs from "highlight.js"; -import { postVscMessage } from "../vscode"; -import { RootStore } from "../redux/store"; -import { useDispatch } from "react-redux"; -import { -  addRangeInFile, -  deleteRangeInFileAt, -  toggleSelectionAt, -  updateFileSystem, -} from "../redux/slices/debugContexSlice"; -import { RangeInFile } from "../../../src/client"; -import { readRangeInVirtualFileSystem } from "../util"; - -//#region Styled Components - -const MultiSelectContainer = styled.div` -  border-radius: ${defaultBorderRadius}; -  padding: 4px; -  display: flex; -  flex-direction: column; -  gap: 4px; -`; - -const MultiSelectHeader = styled.div` -  display: flex; -  justify-content: space-between; -  align-items: left; -  border-bottom: 1px solid gray; -  padding-left: 4px; -  padding-right: 4px; -  & p { -    overflow-wrap: break-word; -    word-wrap: break-word; -    -ms-wrap-flow: break-word; -    overflow: hidden; -  } -`; - -const MultiSelectOption = styled.div` -  border-radius: ${defaultBorderRadius}; -  padding-top: 4px; -  cursor: pointer; -  background-color: ${secondaryDark}; -`; - -const DeleteSelectedRangeButton = styled(Button)` -  align-self: right; -  padding: 0px; -  margin-top: 0; -  aspect-ratio: 1/1; -  height: 28px; -`; - -const ToggleHighlightButton = styled(Button)` -  display: grid; -  justify-content: center; -  align-items: center; -  grid-template-columns: 30px 1fr; -  margin-left: 20px; -  order: 1; -  width: fit-content; -`; - -//#endregion - -//#region Path Formatting - -const filenameToLanguageMap: any = { -  py: "python", -  js: "javascript", -  ts: "typescript", -  html: "html", -  css: "css", -  java: "java", -  c: "c", -  cpp: "cpp", -  cs: "csharp", -  go: "go", -  rb: "ruby", -  rs: "rust", -  swift: "swift", -  php: "php", -  scala: "scala", -  kt: "kotlin", -  dart: "dart", -  hs: "haskell", -  lua: "lua", -  pl: "perl", -  r: "r", -  sql: "sql", -  vb: "vb", -  xml: "xml", -  yaml: "yaml", -}; - -function filenameToLanguage(filename: string): string { -  const extension = filename.split(".").pop(); -  if (extension === undefined) { -    return ""; -  } -  return filenameToLanguageMap[extension] || ""; -} - -function formatPathRelativeToWorkspace( -  path: string, -  workspacePath: string | undefined -) { -  if (workspacePath === undefined) { -    return path; -  } -  if (path.startsWith(workspacePath)) { -    return path.substring(workspacePath.length + 1); -  } else { -    return path; -  } -} - -function formatFileRange( -  rangeInFile: RangeInFile, -  workspacePath: string | undefined -) { -  return `${formatPathRelativeToWorkspace( -    rangeInFile.filepath, -    workspacePath -  )} (lines ${rangeInFile.range.start.line + 1}-${ -    rangeInFile.range.end.line + 1 -  })`; -  // +1 because VS Code Ranges are 0-indexed -} - -//#endregion - -function CodeMultiselect(props: {}) { -  // State -  const [highlightLocked, setHighlightLocked] = useState(true); - -  // Redux -  const dispatch = useDispatch(); -  const workspacePath = useSelector( -    (state: RootStore) => state.config.workspacePath -  ); -  const debugContext = useSelector(selectDebugContext); -  const rangesInFiles = useSelector(selectAllRangesInFiles); -  const rangesInFilesMask = useSelector(selectRangesMask); - -  useEffect(() => { -    let eventListener = (event: any) => { -      switch (event.data.type) { -        case "highlightedCode": -          if (!highlightLocked) { -            dispatch( -              addRangeInFile({ -                rangeInFile: event.data.rangeInFile, -                canUpdateLast: true, -              }) -            ); -            dispatch(updateFileSystem(event.data.filesystem)); -          } -          break; -        case "findSuspiciousCode": -          for (let c of event.data.codeLocations) { -            dispatch(addRangeInFile({ rangeInFile: c, canUpdateLast: false })); -          } -          dispatch(updateFileSystem(event.data.filesystem)); -          postVscMessage("listTenThings", { debugContext }); -          break; -      } -    }; -    window.addEventListener("message", eventListener); -    return () => window.removeEventListener("message", eventListener); -  }, [debugContext, highlightLocked]); - -  useEffect(() => { -    hljs.highlightAll(); -  }, [rangesInFiles]); - -  return ( -    <MultiSelectContainer> -      {rangesInFiles.map((range: RangeInFile, index: number) => { -        return ( -          <MultiSelectOption -            key={index} -            style={{ -              border: `1px solid ${ -                rangesInFilesMask[index] ? buttonColor : "gray" -              }`, -            }} -            onClick={() => { -              dispatch(toggleSelectionAt(index)); -            }} -          > -            <MultiSelectHeader> -              <p style={{ margin: "4px" }}> -                {formatFileRange(range, workspacePath)} -              </p> -              <DeleteSelectedRangeButton -                onClick={() => dispatch(deleteRangeInFileAt(index))} -              > -                x -              </DeleteSelectedRangeButton> -            </MultiSelectHeader> -            <pre> -              <code -                className={"language-" + filenameToLanguage(range.filepath)} -              > -                {readRangeInVirtualFileSystem(range, debugContext.filesystem)} -              </code> -            </pre> -          </MultiSelectOption> -        ); -      })} -      {rangesInFiles.length === 0 && ( -        <> -          <p>Highlight relevant code in the editor.</p> -        </> -      )} -      <ToggleHighlightButton -        onClick={() => { -          setHighlightLocked(!highlightLocked); -        }} -      > -        {highlightLocked ? ( -          <> -            <svg -              xmlns="http://www.w3.org/2000/svg" -              width="20px" -              fill="none" -              viewBox="0 0 24 24" -              strokeWidth="1.5" -              stroke="currentColor" -              className="w-6 h-6" -            > -              <path -                strokeLinecap="round" -                strokeLinejoin="round" -                d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" -              /> -            </svg>{" "} -            Enable Highlight -          </> -        ) : ( -          <> -            <svg -              xmlns="http://www.w3.org/2000/svg" -              width="20px" -              fill="none" -              viewBox="0 0 24 24" -              strokeWidth="1.5" -              stroke="currentColor" -              className="w-6 h-6" -            > -              <path -                strokeLinecap="round" -                strokeLinejoin="round" -                d="M13.5 10.5V6.75a4.5 4.5 0 119 0v3.75M3.75 21.75h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H3.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" -              /> -            </svg>{" "} -            Disable Highlight -          </> -        )} -      </ToggleHighlightButton> -    </MultiSelectContainer> -  ); -} - -export default CodeMultiselect; diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 801c3a03..f11e07af 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -1,30 +1,19 @@ -import React, { -  useCallback, -  useEffect, -  useImperativeHandle, -  useState, -} from "react"; +import React, { useEffect, useImperativeHandle, useState } from "react";  import { useCombobox } from "downshift";  import styled from "styled-components";  import { -  buttonColor,    defaultBorderRadius,    lightGray,    secondaryDark,    vscBackground,  } from ".";  import CodeBlock from "./CodeBlock"; -import { RangeInFile } from "../../../src/client";  import PillButton from "./PillButton";  import HeaderButtonWithText from "./HeaderButtonWithText"; -import { -  Trash, -  LockClosed, -  LockOpen, -  Plus, -  DocumentPlus, -} from "@styled-icons/heroicons-outline"; +import { DocumentPlus } from "@styled-icons/heroicons-outline";  import { HighlightedRangeContext } from "../../../schema/FullState"; +import { postVscMessage } from "../vscode"; +import { getMetaKeyLabel } from "../util";  // #region styled components  const mainInputFontSize = 13; @@ -180,6 +169,27 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {    useImperativeHandle(ref, () => downshiftProps, [downshiftProps]); +  const [metaKeyPressed, setMetaKeyPressed] = useState(false); +  const [focused, setFocused] = useState(false); +  useEffect(() => { +    const handleKeyDown = (e: KeyboardEvent) => { +      if (e.key === "Meta") { +        setMetaKeyPressed(true); +      } +    }; +    const handleKeyUp = (e: KeyboardEvent) => { +      if (e.key === "Meta") { +        setMetaKeyPressed(false); +      } +    }; +    window.addEventListener("keydown", handleKeyDown); +    window.addEventListener("keyup", handleKeyUp); +    return () => { +      window.removeEventListener("keydown", handleKeyDown); +      window.removeEventListener("keyup", handleKeyUp); +    }; +  }); +    useEffect(() => {      if (!inputRef.current) {        return; @@ -221,6 +231,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {          )} */}          {highlightedCodeSections.map((section, idx) => (            <PillButton +            warning={ +              section.range.contents.length > 4000 && section.editing +                ? "Editing such a large range may be slow" +                : undefined +            }              editing={section.editing}              pinned={section.pinned}              index={idx} @@ -272,7 +287,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {        <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>          <MainTextInput            disabled={props.disabled} -          placeholder="Ask a question, give instructions, or type '/' to see slash commands" +          placeholder={`Ask a question, give instructions, or type '/' to see slash commands. ${getMetaKeyLabel()}⏎ to edit.`}            {...getInputProps({              onChange: (e) => {                const target = e.target as HTMLTextAreaElement; @@ -285,6 +300,13 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {                // setShowContextDropdown(target.value.endsWith("@"));              }, +            onFocus: (e) => { +              setFocused(true); +            }, +            onBlur: (e) => { +              setFocused(false); +              postVscMessage("blurContinueInput", {}); +            },              onKeyDown: (event) => {                if (event.key === "Enter" && event.shiftKey) {                  // Prevent Downshift's default 'Enter' behavior. @@ -311,7 +333,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {                ) {                  (event.nativeEvent as any).preventDownshiftDefault = true;                } else if (event.key === "ArrowUp") { -                console.log("OWJFOIJO");                  if (positionInHistory == 0) return;                  else if (                    positionInHistory == history.length && @@ -357,10 +378,15 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {              ))}          </Ul>        </div> -      {/* <span className="text-trueGray-400 ml-auto m-auto text-xs text-right"> -        Highlight code to include as context. Currently open file included by -        default. {highlightedCodeSections.length === 0 && ""} -      </span> */} +      {highlightedCodeSections.length === 0 && +        (downshiftProps.inputValue?.startsWith("/edit") || +          (focused && +            metaKeyPressed && +            downshiftProps.inputValue?.length > 0)) && ( +          <div className="text-trueGray-400 pr-4 text-xs text-right"> +            Inserting at cursor +          </div> +        )}        <ContextDropdown          onMouseEnter={() => {            setHoveringContextDropdown(true); diff --git a/extension/react-app/src/components/LoadingCover.tsx b/extension/react-app/src/components/LoadingCover.tsx deleted file mode 100644 index a0f8f7a2..00000000 --- a/extension/react-app/src/components/LoadingCover.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -const StyledDiv = styled.div` -  position: absolute; -  top: 0; -  left: 0; -  width: 100%; -  height: 100vh; -  background: linear-gradient( -    101.79deg, -    #12887a 0%, -    #87245c 32%, -    #e12637 63%, -    #ffb215 100% -  ); -  display: flex; -  justify-content: center; -  align-items: center; -  flex-direction: column; -  z-index: 10; -`; - -const StyledImg = styled.img` -  /* add your styles here */ -`; - -const StyledDiv2 = styled.div` -  width: 50%; -  height: 5px; -  background: white; -  margin-top: 20px; -`; - -interface LoadingCoverProps { -  message: string; -  hidden?: boolean; -} - -const LoadingCover = (props: LoadingCoverProps) => { -  return ( -    <StyledDiv style={{ display: props.hidden ? "none" : "inherit" }}> -      <StyledImg src="continue.gif" alt="centered image" width="50%" /> -      <StyledDiv2></StyledDiv2> -      <p>{props.message}</p> -    </StyledDiv> -  ); -}; - -export default LoadingCover; diff --git a/extension/react-app/src/components/Onboarding.tsx b/extension/react-app/src/components/Onboarding.tsx new file mode 100644 index 00000000..231c1e93 --- /dev/null +++ b/extension/react-app/src/components/Onboarding.tsx @@ -0,0 +1,136 @@ +import { useSelector } from "react-redux"; +import { RootStore } from "../redux/store"; +import React, { useState, useEffect } from "react"; +import styled from "styled-components"; +import { ArrowLeft, ArrowRight } from "@styled-icons/heroicons-outline"; +import { defaultBorderRadius } from "."; +import Loader from "./Loader"; + +const StyledDiv = styled.div` +  position: absolute; +  top: 0; +  left: 0; +  width: 100%; +  height: 100%; +  background-color: #1e1e1e; +  z-index: 200; +`; + +const StyledSpan = styled.span` +  padding: 8px; +  border-radius: ${defaultBorderRadius}; +  &:hover { +    background-color: #ffffff33; +  } +  white-space: nowrap; +`; + +const Onboarding = () => { +  const [counter, setCounter] = useState(4); +  const gifs = ["intro", "highlight", "question", "help"]; +  const topMessages = [ +    "Welcome!", +    "Highlight code", +    "Ask a question", +    "Use /help to learn more", +  ]; + +  useEffect(() => { +    const hasVisited = localStorage.getItem("hasVisited"); +    if (hasVisited) { +      setCounter(4); +    } else { +      setCounter(0); +      localStorage.setItem("hasVisited", "true"); +    } +  }, []); + +  const [loading, setLoading] = useState(true); + +  useEffect(() => { +    setLoading(true); +  }, [counter]); + +  return ( +    <StyledDiv hidden={counter >= 4}> +      <div +        style={{ +          display: "grid", +          justifyContent: "center", +          alignItems: "center", +          height: "100%", +          textAlign: "center", +          background: `linear-gradient( +            101.79deg, +            #12887a66 0%, +            #87245c66 32%, +            #e1263766 63%, +            #ffb21566 100% +          )`, +          paddingLeft: "16px", +          paddingRight: "16px", +        }} +      > +        <h1>{topMessages[counter]}</h1> +        <div style={{ display: "flex", justifyContent: "center" }}> +          {loading && ( +            <div style={{ margin: "auto", position: "absolute", zIndex: 0 }}> +              <Loader /> +            </div> +          )} +          {counter % 2 === 0 ? ( +            <img +              src={`https://github.com/continuedev/continue/blob/main/media/${gifs[counter]}.gif?raw=true`} +              width="100%" +              key={"even-gif"} +              alt={topMessages[counter]} +              onLoad={() => { +                setLoading(false); +              }} +              style={{ zIndex: 1 }} +            /> +          ) : ( +            <img +              src={`https://github.com/continuedev/continue/blob/main/media/${gifs[counter]}.gif?raw=true`} +              width="100%" +              key={"odd-gif"} +              alt={topMessages[counter]} +              onLoad={() => { +                setLoading(false); +              }} +              style={{ zIndex: 1 }} +            /> +          )} +        </div> +        <p +          style={{ +            paddingLeft: "50px", +            paddingRight: "50px", +            paddingBottom: "50px", +            textAlign: "center", +            cursor: "pointer", +            whiteSpace: "nowrap", +          }} +        > +          <StyledSpan +            hidden={counter === 0} +            onClick={() => setCounter((prev) => Math.max(prev - 1, 0))} +          > +            <ArrowLeft width="18px" strokeWidth="2px" /> Previous +          </StyledSpan> +          <span hidden={counter === 0}>{" | "}</span> +          <StyledSpan onClick={() => setCounter((prev) => prev + 1)}> +            {counter === 0 +              ? "Click to learn how to use Continue" +              : counter === 3 +              ? "Get Started" +              : "Next"}{" "} +            <ArrowRight width="18px" strokeWidth="2px" /> +          </StyledSpan> +        </p> +      </div> +    </StyledDiv> +  ); +}; + +export default Onboarding; diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index 31d98c0f..d9d779d1 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,12 +1,11 @@  import { useContext, useState } from "react";  import styled from "styled-components"; +import { StyledTooltip, defaultBorderRadius, secondaryDark } from ".";  import { -  StyledTooltip, -  defaultBorderRadius, -  lightGray, -  secondaryDark, -} from "."; -import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline"; +  Trash, +  PaintBrush, +  ExclamationTriangle, +} from "@styled-icons/heroicons-outline";  import { GUIClientContext } from "../App";  const Button = styled.button` @@ -31,7 +30,6 @@ const GridDiv = styled.div`    grid-template-columns: 1fr 1fr;    align-items: center;    border-radius: ${defaultBorderRadius}; -  overflow: hidden;    background-color: ${secondaryDark};  `; @@ -48,6 +46,21 @@ const ButtonDiv = styled.div<{ backgroundColor: string }>`    }  `; +const CircleDiv = styled.div` +  position: absolute; +  top: -10px; +  right: -10px; +  width: 20px; +  height: 20px; +  border-radius: 50%; +  background-color: red; +  color: white; +  display: flex; +  align-items: center; +  justify-content: center; +  padding: 2px; +`; +  interface PillButtonProps {    onHover?: (arg0: boolean) => void;    onDelete?: () => void; @@ -55,6 +68,7 @@ interface PillButtonProps {    index: number;    editing: boolean;    pinned: boolean; +  warning?: string;  }  const PillButton = (props: PillButtonProps) => { @@ -63,75 +77,96 @@ const PillButton = (props: PillButtonProps) => {    return (      <> -      <Button -        style={{ -          position: "relative", -          borderColor: props.editing -            ? "#8800aa" -            : props.pinned -            ? "#ffff0099" -            : "transparent", -          borderWidth: "1px", -          borderStyle: "solid", -        }} -        onMouseEnter={() => { -          setIsHovered(true); -          if (props.onHover) { -            props.onHover(true); -          } -        }} -        onMouseLeave={() => { -          setIsHovered(false); -          if (props.onHover) { -            props.onHover(false); -          } -        }} -      > -        {isHovered && ( -          <GridDiv> -            <ButtonDiv -              data-tooltip-id={`edit-${props.index}`} -              backgroundColor={"#8800aa55"} -              onClick={() => { -                client?.setEditingAtIndices([props.index]); -              }} -            > -              <PaintBrush style={{ margin: "auto" }} width="1.6em"></PaintBrush> -            </ButtonDiv> +      <div style={{ position: "relative" }}> +        <Button +          style={{ +            position: "relative", +            borderColor: props.warning +              ? "red" +              : props.editing +              ? "#8800aa" +              : props.pinned +              ? "#ffff0099" +              : "transparent", +            borderWidth: "1px", +            borderStyle: "solid", +          }} +          onMouseEnter={() => { +            setIsHovered(true); +            if (props.onHover) { +              props.onHover(true); +            } +          }} +          onMouseLeave={() => { +            setIsHovered(false); +            if (props.onHover) { +              props.onHover(false); +            } +          }} +        > +          {isHovered && ( +            <GridDiv> +              <ButtonDiv +                data-tooltip-id={`edit-${props.index}`} +                backgroundColor={"#8800aa55"} +                onClick={() => { +                  client?.setEditingAtIndices([props.index]); +                }} +              > +                <PaintBrush +                  style={{ margin: "auto" }} +                  width="1.6em" +                ></PaintBrush> +              </ButtonDiv> -            {/* <ButtonDiv +              {/* <ButtonDiv              data-tooltip-id={`pin-${props.index}`}              backgroundColor={"#ffff0055"}              onClick={() => {                client?.setPinnedAtIndices([props.index]);              }} -          > +            >              <MapPin style={{ margin: "auto" }} width="1.6em"></MapPin>            </ButtonDiv> */} -            <StyledTooltip id={`pin-${props.index}`}> -              Edit this range +              <StyledTooltip id={`pin-${props.index}`}> +                Edit this range +              </StyledTooltip> +              <ButtonDiv +                data-tooltip-id={`delete-${props.index}`} +                backgroundColor={"#cc000055"} +                onClick={() => { +                  if (props.onDelete) { +                    props.onDelete(); +                  } +                }} +              > +                <Trash style={{ margin: "auto" }} width="1.6em"></Trash> +              </ButtonDiv> +            </GridDiv> +          )} +          {props.title} +        </Button> +        <StyledTooltip id={`edit-${props.index}`}> +          {props.editing +            ? "Editing this range (with rest of file as context)" +            : "Edit this range"} +        </StyledTooltip> +        <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip> +        {props.warning && ( +          <> +            <CircleDiv data-tooltip-id={`circle-div-${props.title}`}> +              <ExclamationTriangle +                style={{ margin: "auto" }} +                width="1.0em" +                strokeWidth={2} +              /> +            </CircleDiv> +            <StyledTooltip id={`circle-div-${props.title}`}> +              {props.warning}              </StyledTooltip> -            <ButtonDiv -              data-tooltip-id={`delete-${props.index}`} -              backgroundColor={"#cc000055"} -              onClick={() => { -                if (props.onDelete) { -                  props.onDelete(); -                } -              }} -            > -              <Trash style={{ margin: "auto" }} width="1.6em"></Trash> -            </ButtonDiv> -          </GridDiv> +          </>          )} -        {props.title} -      </Button> -      <StyledTooltip id={`edit-${props.index}`}> -        {props.editing -          ? "Editing this range (with rest of file as context)" -          : "Edit this range"} -      </StyledTooltip> -      <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip> +      </div>      </>    );  }; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index d480c565..93bdbc89 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react";  import styled, { keyframes } from "styled-components";  import {    appear, @@ -15,9 +15,9 @@ import {  } from "@styled-icons/heroicons-outline";  import { StopCircle } from "@styled-icons/heroicons-solid";  import { HistoryNode } from "../../../schema/HistoryNode"; -import ReactMarkdown from "react-markdown";  import HeaderButtonWithText from "./HeaderButtonWithText"; -import CodeBlock from "./CodeBlock"; +import MarkdownPreview from "@uiw/react-markdown-preview"; +import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../util";  interface StepContainerProps {    historyNode: HistoryNode; @@ -72,19 +72,6 @@ const ContentDiv = styled.div<{ isUserInput: boolean }>`    font-size: 13px;  `; -const MarkdownPre = styled.pre` -  background-color: ${secondaryDark}; -  padding: 10px; -  border-radius: ${defaultBorderRadius}; -  border: 0.5px solid white; -`; - -const StyledCode = styled.code` -  word-wrap: break-word; -  color: #f69292; -  background: transparent; -`; -  const gradient = keyframes`    0% {      background-position: 0px 0; @@ -124,6 +111,31 @@ const GradientBorder = styled.div<{    background-size: 200% 200%;  `; +const StyledMarkdownPreview = styled(MarkdownPreview)` +  pre { +    background-color: ${secondaryDark}; +    padding: 1px; +    border-radius: ${defaultBorderRadius}; +    border: 0.5px solid white; +  } + +  code { +    color: #f69292; +    word-wrap: break-word; +  } + +  pre > code { +    background-color: ${secondaryDark}; +    color: white; +  } + +  background-color: ${vscBackground}; +  font-family: "Lexend", sans-serif; +  font-size: 13px; +  padding: 8px; +  color: white; +`; +  // #endregion  function StepContainer(props: StepContainerProps) { @@ -158,7 +170,7 @@ function StepContainer(props: StepContainerProps) {      >        <StepContainerDiv open={props.open}>          <GradientBorder -          loading={props.historyNode.active as boolean | false} +          loading={(props.historyNode.active as boolean) || false}            isFirst={props.isFirst}            isLast={props.isLast}            borderColor={ @@ -170,7 +182,7 @@ function StepContainer(props: StepContainerProps) {            }            className="overflow-hidden cursor-pointer"            onClick={(e) => { -            if (e.metaKey) { +            if (isMetaEquivalentKeyPressed(e)) {                props.onToggleAll();              } else {                props.onToggle(); @@ -178,7 +190,7 @@ function StepContainer(props: StepContainerProps) {            }}          >            <HeaderDiv -            loading={props.historyNode.active as boolean | false} +            loading={(props.historyNode.active as boolean) || false}              error={props.historyNode.observation?.error ? true : false}            >              <div className="m-2"> @@ -206,7 +218,11 @@ function StepContainer(props: StepContainerProps) {                    e.stopPropagation();                    props.onDelete();                  }} -                text={props.historyNode.active ? "Stop (⌘⌫)" : "Delete"} +                text={ +                  props.historyNode.active +                    ? `Stop (${getMetaKeyLabel()}⌫)` +                    : "Delete" +                }                >                  {props.historyNode.active ? (                    <StopCircle size="1.6em" onClick={props.onDelete} /> @@ -242,31 +258,16 @@ function StepContainer(props: StepContainerProps) {            )}            {props.historyNode.observation?.error ? ( -            <pre className="overflow-x-scroll"> -              {props.historyNode.observation.error as string} -            </pre> +            <details> +              <summary>View Traceback</summary> +              <pre className="overflow-x-scroll"> +                {props.historyNode.observation.error as string} +              </pre> +            </details>            ) : ( -            <ReactMarkdown -              key={1} -              className="overflow-x-scroll" -              components={{ -                pre: ({ node, ...props }) => { -                  return ( -                    <CodeBlock -                      children={(props.children[0] as any).props.children[0]} -                    /> -                  ); -                }, -                code: ({ node, ...props }) => { -                  return <StyledCode children={props.children[0] as any} />; -                }, -                ul: ({ node, ...props }) => { -                  return <ul className="ml-0" {...props} />; -                }, -              }} -            > -              {props.historyNode.step.description as any} -            </ReactMarkdown> +            <StyledMarkdownPreview +              source={props.historyNode.step.description || ""} +            />            )}          </ContentDiv>        </StepContainerDiv> diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index ea5727f0..646d6846 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -2,6 +2,7 @@  import React, { useEffect, useState } from "react";  import styled from "styled-components";  import { Button, buttonColor, secondaryDark, vscBackground } from "."; +import { isMetaEquivalentKeyPressed } from "../util";  const ScreenCover = styled.div`    position: absolute; @@ -81,7 +82,11 @@ const TextDialog = (props: {              rows={10}              ref={textAreaRef}              onKeyDown={(e) => { -              if (e.key === "Enter" && e.metaKey && textAreaRef.current) { +              if ( +                e.key === "Enter" && +                isMetaEquivalentKeyPressed(e) && +                textAreaRef.current +              ) {                  props.onEnter(textAreaRef.current.value);                  setText("");                } else if (e.key === "Escape") { diff --git a/extension/react-app/src/highlight/dark.min.css b/extension/react-app/src/highlight/dark.min.css deleted file mode 100644 index 9268d7c9..00000000 --- a/extension/react-app/src/highlight/dark.min.css +++ /dev/null @@ -1,53 +0,0 @@ -pre code.hljs { -  display: block; -  overflow-x: auto; -  padding: 1em; -} -code.hljs { -  padding: 3px 5px; -} -.hljs { -  color: #ddd; -  background: #252526; -} -.hljs-keyword, -.hljs-link, -.hljs-literal, -.hljs-section, -.hljs-selector-tag { -  color: #fff; -} -.hljs-addition, -.hljs-attribute, -.hljs-built_in, -.hljs-bullet, -.hljs-name, -.hljs-string, -.hljs-symbol, -.hljs-template-tag, -.hljs-template-variable, -.hljs-title, -.hljs-type, -.hljs-variable { -  color: #d88; -} -.hljs-comment, -.hljs-deletion, -.hljs-meta, -.hljs-quote { -  color: #979797; -} -.hljs-doctag, -.hljs-keyword, -.hljs-literal, -.hljs-name, -.hljs-section, -.hljs-selector-tag, -.hljs-strong, -.hljs-title, -.hljs-type { -  font-weight: 700; -} -.hljs-emphasis { -  font-style: italic; -} diff --git a/extension/react-app/src/hooks/messenger.ts b/extension/react-app/src/hooks/messenger.ts index e2a0bab8..00ce1fbb 100644 --- a/extension/react-app/src/hooks/messenger.ts +++ b/extension/react-app/src/hooks/messenger.ts @@ -1,6 +1,3 @@ -// console.log("Websocket import"); -// const WebSocket = require("ws"); -  export abstract class Messenger {    abstract send(messageType: string, data: object): void; @@ -28,13 +25,6 @@ export class WebsocketMessenger extends Messenger {    private serverUrl: string;    _newWebsocket(): WebSocket { -    // // Dynamic import, because WebSocket is builtin with browser, but not with node. And can't use require in browser. -    // if (typeof process === "object") { -    //   console.log("Using node"); -    //   // process is only available in Node -    //   var WebSocket = require("ws"); -    // } -      const newWebsocket = new WebSocket(this.serverUrl);      for (const listener of this.onOpenListeners) {        this.onOpen(listener); diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/pages/gui.tsx index e1ecec9e..64207487 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -20,9 +20,10 @@ import ReactSwitch from "react-switch";  import { usePostHog } from "posthog-js/react";  import { useSelector } from "react-redux";  import { RootStore } from "../redux/store"; -import LoadingCover from "../components/LoadingCover";  import { postVscMessage } from "../vscode";  import UserInputContainer from "../components/UserInputContainer"; +import Onboarding from "../components/Onboarding"; +import { isMetaEquivalentKeyPressed } from "../util";  const TopGUIDiv = styled.div`    overflow: hidden; @@ -95,11 +96,8 @@ function GUI(props: GUIProps) {            name: "Welcome to Continue",            hide: false,            description: `- Highlight code and ask a question or give instructions -- Use \`cmd+k\` (Mac) / \`ctrl+k\` (Windows) to open Continue -- Use \`cmd+shift+e\` / \`ctrl+shift+e\` to open file Explorer -- Add your own OpenAI API key to VS Code Settings with \`cmd+,\` -- Use slash commands when you want fine-grained control -- Past steps are included as part of the context by default`, +          - Use \`cmd+m\` (Mac) / \`ctrl+m\` (Windows) to open Continue +          - Use \`/help\` to ask questions about how to use Continue`,            system_message: null,            chat_context: [],            manage_own_chat_context: false, @@ -140,13 +138,14 @@ function GUI(props: GUIProps) {    useEffect(() => {      const listener = (e: any) => {        // Cmd + i to toggle fast model -      if (e.key === "i" && e.metaKey && e.shiftKey) { +      if (e.key === "i" && isMetaEquivalentKeyPressed(e) && e.shiftKey) {          setUsingFastModel((prev) => !prev);          // Cmd + backspace to stop currently running step        } else if (          e.key === "Backspace" && -        e.metaKey && -        typeof history?.current_index !== "undefined" +        isMetaEquivalentKeyPressed(e) && +        typeof history?.current_index !== "undefined" && +        history.timeline[history.current_index]?.active        ) {          client?.deleteAtIndex(history.current_index);        } @@ -169,6 +168,7 @@ function GUI(props: GUIProps) {        const waitingForSteps =          state.active &&          state.history.current_index < state.history.timeline.length && +        state.history.timeline[state.history.current_index] &&          state.history.timeline[            state.history.current_index          ].step.description?.trim() === ""; @@ -221,7 +221,7 @@ function GUI(props: GUIProps) {      if (mainTextInputRef.current) {        let input = (mainTextInputRef.current as any).inputValue;        // cmd+enter to /edit -      if (event?.metaKey) { +      if (isMetaEquivalentKeyPressed(event)) {          input = `/edit ${input}`;        }        (mainTextInputRef.current as any).setInputValue(""); @@ -235,14 +235,14 @@ function GUI(props: GUIProps) {          history.current_index < history.timeline.length        ) {          if ( -          history.timeline[history.current_index].step.name === +          history.timeline[history.current_index]?.step.name ===            "Waiting for user input"          ) {            if (input.trim() === "") return;            onStepUserInput(input, history!.current_index);            return;          } else if ( -          history.timeline[history.current_index].step.name === +          history.timeline[history.current_index]?.step.name ===            "Waiting for user confirmation"          ) {            onStepUserInput("ok", history!.current_index); @@ -260,14 +260,13 @@ function GUI(props: GUIProps) {    const onStepUserInput = (input: string, index: number) => {      if (!client) return; -    console.log("Sending step user input", input, index);      client.sendStepUserInput(input, index);    };    // const iterations = useSelector(selectIterations);    return (      <> -      <LoadingCover hidden={true} message="Downloading local model..." /> +      <Onboarding />        <TextDialog          showDialog={showFeedbackDialog}          onEnter={(text) => { @@ -278,7 +277,7 @@ function GUI(props: GUIProps) {            setShowFeedbackDialog(false);          }}          message={feedbackDialogMessage} -      ></TextDialog> +      />        <TopGUIDiv          ref={topGuiDivRef} @@ -348,12 +347,6 @@ function GUI(props: GUIProps) {          </div>          <ComboBox -          // disabled={ -          //   history?.timeline.length -          //     ? history.timeline[history.current_index].step.name === -          //       "Waiting for user confirmation" -          //     : false -          // }            ref={mainTextInputRef}            onEnter={(e) => {              onMainTextInput(e); @@ -438,7 +431,7 @@ function GUI(props: GUIProps) {              if (!usingFastModel) {                // Show the dialog                setFeedbackDialogMessage( -                "We don't yet support local models, but we're working on it! If privacy is a concern of yours, please use the feedback button in the bottom right to let us know." +                "We don't yet support local models, but we're working on it! If privacy is a concern of yours, please write a short note to let us know."                );                setShowFeedbackDialog(true);              } diff --git a/extension/react-app/src/tabs/additionalContext.tsx b/extension/react-app/src/tabs/additionalContext.tsx deleted file mode 100644 index 98fce9f1..00000000 --- a/extension/react-app/src/tabs/additionalContext.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { H3, TextArea } from "../components"; - -function AdditionalContextTab() { -  return ( -    <div className="mx-5"> -      <H3>Additional Context</H3> -      <TextArea -        rows={8} -        placeholder="Copy and paste information related to the bug from GitHub Issues, Slack threads, or other notes here." -        className="additionalContextTextarea" -      ></TextArea> -      <br></br> -    </div> -  ); -} - -export default AdditionalContextTab; diff --git a/extension/react-app/src/tabs/chat/MessageDiv.tsx b/extension/react-app/src/tabs/chat/MessageDiv.tsx deleted file mode 100644 index 3543dd93..00000000 --- a/extension/react-app/src/tabs/chat/MessageDiv.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useEffect } from "react"; -import { ChatMessage } from "../../redux/store"; -import styled from "styled-components"; -import { -  buttonColor, -  defaultBorderRadius, -  secondaryDark, -} from "../../components"; -import VSCodeFileLink from "../../components/VSCodeFileLink"; -import ReactMarkdown from "react-markdown"; -import "../../highlight/dark.min.css"; -import hljs from "highlight.js"; -import { useSelector } from "react-redux"; -import { selectIsStreaming } from "../../redux/selectors/chatSelectors"; - -const Container = styled.div` -  padding-left: 8px; -  padding-right: 8px; -  border-radius: 8px; -  margin: 3px; -  width: fit-content; -  max-width: 75%; -  overflow-y: scroll; -  word-wrap: break-word; -  -ms-word-wrap: break-word; -  height: fit-content; -  overflow: hidden; -  background-color: ${(props) => { -    if (props.role === "user") { -      return buttonColor; -    } else { -      return secondaryDark; -    } -  }}; -  float: ${(props) => { -    if (props.role === "user") { -      return "right"; -    } else { -      return "left"; -    } -  }}; -  display: block; - -  & pre { -    border: 1px solid gray; -    border-radius: ${defaultBorderRadius}; -  } -`; - -function MessageDiv(props: ChatMessage) { -  const [richContent, setRichContent] = React.useState<JSX.Element[]>([]); -  const isStreaming = useSelector(selectIsStreaming); - -  useEffect(() => { -    if (!isStreaming) { -      hljs.highlightAll(); -    } -  }, [richContent, isStreaming]); - -  useEffect(() => { -    setRichContent([ -      <ReactMarkdown key={1} children={props.content}></ReactMarkdown>, -    ]); -  }, [props.content]); - -  return ( -    <> -      <div className="overflow-auto"> -        <Container role={props.role}>{richContent}</Container> -      </div> -    </> -  ); -} - -export default MessageDiv; diff --git a/extension/react-app/src/tabs/chat/index.tsx b/extension/react-app/src/tabs/chat/index.tsx deleted file mode 100644 index a93ad4f9..00000000 --- a/extension/react-app/src/tabs/chat/index.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { selectChatMessages } from "../../redux/selectors/chatSelectors"; -import MessageDiv from "./MessageDiv"; -import styled from "styled-components"; -import { addMessage, setIsStreaming } from "../../redux/slices/chatSlice"; -import { AnyAction, Dispatch } from "@reduxjs/toolkit"; -import { closeStream, streamUpdate } from "../../redux/slices/chatSlice"; -import { ChatMessage, RootStore } from "../../redux/store"; -import { postVscMessage, vscRequest } from "../../vscode"; -import { defaultBorderRadius, Loader } from "../../components"; -import { selectHighlightedCode } from "../../redux/selectors/miscSelectors"; -import { readRangeInVirtualFileSystem } from "../../util"; -import { selectDebugContext } from "../../redux/selectors/debugContextSelectors"; - -let textEntryBarHeight = "30px"; - -const ChatContainer = styled.div` -  display: grid; -  grid-template-rows: 1fr auto; -  height: 100%; -`; - -const BottomDiv = styled.div` -  display: grid; -  grid-template-rows: auto auto; -`; - -const BottomButton = styled.button( -  (props: { active: boolean }) => ` -  font-size: 10px; -  border: none; -  color: white; -  margin-right: 4px; -  cursor: pointer; -  background-color: ${props.active ? "black" : "gray"}; -  border-radius: ${defaultBorderRadius}; -  padding: 8px; -` -); - -const TextEntryBar = styled.input` -  height: ${textEntryBarHeight}; -  border-bottom-left-radius: ${defaultBorderRadius}; -  border-bottom-right-radius: ${defaultBorderRadius}; -  padding: 8px; -  border: 1px solid white; -  background-color: black; -  color: white; -  outline: none; -`; - -function ChatTab() { -  const dispatch = useDispatch(); -  const chatMessages = useSelector(selectChatMessages); -  const isStreaming = useSelector((state: RootStore) => state.chat.isStreaming); -  const baseUrl = useSelector((state: RootStore) => state.config.apiUrl); -  const debugContext = useSelector(selectDebugContext); - -  const [includeHighlightedCode, setIncludeHighlightedCode] = useState(true); -  const [writeToEditor, setWriteToEditor] = useState(false); -  const [waitingForResponse, setWaitingForResponse] = useState(false); - -  const highlightedCode = useSelector(selectHighlightedCode); - -  const streamToStateThunk = useCallback( -    (dispatch: Dispatch<AnyAction>, getResponse: () => Promise<Response>) => { -      let streamToCursor = writeToEditor; -      getResponse().then((resp) => { -        setWaitingForResponse(false); -        if (resp.body) { -          resp.body.pipeTo( -            new WritableStream({ -              write(chunk) { -                let update = new TextDecoder("utf-8").decode(chunk); -                dispatch(streamUpdate(update)); -                if (streamToCursor) { -                  postVscMessage("streamUpdate", { update }); -                } -              }, -              close() { -                dispatch(closeStream()); -                if (streamToCursor) { -                  postVscMessage("closeStream", null); -                } -              }, -            }) -          ); -        } -      }); -    }, -    [writeToEditor] -  ); - -  const compileHiddenChatMessages = useCallback(async () => { -    let messages: ChatMessage[] = []; -    if ( -      includeHighlightedCode && -      highlightedCode?.filepath !== undefined && -      highlightedCode?.range !== undefined && -      debugContext.filesystem[highlightedCode.filepath] !== undefined -    ) { -      let fileContents = readRangeInVirtualFileSystem( -        highlightedCode, -        debugContext.filesystem -      ); -      if (fileContents) { -        messages.push({ -          role: "user", -          content: fileContents, -        }); -      } -    } else { -      // Similarity search over workspace -      let data = await vscRequest("queryEmbeddings", { -        query: chatMessages[chatMessages.length - 1].content, -      }); -      let codeContextMessages = data.results.map( -        (result: { id: string; document: string }) => { -          let msg: ChatMessage = { -            role: "user", -            content: `File: ${result.id} \n ${result.document}`, -          }; -          return msg; -        } -      ); -      codeContextMessages.push({ -        role: "user", -        content: -          "Use the above code to help you answer the question below. Answer in asterisk bullet points, and give the full path whenever you reference files.", -      }); -      messages.push(...codeContextMessages); -    } - -    let systemMsgContent = writeToEditor -      ? "Respond only with the exact code requested, no additional text." -      : "Use the above code to help you answer the question below. Respond in markdown if using bullets or other special formatting, being sure to specify language for code blocks."; - -    messages.push({ -      role: "system", -      content: systemMsgContent, -    }); -    return messages; -  }, [highlightedCode, chatMessages, includeHighlightedCode, writeToEditor]); - -  useEffect(() => { -    if ( -      chatMessages.length > 0 && -      chatMessages[chatMessages.length - 1].role === "user" && -      !isStreaming -    ) { -      dispatch(setIsStreaming(true)); -      streamToStateThunk(dispatch, async () => { -        if (chatMessages.length === 0) { -          return new Promise((resolve, _) => resolve(new Response())); -        } -        let hiddenChatMessages = await compileHiddenChatMessages(); -        let augmentedMessages = [ -          ...chatMessages.slice(0, -1), -          ...hiddenChatMessages, -          chatMessages[chatMessages.length - 1], -        ]; -        console.log(augmentedMessages); -        // The autogenerated client can't handle streams, so have to go raw -        return fetch(`${baseUrl}/chat/complete`, { -          method: "POST", -          headers: { -            "Content-Type": "application/json", -          }, -          body: JSON.stringify({ -            messages: augmentedMessages, -          }), -        }); -      }); -    } -  }, [chatMessages, dispatch, isStreaming, highlightedCode]); - -  const chatMessagesDiv = useRef<HTMLDivElement>(null); -  useEffect(() => { -    // Scroll to bottom -    let interval = setInterval(() => { -      if (chatMessagesDiv.current && !waitingForResponse) { -        chatMessagesDiv.current.scrollTop += Math.max( -          4, -          0.05 * chatMessagesDiv.current.scrollHeight - -            chatMessagesDiv.current.clientHeight - -            chatMessagesDiv.current.scrollTop -        ); -        if ( -          chatMessagesDiv.current.scrollTop >= -          chatMessagesDiv.current.scrollHeight - -            chatMessagesDiv.current.clientHeight -        ) { -          clearInterval(interval); -        } -      } -    }, 10); -  }, [chatMessages, chatMessagesDiv, waitingForResponse]); - -  return ( -    <ChatContainer> -      <div className="mx-5 overflow-y-scroll" ref={chatMessagesDiv}> -        <h1>Chat</h1> -        <hr></hr> -        <div> -          {chatMessages.length > 0 ? ( -            chatMessages.map((message, idx) => { -              return <MessageDiv key={idx} {...message}></MessageDiv>; -            }) -          ) : ( -            <p className="text-gray-400 m-auto text-center"> -              You can ask questions about your codebase or ask for code written -              directly in the editor. -            </p> -          )} -          {waitingForResponse && <Loader></Loader>} -        </div> -      </div> - -      <BottomDiv> -        <div className="h-12 bg-secondary-"> -          <div className="flex items-center p-2"> -            {/* <p className="mr-auto text-xs"> -              Highlighted code is automatically included in your chat message. -            </p> */} -            <BottomButton -              className="ml-auto" -              active={writeToEditor} -              onClick={() => { -                setWriteToEditor(!writeToEditor); -              }} -            > -              {writeToEditor ? "Writing to editor" : "Write to editor"} -            </BottomButton> - -            <BottomButton -              active={includeHighlightedCode} -              onClick={() => { -                setIncludeHighlightedCode(!includeHighlightedCode); -              }} -            > -              {includeHighlightedCode -                ? "Including highlighted code" -                : "Automatically finding relevant code"} -            </BottomButton> -          </div> -        </div> -        <TextEntryBar -          type="text" -          placeholder="Enter your message here" -          onKeyDown={(e) => { -            if (e.key === "Enter" && e.currentTarget.value !== "") { -              console.log("Sending message", e.currentTarget.value); -              dispatch( -                addMessage({ content: e.currentTarget.value, role: "user" }) -              ); -              (e.target as any).value = ""; -              setWaitingForResponse(true); -            } -          }} -        ></TextEntryBar> -      </BottomDiv> -    </ChatContainer> -  ); -} - -export default ChatTab; diff --git a/extension/react-app/src/tabs/main.tsx b/extension/react-app/src/tabs/main.tsx deleted file mode 100644 index a8b3300d..00000000 --- a/extension/react-app/src/tabs/main.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { H3, TextArea, Button, Pre, Loader } from "../components"; -import styled from "styled-components"; -import { postVscMessage, withProgress } from "../vscode"; -import { useDebugContextValue } from "../redux/hooks"; -import CodeMultiselect from "../components/CodeMultiselect"; -import { useSelector } from "react-redux"; -import { selectDebugContext } from "../redux/selectors/debugContextSelectors"; -import { useDispatch } from "react-redux"; -import { updateValue } from "../redux/slices/debugContexSlice"; -import { setWorkspacePath } from "../redux/slices/configSlice"; -import { SerializedDebugContext } from "../../../src/client"; -import { useEditCache } from "../util/editCache"; -import { useApi } from "../util/api"; - -const ButtonDiv = styled.div` -  display: flex; -  justify-content: space-between; -  align-items: center; -  gap: 4px; -  margin: 4px; -  flex-wrap: wrap; - -  & button { -    flex-grow: 1; -  } -`; - -function MainTab(props: any) { -  const dispatch = useDispatch(); - -  const [suggestion, setSuggestion] = useState(""); -  const [traceback, setTraceback] = useDebugContextValue("traceback", ""); -  const [selectedRanges, setSelectedRanges] = useDebugContextValue( -    "rangesInFiles", -    [] -  ); - -  const editCache = useEditCache(); -  const { debugApi } = useApi(); - -  const [responseLoading, setResponseLoading] = useState(false); - -  let debugContext = useSelector(selectDebugContext); - -  useEffect(() => { -    editCache.preloadEdit(debugContext); -  }, [debugContext]); - -  function postVscMessageWithDebugContext( -    type: string, -    overrideDebugContext: SerializedDebugContext | null = null -  ) { -    postVscMessage(type, { -      debugContext: overrideDebugContext || debugContext, -    }); -  } - -  function launchFindSuspiciousCode(newTraceback: string) { -    // setTraceback's effects don't occur immediately, so we have to add it to the debug context manually -    let updatedDebugContext = { -      ...debugContext, -      traceback: newTraceback, -    }; -    postVscMessageWithDebugContext("findSuspiciousCode", updatedDebugContext); -    postVscMessageWithDebugContext("preloadEdit", updatedDebugContext); -  } - -  useEffect(() => { -    const eventListener = (event: any) => { -      switch (event.data.type) { -        case "suggestFix": -        case "explainCode": -        case "listTenThings": -          setSuggestion(event.data.value); -          setResponseLoading(false); -          break; -        case "traceback": -          setTraceback(event.data.value); -          launchFindSuspiciousCode(event.data.value); -          break; -        case "workspacePath": -          dispatch(setWorkspacePath(event.data.value)); -          break; -      } -    }; -    window.addEventListener("message", eventListener); - -    return () => window.removeEventListener("message", eventListener); -  }, [debugContext, selectedRanges]); - -  return ( -    <div className="mx-5"> -      <h1>Debug Panel</h1> - -      <H3>Code Sections</H3> -      <CodeMultiselect></CodeMultiselect> - -      <H3>Bug Description</H3> -      <TextArea -        id="bugDescription" -        name="bugDescription" -        className="bugDescription" -        rows={4} -        cols={50} -        placeholder="Describe your bug..." -      ></TextArea> - -      <H3>Stack Trace</H3> -      <TextArea -        id="traceback" -        className="traceback" -        name="traceback" -        rows={4} -        cols={50} -        placeholder="Paste stack trace here" -        onChange={(e) => { -          setTraceback(e.target.value); -          dispatch(updateValue({ key: "traceback", value: e.target.value })); -          // postVscMessageWithDebugContext("findSuspiciousCode"); -        }} -        onPaste={(e) => { -          let pasted = e.clipboardData.getData("text"); -          console.log("PASTED", pasted); -          setTraceback(pasted); -          launchFindSuspiciousCode(pasted); -        }} -        value={traceback} -      ></TextArea> - -      <select -        hidden -        id="relevantVars" -        className="relevantVars" -        name="relevantVars" -      ></select> - -      <ButtonDiv> -        <Button -          onClick={() => { -            postVscMessageWithDebugContext("explainCode"); -            setResponseLoading(true); -          }} -        > -          Explain Code -        </Button> -        <Button -          onClick={() => { -            postVscMessageWithDebugContext("suggestFix"); -            setResponseLoading(true); -          }} -        > -          Generate Ideas -        </Button> -        <Button -          disabled={selectedRanges.length === 0} -          onClick={async () => { -            withProgress("Generating Fix", async () => { -              let edits = await editCache.getEdit(debugContext); -              postVscMessage("makeEdit", { edits }); -            }); -          }} -        > -          Suggest Fix -        </Button> -        <Button -          disabled={selectedRanges.length === 0} -          onClick={() => { -            postVscMessageWithDebugContext("generateUnitTest"); -          }} -        > -          Create Test -        </Button> -      </ButtonDiv> -      <Loader hidden={!responseLoading}></Loader> - -      <Pre -        className="fixSuggestion" -        hidden={!(typeof suggestion === "string" && suggestion.length > 0)} -      > -        {suggestion} -      </Pre> - -      <br></br> -    </div> -  ); -} - -export default MainTab; diff --git a/extension/react-app/src/tabs/welcome.tsx b/extension/react-app/src/tabs/welcome.tsx deleted file mode 100644 index c29d260a..00000000 --- a/extension/react-app/src/tabs/welcome.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; - -function WelcomeTab() { -  return ( -    <div className="mx-5"> -      <h1>Welcome to Continue</h1> - -      <p> -        Learn more in the{" "} -        <a href="https://www.notion.so/continue-dev/Continue-User-Guide-1c6ad99887d0474d9e42206f6c98efa4"> -          Continue User Guide -        </a>{" "} -      </p> -      <p>Send Nate or Ty your feedback:</p> -      <p>1. What excites you about Continue?</p> -      <p>2. What did you struggle with when using Continue?</p> -      <p>3. How do you wish Continue worked?</p> -    </div> -  ); -} - -export default WelcomeTab; diff --git a/extension/react-app/src/util/api.ts b/extension/react-app/src/util/api.ts deleted file mode 100644 index bdec1d20..00000000 --- a/extension/react-app/src/util/api.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { -  Configuration, -  DebugApi, -  UnittestApi, -  ChatApi, -} from "../../../src/client"; -import { useSelector } from "react-redux"; -import { useEffect, useState } from "react"; -import { RootStore } from "../redux/store"; - -export function useApi() { -  const apiUrl = useSelector((state: RootStore) => state.config.apiUrl); -  const vscMachineId = useSelector( -    (state: RootStore) => state.config.vscMachineId -  ); -  const [debugApi, setDebugApi] = useState<DebugApi>(); -  const [unittestApi, setUnittestApi] = useState<UnittestApi>(); -  const [chatApi, setChatApi] = useState<ChatApi>(); - -  useEffect(() => { -    if (apiUrl && vscMachineId) { -      let config = new Configuration({ -        basePath: apiUrl, -        fetchApi: fetch, -        middleware: [ -          { -            pre: async (context) => { -              context.init.headers = { -                ...context.init.headers, -                "x-vsc-machine-id": vscMachineId, -              }; -            }, -          }, -        ], -      }); -      setDebugApi(new DebugApi(config)); -      setUnittestApi(new UnittestApi(config)); -      setChatApi(new ChatApi(config)); -    } -  }, [apiUrl, vscMachineId]); - -  return { debugApi, unittestApi, chatApi }; -} diff --git a/extension/react-app/src/util/editCache.ts b/extension/react-app/src/util/editCache.ts deleted file mode 100644 index b8071127..00000000 --- a/extension/react-app/src/util/editCache.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { useApi } from "../util/api"; -import { FileEdit, SerializedDebugContext } from "../../../src/client"; -import { useCallback, useEffect, useState } from "react"; - -export function useEditCache() { -  const { debugApi } = useApi(); - -  const fetchNewEdit = useCallback( -    async (debugContext: SerializedDebugContext) => { -      return ( -        await debugApi?.editEndpointDebugEditPost({ -          serializedDebugContext: debugContext, -        }) -      )?.completion; -    }, -    [debugApi] -  ); - -  const [editCache, setEditCache] = useState(new EditCache(fetchNewEdit)); - -  useEffect(() => { -    setEditCache(new EditCache(fetchNewEdit)); -  }, [fetchNewEdit]); - -  return editCache; -} - -/** - * Stores preloaded edits, invalidating based off of debug context changes - */ -class EditCache { -  private _lastDebugContext: SerializedDebugContext | undefined; -  private _cachedEdits: FileEdit[] | undefined; -  private _fetchNewEdit: ( -    debugContext: SerializedDebugContext -  ) => Promise<FileEdit[] | undefined>; -  private _debounceTimer: NodeJS.Timeout | undefined; - -  private _debugContextChanged(debugContext: SerializedDebugContext): boolean { -    if (!this._lastDebugContext) { -      return true; -    } - -    return ( -      JSON.stringify(this._lastDebugContext) !== JSON.stringify(debugContext) -    ); -  } - -  private _debugContextComplete(debugContext: SerializedDebugContext): boolean { -    return debugContext.rangesInFiles.length > 0; -  } - -  public async preloadEdit(debugContext: SerializedDebugContext) { -    if (this._debounceTimer) { -      clearTimeout(this._debounceTimer); -    } -    if ( -      this._debugContextComplete(debugContext) && -      this._debugContextChanged(debugContext) -    ) { -      this._debounceTimer = setTimeout(async () => { -        console.log("Preloading edits"); -        this._cachedEdits = await this._fetchNewEdit(debugContext); -        this._lastDebugContext = debugContext; -      }, 200); -    } -  } - -  public async getEdit( -    debugContext: SerializedDebugContext -  ): Promise<FileEdit[]> { -    if (this._debugContextChanged(debugContext)) { -      console.log("Cache miss"); -      this._cachedEdits = await this._fetchNewEdit(debugContext); -    } else { -      console.log("Cache hit"); -    } - -    return this._cachedEdits!; -  } - -  constructor( -    fetchNewEdit: ( -      debugContext: SerializedDebugContext -    ) => Promise<FileEdit[] | undefined> -  ) { -    this._fetchNewEdit = fetchNewEdit; -  } -} diff --git a/extension/react-app/src/util/index.ts b/extension/react-app/src/util/index.ts index 458f9d95..c4168e13 100644 --- a/extension/react-app/src/util/index.ts +++ b/extension/react-app/src/util/index.ts @@ -1,27 +1,43 @@ -import { RangeInFile } from "../../../src/client"; +type Platform = "mac" | "linux" | "windows" | "unknown"; -export function readRangeInVirtualFileSystem( -  rangeInFile: RangeInFile, -  filesystem: { [filepath: string]: string } -): string | undefined { -  const range = rangeInFile.range; - -  let data = filesystem[rangeInFile.filepath]; -  if (data === undefined) { -    console.log("File not found"); -    return undefined; +export function getPlatform(): Platform { +  const platform = window.navigator.platform.toUpperCase(); +  if (platform.indexOf("MAC") >= 0) { +    return "mac"; +  } else if (platform.indexOf("LINUX") >= 0) { +    return "linux"; +  } else if (platform.indexOf("WIN") >= 0) { +    return "windows";    } else { -    let lines = data.toString().split("\n"); -    if (range.start.line === range.end.line) { -      return lines[rangeInFile.range.start.line].slice( -        rangeInFile.range.start.character, -        rangeInFile.range.end.character -      ); -    } else { -      let firstLine = lines[range.start.line].slice(range.start.character); -      let lastLine = lines[range.end.line].slice(0, range.end.character); -      let middleLines = lines.slice(range.start.line + 1, range.end.line); -      return [firstLine, ...middleLines, lastLine].join("\n"); -    } +    return "unknown"; +  } +} + +export function isMetaEquivalentKeyPressed(event: { +  metaKey: boolean; +  ctrlKey: boolean; +}): boolean { +  const platform = getPlatform(); +  switch (platform) { +    case "mac": +      return event.metaKey; +    case "linux": +    case "windows": +      return event.ctrlKey; +    default: +      return event.metaKey; +  } +} + +export function getMetaKeyLabel(): string { +  const platform = getPlatform(); +  switch (platform) { +    case "mac": +      return "⌘"; +    case "linux": +    case "windows": +      return "^"; +    default: +      return "⌘";    }  } | 
