about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/editors/code
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/editors/code')
-rw-r--r--src/tools/rust-analyzer/editors/code/.eslintignore2
-rw-r--r--src/tools/rust-analyzer/editors/code/.eslintrc.js37
-rw-r--r--src/tools/rust-analyzer/editors/code/.gitignore7
-rw-r--r--src/tools/rust-analyzer/editors/code/.prettierignore3
-rw-r--r--src/tools/rust-analyzer/editors/code/.prettierrc.js5
-rw-r--r--src/tools/rust-analyzer/editors/code/.vscodeignore14
-rw-r--r--src/tools/rust-analyzer/editors/code/LICENSE230
-rw-r--r--src/tools/rust-analyzer/editors/code/README.md52
-rw-r--r--src/tools/rust-analyzer/editors/code/icon.pngbin0 -> 15341 bytes
-rw-r--r--src/tools/rust-analyzer/editors/code/language-configuration.json42
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json2811
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json1613
-rw-r--r--src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json29
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ast_inspector.ts215
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts299
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts952
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts394
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts122
-rw-r--r--src/tools/rust-analyzer/editors/code/src/debug.ts202
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts180
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts403
-rw-r--r--src/tools/rust-analyzer/editors/code/src/persistent_state.ts20
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts175
-rw-r--r--src/tools/rust-analyzer/editors/code/src/snippets.ts87
-rw-r--r--src/tools/rust-analyzer/editors/code/src/tasks.ts138
-rw-r--r--src/tools/rust-analyzer/editors/code/src/toolchain.ts203
-rw-r--r--src/tools/rust-analyzer/editors/code/src/util.ts168
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/runTests.ts43
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/index.ts84
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts99
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts121
-rw-r--r--src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts61
-rw-r--r--src/tools/rust-analyzer/editors/code/tsconfig.eslint.json11
-rw-r--r--src/tools/rust-analyzer/editors/code/tsconfig.json19
34 files changed, 8841 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/editors/code/.eslintignore b/src/tools/rust-analyzer/editors/code/.eslintignore
new file mode 100644
index 00000000000..3a1e8e186f5
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.eslintignore
@@ -0,0 +1,2 @@
+node_modules
+.eslintrc.js
diff --git a/src/tools/rust-analyzer/editors/code/.eslintrc.js b/src/tools/rust-analyzer/editors/code/.eslintrc.js
new file mode 100644
index 00000000000..297e9fa1e5c
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.eslintrc.js
@@ -0,0 +1,37 @@
+module.exports = {
+    env: {
+        es6: true,
+        node: true,
+    },
+    extends: ["prettier"],
+    parser: "@typescript-eslint/parser",
+    parserOptions: {
+        project: "tsconfig.eslint.json",
+        tsconfigRootDir: __dirname,
+        sourceType: "module",
+    },
+    plugins: ["@typescript-eslint"],
+    rules: {
+        camelcase: ["error"],
+        eqeqeq: ["error", "always", { null: "ignore" }],
+        curly: ["error", "multi-line"],
+        "no-console": ["error", { allow: ["warn", "error"] }],
+        "prefer-const": "error",
+        "@typescript-eslint/member-delimiter-style": [
+            "error",
+            {
+                multiline: {
+                    delimiter: "semi",
+                    requireLast: true,
+                },
+                singleline: {
+                    delimiter: "semi",
+                    requireLast: false,
+                },
+            },
+        ],
+        "@typescript-eslint/semi": ["error", "always"],
+        "@typescript-eslint/no-unnecessary-type-assertion": "error",
+        "@typescript-eslint/no-floating-promises": "error",
+    },
+};
diff --git a/src/tools/rust-analyzer/editors/code/.gitignore b/src/tools/rust-analyzer/editors/code/.gitignore
new file mode 100644
index 00000000000..2c975a947eb
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.gitignore
@@ -0,0 +1,7 @@
+out
+node_modules
+server
+.vscode-test/
+*.vsix
+bundle
+vscode.proposed.d.ts
diff --git a/src/tools/rust-analyzer/editors/code/.prettierignore b/src/tools/rust-analyzer/editors/code/.prettierignore
new file mode 100644
index 00000000000..13baf68d7cc
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.prettierignore
@@ -0,0 +1,3 @@
+node_modules
+.vscode-test
+out
diff --git a/src/tools/rust-analyzer/editors/code/.prettierrc.js b/src/tools/rust-analyzer/editors/code/.prettierrc.js
new file mode 100644
index 00000000000..cafb12f0e6d
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.prettierrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+    // use 100 because it's Rustfmt's default
+    // https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width
+    printWidth: 100,
+};
diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore
new file mode 100644
index 00000000000..09dc27056b3
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/.vscodeignore
@@ -0,0 +1,14 @@
+**
+!icon.png
+!language-configuration.json
+!LICENSE
+!node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm
+!node_modules/@hpcc-js/wasm/dist/index.min.js
+!node_modules/d3-graphviz/build/d3-graphviz.min.js
+!node_modules/d3/dist/d3.min.js
+!out/main.js
+!package-lock.json
+!package.json
+!ra_syntax_tree.tmGrammar.json
+!server
+!README.md
diff --git a/src/tools/rust-analyzer/editors/code/LICENSE b/src/tools/rust-analyzer/editors/code/LICENSE
new file mode 100644
index 00000000000..d32e7fe8c91
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/LICENSE
@@ -0,0 +1,230 @@
+This software is licensed under either of the Apache License, Version
+2.0, or the MIT License. See below for their text.
+
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/tools/rust-analyzer/editors/code/README.md b/src/tools/rust-analyzer/editors/code/README.md
new file mode 100644
index 00000000000..36ab9818822
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/README.md
@@ -0,0 +1,52 @@
+# rust-analyzer
+
+This extension provides support for the [Rust programming language](https://www.rust-lang.org/).
+It is recommended over and replaces `rust-lang.rust`.
+
+## Features
+
+- [code completion] with [imports insertion]
+- go to [definition], [implementation], [type definition]
+- [find all references], [workspace symbol search], [symbol renaming]
+- [types and documentation on hover]
+- [inlay hints] for types and parameter names
+- [semantic syntax highlighting]
+- a lot of [assists (code actions)]
+- apply suggestions from errors
+- ... and many more, check out the [manual] to see them all
+
+[code completion]: https://rust-analyzer.github.io/manual.html#magic-completions
+[imports insertion]: https://rust-analyzer.github.io/manual.html#completion-with-autoimport
+[definition]: https://rust-analyzer.github.io/manual.html#go-to-definition
+[implementation]: https://rust-analyzer.github.io/manual.html#go-to-implementation
+[type definition]: https://rust-analyzer.github.io/manual.html#go-to-type-definition
+[find all references]: https://rust-analyzer.github.io/manual.html#find-all-references
+[workspace symbol search]: https://rust-analyzer.github.io/manual.html#workspace-symbol
+[symbol renaming]: https://rust-analyzer.github.io/manual.html#rename
+[types and documentation on hover]: https://rust-analyzer.github.io/manual.html#hover
+[inlay hints]: https://rust-analyzer.github.io/manual.html#inlay-hints
+[semantic syntax highlighting]: https://rust-analyzer.github.io/manual.html#semantic-syntax-highlighting
+[assists (code actions)]: https://rust-analyzer.github.io/manual.html#assists-code-actions
+[manual]: https://rust-analyzer.github.io/manual.html
+
+## Quick start
+
+1. Install [rustup].
+2. Install the [rust-analyzer extension].
+
+[rustup]: https://rustup.rs
+[rust-analyzer extension]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer
+
+## Configuration
+
+This extension provides configurations through VSCode's configuration settings. All configurations are under `rust-analyzer.*`.
+
+See [the manual](https://rust-analyzer.github.io/manual.html#vs-code-2) for more information on VSCode specific configurations.
+
+## Communication
+
+For usage and troubleshooting requests, please use the ["IDEs and Editors" category of the Rust forum](https://users.rust-lang.org/c/ide/14).
+
+## Documentation
+
+See [rust-analyzer.github.io](https://rust-analyzer.github.io/) for more information.
diff --git a/src/tools/rust-analyzer/editors/code/icon.png b/src/tools/rust-analyzer/editors/code/icon.png
new file mode 100644
index 00000000000..072090c6f4a
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/icon.png
Binary files differdiff --git a/src/tools/rust-analyzer/editors/code/language-configuration.json b/src/tools/rust-analyzer/editors/code/language-configuration.json
new file mode 100644
index 00000000000..b1ee0843e3e
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/language-configuration.json
@@ -0,0 +1,42 @@
+{
+    "comments": {
+        "lineComment": "//",
+        "blockComment": ["/*", "*/"]
+    },
+    "brackets": [
+        ["{", "}"],
+        ["[", "]"],
+        ["(", ")"]
+    ],
+    "colorizedBracketPairs": [
+        ["{", "}"],
+        ["[", "]"],
+        ["(", ")"]
+    ],
+    "autoClosingPairs": [
+        { "open": "{", "close": "}" },
+        { "open": "[", "close": "]" },
+        { "open": "(", "close": ")" },
+        { "open": "\"", "close": "\"", "notIn": ["string"] },
+        { "open": "/*", "close": " */" }
+    ],
+    "autoCloseBefore": ";:.,=}])> \n\t",
+    "surroundingPairs": [
+        ["{", "}"],
+        ["[", "]"],
+        ["(", ")"],
+        ["<", ">"],
+        ["\"", "\""],
+        ["'", "'"]
+    ],
+    "indentationRules": {
+        "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$",
+        "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]"
+    },
+    "folding": {
+        "markers": {
+            "start": "^\\s*//\\s*#?region\\b",
+            "end": "^\\s*//\\s*#?endregion\\b"
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
new file mode 100644
index 00000000000..0436681b1a0
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -0,0 +1,2811 @@
+{
+    "name": "rust-analyzer",
+    "version": "0.5.0-dev",
+    "lockfileVersion": 1,
+    "requires": true,
+    "dependencies": {
+        "@eslint/eslintrc": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+            "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
+            "dev": true,
+            "requires": {
+                "ajv": "^6.12.4",
+                "debug": "^4.3.2",
+                "espree": "^9.3.2",
+                "globals": "^13.15.0",
+                "ignore": "^5.2.0",
+                "import-fresh": "^3.2.1",
+                "js-yaml": "^4.1.0",
+                "minimatch": "^3.1.2",
+                "strip-json-comments": "^3.1.1"
+            }
+        },
+        "@hpcc-js/wasm": {
+            "version": "1.12.8",
+            "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz",
+            "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==",
+            "requires": {
+                "yargs": "^17.3.1"
+            }
+        },
+        "@humanwhocodes/config-array": {
+            "version": "0.9.5",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
+            "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
+            "dev": true,
+            "requires": {
+                "@humanwhocodes/object-schema": "^1.2.1",
+                "debug": "^4.1.1",
+                "minimatch": "^3.0.4"
+            }
+        },
+        "@humanwhocodes/object-schema": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+            "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+            "dev": true
+        },
+        "@nodelib/fs.scandir": {
+            "version": "2.1.5",
+            "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+            "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+            "dev": true,
+            "requires": {
+                "@nodelib/fs.stat": "2.0.5",
+                "run-parallel": "^1.1.9"
+            }
+        },
+        "@nodelib/fs.stat": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+            "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+            "dev": true
+        },
+        "@nodelib/fs.walk": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+            "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+            "dev": true,
+            "requires": {
+                "@nodelib/fs.scandir": "2.1.5",
+                "fastq": "^1.6.0"
+            }
+        },
+        "@tootallnate/once": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+            "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+            "dev": true
+        },
+        "@types/json-schema": {
+            "version": "7.0.11",
+            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+            "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+            "dev": true
+        },
+        "@types/node": {
+            "version": "16.11.43",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz",
+            "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==",
+            "dev": true
+        },
+        "@types/vscode": {
+            "version": "1.66.0",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz",
+            "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==",
+            "dev": true
+        },
+        "@typescript-eslint/eslint-plugin": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
+            "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/type-utils": "5.30.5",
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "functional-red-black-tree": "^1.0.1",
+                "ignore": "^5.2.0",
+                "regexpp": "^3.2.0",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/parser": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
+            "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "debug": "^4.3.4"
+            }
+        },
+        "@typescript-eslint/scope-manager": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
+            "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5"
+            }
+        },
+        "@typescript-eslint/type-utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
+            "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/utils": "5.30.5",
+                "debug": "^4.3.4",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/types": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
+            "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
+            "dev": true
+        },
+        "@typescript-eslint/typescript-estree": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
+            "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/visitor-keys": "5.30.5",
+                "debug": "^4.3.4",
+                "globby": "^11.1.0",
+                "is-glob": "^4.0.3",
+                "semver": "^7.3.7",
+                "tsutils": "^3.21.0"
+            }
+        },
+        "@typescript-eslint/utils": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
+            "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
+            "dev": true,
+            "requires": {
+                "@types/json-schema": "^7.0.9",
+                "@typescript-eslint/scope-manager": "5.30.5",
+                "@typescript-eslint/types": "5.30.5",
+                "@typescript-eslint/typescript-estree": "5.30.5",
+                "eslint-scope": "^5.1.1",
+                "eslint-utils": "^3.0.0"
+            }
+        },
+        "@typescript-eslint/visitor-keys": {
+            "version": "5.30.5",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
+            "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
+            "dev": true,
+            "requires": {
+                "@typescript-eslint/types": "5.30.5",
+                "eslint-visitor-keys": "^3.3.0"
+            }
+        },
+        "@vscode/test-electron": {
+            "version": "2.1.5",
+            "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz",
+            "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==",
+            "dev": true,
+            "requires": {
+                "http-proxy-agent": "^4.0.1",
+                "https-proxy-agent": "^5.0.0",
+                "rimraf": "^3.0.2",
+                "unzipper": "^0.10.11"
+            }
+        },
+        "acorn": {
+            "version": "8.7.1",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
+            "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+            "dev": true
+        },
+        "acorn-jsx": {
+            "version": "5.3.2",
+            "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+            "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+            "dev": true
+        },
+        "agent-base": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "dev": true,
+            "requires": {
+                "debug": "4"
+            }
+        },
+        "ajv": {
+            "version": "6.12.6",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+            "dev": true,
+            "requires": {
+                "fast-deep-equal": "^3.1.1",
+                "fast-json-stable-stringify": "^2.0.0",
+                "json-schema-traverse": "^0.4.1",
+                "uri-js": "^4.2.2"
+            }
+        },
+        "ansi-regex": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+        },
+        "ansi-styles": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+            "requires": {
+                "color-convert": "^2.0.1"
+            }
+        },
+        "argparse": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+            "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+            "dev": true
+        },
+        "array-union": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+            "dev": true
+        },
+        "azure-devops-node-api": {
+            "version": "11.2.0",
+            "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
+            "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
+            "dev": true,
+            "requires": {
+                "tunnel": "0.0.6",
+                "typed-rest-client": "^1.8.4"
+            }
+        },
+        "balanced-match": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+        },
+        "base64-js": {
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+            "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+            "dev": true
+        },
+        "big-integer": {
+            "version": "1.6.51",
+            "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+            "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+            "dev": true
+        },
+        "binary": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+            "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
+            "dev": true,
+            "requires": {
+                "buffers": "~0.1.1",
+                "chainsaw": "~0.1.0"
+            }
+        },
+        "bl": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+            "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+            "dev": true,
+            "requires": {
+                "buffer": "^5.5.0",
+                "inherits": "^2.0.4",
+                "readable-stream": "^3.4.0"
+            },
+            "dependencies": {
+                "readable-stream": {
+                    "version": "3.6.0",
+                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+                    "dev": true,
+                    "requires": {
+                        "inherits": "^2.0.3",
+                        "string_decoder": "^1.1.1",
+                        "util-deprecate": "^1.0.1"
+                    }
+                }
+            }
+        },
+        "bluebird": {
+            "version": "3.4.7",
+            "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+            "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
+            "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==",
+            "dev": true
+        },
+        "brace-expansion": {
+            "version": "1.1.11",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "requires": {
+                "balanced-match": "^1.0.0",
+                "concat-map": "0.0.1"
+            }
+        },
+        "braces": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+            "dev": true,
+            "requires": {
+                "fill-range": "^7.0.1"
+            }
+        },
+        "buffer": {
+            "version": "5.7.1",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+            "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+            "dev": true,
+            "requires": {
+                "base64-js": "^1.3.1",
+                "ieee754": "^1.1.13"
+            }
+        },
+        "buffer-crc32": {
+            "version": "0.2.13",
+            "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+            "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+            "dev": true
+        },
+        "buffer-indexof-polyfill": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+            "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
+            "dev": true
+        },
+        "buffers": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+            "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
+            "dev": true
+        },
+        "call-bind": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+            "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+            "dev": true,
+            "requires": {
+                "function-bind": "^1.1.1",
+                "get-intrinsic": "^1.0.2"
+            }
+        },
+        "callsites": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+            "dev": true
+        },
+        "chainsaw": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+            "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
+            "dev": true,
+            "requires": {
+                "traverse": ">=0.3.0 <0.4"
+            }
+        },
+        "chalk": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+            "dev": true,
+            "requires": {
+                "ansi-styles": "^4.1.0",
+                "supports-color": "^7.1.0"
+            }
+        },
+        "cheerio": {
+            "version": "1.0.0-rc.12",
+            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+            "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+            "dev": true,
+            "requires": {
+                "cheerio-select": "^2.1.0",
+                "dom-serializer": "^2.0.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1",
+                "htmlparser2": "^8.0.1",
+                "parse5": "^7.0.0",
+                "parse5-htmlparser2-tree-adapter": "^7.0.0"
+            }
+        },
+        "cheerio-select": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+            "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0",
+                "css-select": "^5.1.0",
+                "css-what": "^6.1.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.3",
+                "domutils": "^3.0.1"
+            }
+        },
+        "chownr": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+            "dev": true
+        },
+        "ci-info": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+            "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+            "dev": true
+        },
+        "cliui": {
+            "version": "7.0.4",
+            "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+            "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+            "requires": {
+                "string-width": "^4.2.0",
+                "strip-ansi": "^6.0.0",
+                "wrap-ansi": "^7.0.0"
+            }
+        },
+        "color-convert": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+            "requires": {
+                "color-name": "~1.1.4"
+            }
+        },
+        "color-name": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "commander": {
+            "version": "7.2.0",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+            "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
+        },
+        "concat-map": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+        },
+        "core-util-is": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+            "dev": true
+        },
+        "cross-env": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+            "dev": true,
+            "requires": {
+                "cross-spawn": "^7.0.1"
+            }
+        },
+        "cross-spawn": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+            "dev": true,
+            "requires": {
+                "path-key": "^3.1.0",
+                "shebang-command": "^2.0.0",
+                "which": "^2.0.1"
+            }
+        },
+        "css-select": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+            "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0",
+                "css-what": "^6.1.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "nth-check": "^2.0.1"
+            }
+        },
+        "css-what": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+            "dev": true
+        },
+        "d3": {
+            "version": "7.6.1",
+            "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz",
+            "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==",
+            "requires": {
+                "d3-array": "3",
+                "d3-axis": "3",
+                "d3-brush": "3",
+                "d3-chord": "3",
+                "d3-color": "3",
+                "d3-contour": "4",
+                "d3-delaunay": "6",
+                "d3-dispatch": "3",
+                "d3-drag": "3",
+                "d3-dsv": "3",
+                "d3-ease": "3",
+                "d3-fetch": "3",
+                "d3-force": "3",
+                "d3-format": "3",
+                "d3-geo": "3",
+                "d3-hierarchy": "3",
+                "d3-interpolate": "3",
+                "d3-path": "3",
+                "d3-polygon": "3",
+                "d3-quadtree": "3",
+                "d3-random": "3",
+                "d3-scale": "4",
+                "d3-scale-chromatic": "3",
+                "d3-selection": "3",
+                "d3-shape": "3",
+                "d3-time": "3",
+                "d3-time-format": "4",
+                "d3-timer": "3",
+                "d3-transition": "3",
+                "d3-zoom": "3"
+            },
+            "dependencies": {
+                "d3-selection": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
+                }
+            }
+        },
+        "d3-array": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz",
+            "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==",
+            "requires": {
+                "internmap": "1 - 2"
+            }
+        },
+        "d3-axis": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
+            "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="
+        },
+        "d3-brush": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
+            "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
+            "requires": {
+                "d3-dispatch": "1 - 3",
+                "d3-drag": "2 - 3",
+                "d3-interpolate": "1 - 3",
+                "d3-selection": "3",
+                "d3-transition": "3"
+            },
+            "dependencies": {
+                "d3-selection": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
+                }
+            }
+        },
+        "d3-chord": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
+            "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
+            "requires": {
+                "d3-path": "1 - 3"
+            }
+        },
+        "d3-color": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+            "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
+        },
+        "d3-contour": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz",
+            "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==",
+            "requires": {
+                "d3-array": "^3.2.0"
+            }
+        },
+        "d3-delaunay": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz",
+            "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==",
+            "requires": {
+                "delaunator": "5"
+            }
+        },
+        "d3-dispatch": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+            "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
+        },
+        "d3-drag": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+            "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+            "requires": {
+                "d3-dispatch": "1 - 3",
+                "d3-selection": "3"
+            },
+            "dependencies": {
+                "d3-selection": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
+                }
+            }
+        },
+        "d3-dsv": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+            "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+            "requires": {
+                "commander": "7",
+                "iconv-lite": "0.6",
+                "rw": "1"
+            }
+        },
+        "d3-ease": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+            "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="
+        },
+        "d3-fetch": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+            "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+            "requires": {
+                "d3-dsv": "1 - 3"
+            }
+        },
+        "d3-force": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+            "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+            "requires": {
+                "d3-dispatch": "1 - 3",
+                "d3-quadtree": "1 - 3",
+                "d3-timer": "1 - 3"
+            }
+        },
+        "d3-format": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+            "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="
+        },
+        "d3-geo": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz",
+            "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==",
+            "requires": {
+                "d3-array": "2.5.0 - 3"
+            }
+        },
+        "d3-graphviz": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz",
+            "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==",
+            "requires": {
+                "@hpcc-js/wasm": "1.12.8",
+                "d3-dispatch": "^2.0.0",
+                "d3-format": "^2.0.0",
+                "d3-interpolate": "^2.0.1",
+                "d3-path": "^2.0.0",
+                "d3-timer": "^2.0.0",
+                "d3-transition": "^2.0.0",
+                "d3-zoom": "^2.0.0"
+            },
+            "dependencies": {
+                "d3-color": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
+                    "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
+                },
+                "d3-dispatch": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz",
+                    "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA=="
+                },
+                "d3-drag": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz",
+                    "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==",
+                    "requires": {
+                        "d3-dispatch": "1 - 2",
+                        "d3-selection": "2"
+                    }
+                },
+                "d3-ease": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
+                    "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
+                },
+                "d3-format": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
+                    "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
+                },
+                "d3-interpolate": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
+                    "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
+                    "requires": {
+                        "d3-color": "1 - 2"
+                    }
+                },
+                "d3-path": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
+                    "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
+                },
+                "d3-timer": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz",
+                    "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA=="
+                },
+                "d3-transition": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz",
+                    "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==",
+                    "requires": {
+                        "d3-color": "1 - 2",
+                        "d3-dispatch": "1 - 2",
+                        "d3-ease": "1 - 2",
+                        "d3-interpolate": "1 - 2",
+                        "d3-timer": "1 - 2"
+                    }
+                },
+                "d3-zoom": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz",
+                    "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==",
+                    "requires": {
+                        "d3-dispatch": "1 - 2",
+                        "d3-drag": "2",
+                        "d3-interpolate": "1 - 2",
+                        "d3-selection": "2",
+                        "d3-transition": "2"
+                    }
+                }
+            }
+        },
+        "d3-hierarchy": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+            "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="
+        },
+        "d3-interpolate": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+            "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+            "requires": {
+                "d3-color": "1 - 3"
+            }
+        },
+        "d3-path": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz",
+            "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w=="
+        },
+        "d3-polygon": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
+            "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="
+        },
+        "d3-quadtree": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+            "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="
+        },
+        "d3-random": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+            "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="
+        },
+        "d3-scale": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+            "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+            "requires": {
+                "d3-array": "2.10.0 - 3",
+                "d3-format": "1 - 3",
+                "d3-interpolate": "1.2.0 - 3",
+                "d3-time": "2.1.1 - 3",
+                "d3-time-format": "2 - 4"
+            }
+        },
+        "d3-scale-chromatic": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz",
+            "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==",
+            "requires": {
+                "d3-color": "1 - 3",
+                "d3-interpolate": "1 - 3"
+            }
+        },
+        "d3-selection": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz",
+            "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA=="
+        },
+        "d3-shape": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz",
+            "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==",
+            "requires": {
+                "d3-path": "1 - 3"
+            }
+        },
+        "d3-time": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz",
+            "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==",
+            "requires": {
+                "d3-array": "2 - 3"
+            }
+        },
+        "d3-time-format": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+            "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+            "requires": {
+                "d3-time": "1 - 3"
+            }
+        },
+        "d3-timer": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+            "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="
+        },
+        "d3-transition": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+            "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+            "requires": {
+                "d3-color": "1 - 3",
+                "d3-dispatch": "1 - 3",
+                "d3-ease": "1 - 3",
+                "d3-interpolate": "1 - 3",
+                "d3-timer": "1 - 3"
+            }
+        },
+        "d3-zoom": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+            "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+            "requires": {
+                "d3-dispatch": "1 - 3",
+                "d3-drag": "2 - 3",
+                "d3-interpolate": "1 - 3",
+                "d3-selection": "2 - 3",
+                "d3-transition": "2 - 3"
+            }
+        },
+        "debug": {
+            "version": "4.3.4",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+            "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+            "dev": true,
+            "requires": {
+                "ms": "2.1.2"
+            }
+        },
+        "decompress-response": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+            "dev": true,
+            "requires": {
+                "mimic-response": "^3.1.0"
+            }
+        },
+        "deep-extend": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+            "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+            "dev": true
+        },
+        "deep-is": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+            "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+            "dev": true
+        },
+        "delaunator": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
+            "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
+            "requires": {
+                "robust-predicates": "^3.0.0"
+            }
+        },
+        "detect-libc": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+            "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+            "dev": true
+        },
+        "dir-glob": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+            "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+            "dev": true,
+            "requires": {
+                "path-type": "^4.0.0"
+            }
+        },
+        "doctrine": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+            "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+            "dev": true,
+            "requires": {
+                "esutils": "^2.0.2"
+            }
+        },
+        "dom-serializer": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+            "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "entities": "^4.2.0"
+            }
+        },
+        "domelementtype": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+            "dev": true
+        },
+        "domhandler": {
+            "version": "5.0.3",
+            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+            "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0"
+            }
+        },
+        "domutils": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+            "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+            "dev": true,
+            "requires": {
+                "dom-serializer": "^2.0.0",
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.1"
+            }
+        },
+        "duplexer2": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+            "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
+            "dev": true,
+            "requires": {
+                "readable-stream": "^2.0.2"
+            }
+        },
+        "emoji-regex": {
+            "version": "8.0.0",
+            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+        },
+        "end-of-stream": {
+            "version": "1.4.4",
+            "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+            "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+            "dev": true,
+            "requires": {
+                "once": "^1.4.0"
+            }
+        },
+        "entities": {
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
+            "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==",
+            "dev": true
+        },
+        "esbuild": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
+            "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
+            "dev": true,
+            "requires": {
+                "esbuild-android-64": "0.14.48",
+                "esbuild-android-arm64": "0.14.48",
+                "esbuild-darwin-64": "0.14.48",
+                "esbuild-darwin-arm64": "0.14.48",
+                "esbuild-freebsd-64": "0.14.48",
+                "esbuild-freebsd-arm64": "0.14.48",
+                "esbuild-linux-32": "0.14.48",
+                "esbuild-linux-64": "0.14.48",
+                "esbuild-linux-arm": "0.14.48",
+                "esbuild-linux-arm64": "0.14.48",
+                "esbuild-linux-mips64le": "0.14.48",
+                "esbuild-linux-ppc64le": "0.14.48",
+                "esbuild-linux-riscv64": "0.14.48",
+                "esbuild-linux-s390x": "0.14.48",
+                "esbuild-netbsd-64": "0.14.48",
+                "esbuild-openbsd-64": "0.14.48",
+                "esbuild-sunos-64": "0.14.48",
+                "esbuild-windows-32": "0.14.48",
+                "esbuild-windows-64": "0.14.48",
+                "esbuild-windows-arm64": "0.14.48"
+            }
+        },
+        "esbuild-android-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
+            "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-android-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
+            "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-darwin-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
+            "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-darwin-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
+            "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-freebsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
+            "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-freebsd-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
+            "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
+            "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
+            "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-arm": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
+            "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
+            "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-mips64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
+            "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-ppc64le": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
+            "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-riscv64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
+            "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-linux-s390x": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
+            "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-netbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
+            "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-openbsd-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
+            "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-sunos-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
+            "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-32": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
+            "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
+            "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
+            "dev": true,
+            "optional": true
+        },
+        "esbuild-windows-arm64": {
+            "version": "0.14.48",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
+            "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
+            "dev": true,
+            "optional": true
+        },
+        "escalade": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
+        },
+        "escape-string-regexp": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+            "dev": true
+        },
+        "eslint": {
+            "version": "8.19.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz",
+            "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==",
+            "dev": true,
+            "requires": {
+                "@eslint/eslintrc": "^1.3.0",
+                "@humanwhocodes/config-array": "^0.9.2",
+                "ajv": "^6.10.0",
+                "chalk": "^4.0.0",
+                "cross-spawn": "^7.0.2",
+                "debug": "^4.3.2",
+                "doctrine": "^3.0.0",
+                "escape-string-regexp": "^4.0.0",
+                "eslint-scope": "^7.1.1",
+                "eslint-utils": "^3.0.0",
+                "eslint-visitor-keys": "^3.3.0",
+                "espree": "^9.3.2",
+                "esquery": "^1.4.0",
+                "esutils": "^2.0.2",
+                "fast-deep-equal": "^3.1.3",
+                "file-entry-cache": "^6.0.1",
+                "functional-red-black-tree": "^1.0.1",
+                "glob-parent": "^6.0.1",
+                "globals": "^13.15.0",
+                "ignore": "^5.2.0",
+                "import-fresh": "^3.0.0",
+                "imurmurhash": "^0.1.4",
+                "is-glob": "^4.0.0",
+                "js-yaml": "^4.1.0",
+                "json-stable-stringify-without-jsonify": "^1.0.1",
+                "levn": "^0.4.1",
+                "lodash.merge": "^4.6.2",
+                "minimatch": "^3.1.2",
+                "natural-compare": "^1.4.0",
+                "optionator": "^0.9.1",
+                "regexpp": "^3.2.0",
+                "strip-ansi": "^6.0.1",
+                "strip-json-comments": "^3.1.0",
+                "text-table": "^0.2.0",
+                "v8-compile-cache": "^2.0.3"
+            },
+            "dependencies": {
+                "eslint-scope": {
+                    "version": "7.1.1",
+                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+                    "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+                    "dev": true,
+                    "requires": {
+                        "esrecurse": "^4.3.0",
+                        "estraverse": "^5.2.0"
+                    }
+                },
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "eslint-config-prettier": {
+            "version": "8.5.0",
+            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+            "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+            "dev": true
+        },
+        "eslint-scope": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+            "dev": true,
+            "requires": {
+                "esrecurse": "^4.3.0",
+                "estraverse": "^4.1.1"
+            }
+        },
+        "eslint-utils": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+            "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+            "dev": true,
+            "requires": {
+                "eslint-visitor-keys": "^2.0.0"
+            },
+            "dependencies": {
+                "eslint-visitor-keys": {
+                    "version": "2.1.0",
+                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+                    "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+                    "dev": true
+                }
+            }
+        },
+        "eslint-visitor-keys": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+            "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+            "dev": true
+        },
+        "espree": {
+            "version": "9.3.2",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
+            "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
+            "dev": true,
+            "requires": {
+                "acorn": "^8.7.1",
+                "acorn-jsx": "^5.3.2",
+                "eslint-visitor-keys": "^3.3.0"
+            }
+        },
+        "esquery": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+            "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+            "dev": true,
+            "requires": {
+                "estraverse": "^5.1.0"
+            },
+            "dependencies": {
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "esrecurse": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+            "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+            "dev": true,
+            "requires": {
+                "estraverse": "^5.2.0"
+            },
+            "dependencies": {
+                "estraverse": {
+                    "version": "5.3.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+                    "dev": true
+                }
+            }
+        },
+        "estraverse": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+            "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+            "dev": true
+        },
+        "esutils": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+            "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+            "dev": true
+        },
+        "expand-template": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+            "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+            "dev": true
+        },
+        "fast-deep-equal": {
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+            "dev": true
+        },
+        "fast-glob": {
+            "version": "3.2.11",
+            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+            "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+            "dev": true,
+            "requires": {
+                "@nodelib/fs.stat": "^2.0.2",
+                "@nodelib/fs.walk": "^1.2.3",
+                "glob-parent": "^5.1.2",
+                "merge2": "^1.3.0",
+                "micromatch": "^4.0.4"
+            },
+            "dependencies": {
+                "glob-parent": {
+                    "version": "5.1.2",
+                    "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+                    "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+                    "dev": true,
+                    "requires": {
+                        "is-glob": "^4.0.1"
+                    }
+                }
+            }
+        },
+        "fast-json-stable-stringify": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+            "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+            "dev": true
+        },
+        "fast-levenshtein": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+            "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+            "dev": true
+        },
+        "fastq": {
+            "version": "1.13.0",
+            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+            "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+            "dev": true,
+            "requires": {
+                "reusify": "^1.0.4"
+            }
+        },
+        "fd-slicer": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+            "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+            "dev": true,
+            "requires": {
+                "pend": "~1.2.0"
+            }
+        },
+        "file-entry-cache": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+            "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+            "dev": true,
+            "requires": {
+                "flat-cache": "^3.0.4"
+            }
+        },
+        "fill-range": {
+            "version": "7.0.1",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+            "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+            "dev": true,
+            "requires": {
+                "to-regex-range": "^5.0.1"
+            }
+        },
+        "flat-cache": {
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+            "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+            "dev": true,
+            "requires": {
+                "flatted": "^3.1.0",
+                "rimraf": "^3.0.2"
+            }
+        },
+        "flatted": {
+            "version": "3.2.6",
+            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
+            "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
+            "dev": true
+        },
+        "follow-redirects": {
+            "version": "1.15.1",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
+            "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
+            "dev": true
+        },
+        "fs-constants": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+            "dev": true
+        },
+        "fs.realpath": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+            "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+            "dev": true
+        },
+        "fstream": {
+            "version": "1.0.12",
+            "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+            "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+            "dev": true,
+            "requires": {
+                "graceful-fs": "^4.1.2",
+                "inherits": "~2.0.0",
+                "mkdirp": ">=0.5 0",
+                "rimraf": "2"
+            },
+            "dependencies": {
+                "rimraf": {
+                    "version": "2.7.1",
+                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+                    "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+                    "dev": true,
+                    "requires": {
+                        "glob": "^7.1.3"
+                    }
+                }
+            }
+        },
+        "function-bind": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+            "dev": true
+        },
+        "functional-red-black-tree": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+            "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+            "dev": true
+        },
+        "get-caller-file": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+        },
+        "get-intrinsic": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
+            "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
+            "dev": true,
+            "requires": {
+                "function-bind": "^1.1.1",
+                "has": "^1.0.3",
+                "has-symbols": "^1.0.3"
+            }
+        },
+        "github-from-package": {
+            "version": "0.0.0",
+            "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+            "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+            "dev": true
+        },
+        "glob": {
+            "version": "7.2.3",
+            "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+            "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+            "dev": true,
+            "requires": {
+                "fs.realpath": "^1.0.0",
+                "inflight": "^1.0.4",
+                "inherits": "2",
+                "minimatch": "^3.1.1",
+                "once": "^1.3.0",
+                "path-is-absolute": "^1.0.0"
+            }
+        },
+        "glob-parent": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+            "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+            "dev": true,
+            "requires": {
+                "is-glob": "^4.0.3"
+            }
+        },
+        "globals": {
+            "version": "13.16.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz",
+            "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==",
+            "dev": true,
+            "requires": {
+                "type-fest": "^0.20.2"
+            }
+        },
+        "globby": {
+            "version": "11.1.0",
+            "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+            "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+            "dev": true,
+            "requires": {
+                "array-union": "^2.1.0",
+                "dir-glob": "^3.0.1",
+                "fast-glob": "^3.2.9",
+                "ignore": "^5.2.0",
+                "merge2": "^1.4.1",
+                "slash": "^3.0.0"
+            }
+        },
+        "graceful-fs": {
+            "version": "4.2.10",
+            "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+            "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+            "dev": true
+        },
+        "has": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+            "dev": true,
+            "requires": {
+                "function-bind": "^1.1.1"
+            }
+        },
+        "has-flag": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+            "dev": true
+        },
+        "has-symbols": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+            "dev": true
+        },
+        "hosted-git-info": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+            "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+            "dev": true,
+            "requires": {
+                "lru-cache": "^6.0.0"
+            }
+        },
+        "htmlparser2": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+            "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+            "dev": true,
+            "requires": {
+                "domelementtype": "^2.3.0",
+                "domhandler": "^5.0.2",
+                "domutils": "^3.0.1",
+                "entities": "^4.3.0"
+            }
+        },
+        "http-proxy-agent": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+            "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+            "dev": true,
+            "requires": {
+                "@tootallnate/once": "1",
+                "agent-base": "6",
+                "debug": "4"
+            }
+        },
+        "https-proxy-agent": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+            "dev": true,
+            "requires": {
+                "agent-base": "6",
+                "debug": "4"
+            }
+        },
+        "iconv-lite": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+            "requires": {
+                "safer-buffer": ">= 2.1.2 < 3.0.0"
+            }
+        },
+        "ieee754": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+            "dev": true
+        },
+        "ignore": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+            "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+            "dev": true
+        },
+        "import-fresh": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+            "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+            "dev": true,
+            "requires": {
+                "parent-module": "^1.0.0",
+                "resolve-from": "^4.0.0"
+            }
+        },
+        "imurmurhash": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+            "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+            "dev": true
+        },
+        "inflight": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+            "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+            "dev": true,
+            "requires": {
+                "once": "^1.3.0",
+                "wrappy": "1"
+            }
+        },
+        "inherits": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+            "dev": true
+        },
+        "ini": {
+            "version": "1.3.8",
+            "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+            "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+            "dev": true
+        },
+        "internmap": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+            "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="
+        },
+        "is-ci": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+            "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+            "dev": true,
+            "requires": {
+                "ci-info": "^2.0.0"
+            }
+        },
+        "is-extglob": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+            "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+            "dev": true
+        },
+        "is-fullwidth-code-point": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+            "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+        },
+        "is-glob": {
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+            "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+            "dev": true,
+            "requires": {
+                "is-extglob": "^2.1.1"
+            }
+        },
+        "is-number": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+            "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+            "dev": true
+        },
+        "isarray": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+            "dev": true
+        },
+        "isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+            "dev": true
+        },
+        "js-yaml": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+            "dev": true,
+            "requires": {
+                "argparse": "^2.0.1"
+            }
+        },
+        "json-schema-traverse": {
+            "version": "0.4.1",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+            "dev": true
+        },
+        "json-stable-stringify-without-jsonify": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+            "dev": true
+        },
+        "keytar": {
+            "version": "7.9.0",
+            "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+            "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+            "dev": true,
+            "requires": {
+                "node-addon-api": "^4.3.0",
+                "prebuild-install": "^7.0.1"
+            }
+        },
+        "leven": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+            "dev": true
+        },
+        "levn": {
+            "version": "0.4.1",
+            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+            "dev": true,
+            "requires": {
+                "prelude-ls": "^1.2.1",
+                "type-check": "~0.4.0"
+            }
+        },
+        "linkify-it": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+            "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+            "dev": true,
+            "requires": {
+                "uc.micro": "^1.0.1"
+            }
+        },
+        "listenercount": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+            "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==",
+            "dev": true
+        },
+        "lodash.merge": {
+            "version": "4.6.2",
+            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+            "dev": true
+        },
+        "lru-cache": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+            "requires": {
+                "yallist": "^4.0.0"
+            }
+        },
+        "markdown-it": {
+            "version": "12.3.2",
+            "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+            "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+            "dev": true,
+            "requires": {
+                "argparse": "^2.0.1",
+                "entities": "~2.1.0",
+                "linkify-it": "^3.0.1",
+                "mdurl": "^1.0.1",
+                "uc.micro": "^1.0.5"
+            },
+            "dependencies": {
+                "entities": {
+                    "version": "2.1.0",
+                    "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+                    "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+                    "dev": true
+                }
+            }
+        },
+        "mdurl": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+            "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+            "dev": true
+        },
+        "merge2": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+            "dev": true
+        },
+        "micromatch": {
+            "version": "4.0.5",
+            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+            "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+            "dev": true,
+            "requires": {
+                "braces": "^3.0.2",
+                "picomatch": "^2.3.1"
+            }
+        },
+        "mime": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+            "dev": true
+        },
+        "mimic-response": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+            "dev": true
+        },
+        "minimatch": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+            "requires": {
+                "brace-expansion": "^1.1.7"
+            }
+        },
+        "minimist": {
+            "version": "1.2.6",
+            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+            "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+            "dev": true
+        },
+        "mkdirp": {
+            "version": "0.5.6",
+            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+            "dev": true,
+            "requires": {
+                "minimist": "^1.2.6"
+            }
+        },
+        "mkdirp-classic": {
+            "version": "0.5.3",
+            "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+            "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+            "dev": true
+        },
+        "ms": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+            "dev": true
+        },
+        "mute-stream": {
+            "version": "0.0.8",
+            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+            "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+            "dev": true
+        },
+        "napi-build-utils": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+            "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+            "dev": true
+        },
+        "natural-compare": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+            "dev": true
+        },
+        "node-abi": {
+            "version": "3.22.0",
+            "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
+            "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
+            "dev": true,
+            "requires": {
+                "semver": "^7.3.5"
+            }
+        },
+        "node-addon-api": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+            "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+            "dev": true
+        },
+        "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==",
+            "dev": true,
+            "requires": {
+                "boolbase": "^1.0.0"
+            }
+        },
+        "object-inspect": {
+            "version": "1.12.2",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+            "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+            "dev": true
+        },
+        "once": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+            "dev": true,
+            "requires": {
+                "wrappy": "1"
+            }
+        },
+        "optionator": {
+            "version": "0.9.1",
+            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+            "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+            "dev": true,
+            "requires": {
+                "deep-is": "^0.1.3",
+                "fast-levenshtein": "^2.0.6",
+                "levn": "^0.4.1",
+                "prelude-ls": "^1.2.1",
+                "type-check": "^0.4.0",
+                "word-wrap": "^1.2.3"
+            }
+        },
+        "ovsx": {
+            "version": "0.5.1",
+            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
+            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
+            "dev": true,
+            "requires": {
+                "commander": "^6.1.0",
+                "follow-redirects": "^1.14.6",
+                "is-ci": "^2.0.0",
+                "leven": "^3.1.0",
+                "tmp": "^0.2.1",
+                "vsce": "^2.6.3"
+            },
+            "dependencies": {
+                "commander": {
+                    "version": "6.2.1",
+                    "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+                    "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+                    "dev": true
+                }
+            }
+        },
+        "parent-module": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+            "dev": true,
+            "requires": {
+                "callsites": "^3.0.0"
+            }
+        },
+        "parse-semver": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+            "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
+            "dev": true,
+            "requires": {
+                "semver": "^5.1.0"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "5.7.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+                    "dev": true
+                }
+            }
+        },
+        "parse5": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
+            "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==",
+            "dev": true,
+            "requires": {
+                "entities": "^4.3.0"
+            }
+        },
+        "parse5-htmlparser2-tree-adapter": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+            "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+            "dev": true,
+            "requires": {
+                "domhandler": "^5.0.2",
+                "parse5": "^7.0.0"
+            }
+        },
+        "path-is-absolute": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+            "dev": true
+        },
+        "path-key": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+            "dev": true
+        },
+        "path-type": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+            "dev": true
+        },
+        "pend": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+            "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+            "dev": true
+        },
+        "picomatch": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+            "dev": true
+        },
+        "prebuild-install": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
+            "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
+            "dev": true,
+            "requires": {
+                "detect-libc": "^2.0.0",
+                "expand-template": "^2.0.3",
+                "github-from-package": "0.0.0",
+                "minimist": "^1.2.3",
+                "mkdirp-classic": "^0.5.3",
+                "napi-build-utils": "^1.0.1",
+                "node-abi": "^3.3.0",
+                "pump": "^3.0.0",
+                "rc": "^1.2.7",
+                "simple-get": "^4.0.0",
+                "tar-fs": "^2.0.0",
+                "tunnel-agent": "^0.6.0"
+            }
+        },
+        "prelude-ls": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+            "dev": true
+        },
+        "prettier": {
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+            "dev": true
+        },
+        "process-nextick-args": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+            "dev": true
+        },
+        "pump": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+            "dev": true,
+            "requires": {
+                "end-of-stream": "^1.1.0",
+                "once": "^1.3.1"
+            }
+        },
+        "punycode": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+            "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+            "dev": true
+        },
+        "qs": {
+            "version": "6.11.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+            "dev": true,
+            "requires": {
+                "side-channel": "^1.0.4"
+            }
+        },
+        "queue-microtask": {
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+            "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+            "dev": true
+        },
+        "rc": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+            "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+            "dev": true,
+            "requires": {
+                "deep-extend": "^0.6.0",
+                "ini": "~1.3.0",
+                "minimist": "^1.2.0",
+                "strip-json-comments": "~2.0.1"
+            },
+            "dependencies": {
+                "strip-json-comments": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+                    "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+                    "dev": true
+                }
+            }
+        },
+        "read": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+            "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
+            "dev": true,
+            "requires": {
+                "mute-stream": "~0.0.4"
+            }
+        },
+        "readable-stream": {
+            "version": "2.3.7",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+            "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+            "dev": true,
+            "requires": {
+                "core-util-is": "~1.0.0",
+                "inherits": "~2.0.3",
+                "isarray": "~1.0.0",
+                "process-nextick-args": "~2.0.0",
+                "safe-buffer": "~5.1.1",
+                "string_decoder": "~1.1.1",
+                "util-deprecate": "~1.0.1"
+            }
+        },
+        "regexpp": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+            "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+            "dev": true
+        },
+        "require-directory": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
+        },
+        "resolve-from": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+            "dev": true
+        },
+        "reusify": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+            "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+            "dev": true
+        },
+        "rimraf": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+            "dev": true,
+            "requires": {
+                "glob": "^7.1.3"
+            }
+        },
+        "robust-predicates": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
+            "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g=="
+        },
+        "run-parallel": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+            "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+            "dev": true,
+            "requires": {
+                "queue-microtask": "^1.2.2"
+            }
+        },
+        "rw": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+            "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
+        },
+        "safe-buffer": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+            "dev": true
+        },
+        "safer-buffer": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+        },
+        "sax": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+            "dev": true
+        },
+        "semver": {
+            "version": "7.3.7",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+            "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+            "requires": {
+                "lru-cache": "^6.0.0"
+            }
+        },
+        "setimmediate": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+            "dev": true
+        },
+        "shebang-command": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+            "dev": true,
+            "requires": {
+                "shebang-regex": "^3.0.0"
+            }
+        },
+        "shebang-regex": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+            "dev": true
+        },
+        "side-channel": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+            "dev": true,
+            "requires": {
+                "call-bind": "^1.0.0",
+                "get-intrinsic": "^1.0.2",
+                "object-inspect": "^1.9.0"
+            }
+        },
+        "simple-concat": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+            "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+            "dev": true
+        },
+        "simple-get": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+            "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+            "dev": true,
+            "requires": {
+                "decompress-response": "^6.0.0",
+                "once": "^1.3.1",
+                "simple-concat": "^1.0.0"
+            }
+        },
+        "slash": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+            "dev": true
+        },
+        "string-width": {
+            "version": "4.2.3",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+            "requires": {
+                "emoji-regex": "^8.0.0",
+                "is-fullwidth-code-point": "^3.0.0",
+                "strip-ansi": "^6.0.1"
+            }
+        },
+        "string_decoder": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+            "dev": true,
+            "requires": {
+                "safe-buffer": "~5.1.0"
+            }
+        },
+        "strip-ansi": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "requires": {
+                "ansi-regex": "^5.0.1"
+            }
+        },
+        "strip-json-comments": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+            "dev": true
+        },
+        "supports-color": {
+            "version": "7.2.0",
+            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+            "dev": true,
+            "requires": {
+                "has-flag": "^4.0.0"
+            }
+        },
+        "tar-fs": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+            "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+            "dev": true,
+            "requires": {
+                "chownr": "^1.1.1",
+                "mkdirp-classic": "^0.5.2",
+                "pump": "^3.0.0",
+                "tar-stream": "^2.1.4"
+            }
+        },
+        "tar-stream": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+            "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+            "dev": true,
+            "requires": {
+                "bl": "^4.0.3",
+                "end-of-stream": "^1.4.1",
+                "fs-constants": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.1.1"
+            },
+            "dependencies": {
+                "readable-stream": {
+                    "version": "3.6.0",
+                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+                    "dev": true,
+                    "requires": {
+                        "inherits": "^2.0.3",
+                        "string_decoder": "^1.1.1",
+                        "util-deprecate": "^1.0.1"
+                    }
+                }
+            }
+        },
+        "text-table": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+            "dev": true
+        },
+        "tmp": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+            "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+            "dev": true,
+            "requires": {
+                "rimraf": "^3.0.0"
+            }
+        },
+        "to-regex-range": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+            "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+            "dev": true,
+            "requires": {
+                "is-number": "^7.0.0"
+            }
+        },
+        "traverse": {
+            "version": "0.3.9",
+            "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+            "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
+            "dev": true
+        },
+        "tslib": {
+            "version": "2.4.0",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+            "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+            "dev": true
+        },
+        "tsutils": {
+            "version": "3.21.0",
+            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+            "dev": true,
+            "requires": {
+                "tslib": "^1.8.1"
+            },
+            "dependencies": {
+                "tslib": {
+                    "version": "1.14.1",
+                    "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+                    "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+                    "dev": true
+                }
+            }
+        },
+        "tunnel": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+            "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+            "dev": true
+        },
+        "tunnel-agent": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+            "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+            "dev": true,
+            "requires": {
+                "safe-buffer": "^5.0.1"
+            }
+        },
+        "type-check": {
+            "version": "0.4.0",
+            "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+            "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+            "dev": true,
+            "requires": {
+                "prelude-ls": "^1.2.1"
+            }
+        },
+        "type-fest": {
+            "version": "0.20.2",
+            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+            "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+            "dev": true
+        },
+        "typed-rest-client": {
+            "version": "1.8.9",
+            "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz",
+            "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==",
+            "dev": true,
+            "requires": {
+                "qs": "^6.9.1",
+                "tunnel": "0.0.6",
+                "underscore": "^1.12.1"
+            }
+        },
+        "typescript": {
+            "version": "4.7.4",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+            "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
+            "dev": true
+        },
+        "uc.micro": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+            "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+            "dev": true
+        },
+        "underscore": {
+            "version": "1.13.4",
+            "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
+            "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
+            "dev": true
+        },
+        "unzipper": {
+            "version": "0.10.11",
+            "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
+            "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
+            "dev": true,
+            "requires": {
+                "big-integer": "^1.6.17",
+                "binary": "~0.3.0",
+                "bluebird": "~3.4.1",
+                "buffer-indexof-polyfill": "~1.0.0",
+                "duplexer2": "~0.1.4",
+                "fstream": "^1.0.12",
+                "graceful-fs": "^4.2.2",
+                "listenercount": "~1.0.1",
+                "readable-stream": "~2.3.6",
+                "setimmediate": "~1.0.4"
+            }
+        },
+        "uri-js": {
+            "version": "4.4.1",
+            "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+            "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+            "dev": true,
+            "requires": {
+                "punycode": "^2.1.0"
+            }
+        },
+        "url-join": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+            "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+            "dev": true
+        },
+        "util-deprecate": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+            "dev": true
+        },
+        "v8-compile-cache": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+            "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+            "dev": true
+        },
+        "vsce": {
+            "version": "2.9.2",
+            "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz",
+            "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==",
+            "dev": true,
+            "requires": {
+                "azure-devops-node-api": "^11.0.1",
+                "chalk": "^2.4.2",
+                "cheerio": "^1.0.0-rc.9",
+                "commander": "^6.1.0",
+                "glob": "^7.0.6",
+                "hosted-git-info": "^4.0.2",
+                "keytar": "^7.7.0",
+                "leven": "^3.1.0",
+                "markdown-it": "^12.3.2",
+                "mime": "^1.3.4",
+                "minimatch": "^3.0.3",
+                "parse-semver": "^1.1.1",
+                "read": "^1.0.7",
+                "semver": "^5.1.0",
+                "tmp": "^0.2.1",
+                "typed-rest-client": "^1.8.4",
+                "url-join": "^4.0.1",
+                "xml2js": "^0.4.23",
+                "yauzl": "^2.3.1",
+                "yazl": "^2.2.2"
+            },
+            "dependencies": {
+                "ansi-styles": {
+                    "version": "3.2.1",
+                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+                    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+                    "dev": true,
+                    "requires": {
+                        "color-convert": "^1.9.0"
+                    }
+                },
+                "chalk": {
+                    "version": "2.4.2",
+                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+                    "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+                    "dev": true,
+                    "requires": {
+                        "ansi-styles": "^3.2.1",
+                        "escape-string-regexp": "^1.0.5",
+                        "supports-color": "^5.3.0"
+                    }
+                },
+                "color-convert": {
+                    "version": "1.9.3",
+                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+                    "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+                    "dev": true,
+                    "requires": {
+                        "color-name": "1.1.3"
+                    }
+                },
+                "color-name": {
+                    "version": "1.1.3",
+                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+                    "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+                    "dev": true
+                },
+                "commander": {
+                    "version": "6.2.1",
+                    "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+                    "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+                    "dev": true
+                },
+                "escape-string-regexp": {
+                    "version": "1.0.5",
+                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+                    "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+                    "dev": true
+                },
+                "has-flag": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+                    "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+                    "dev": true
+                },
+                "semver": {
+                    "version": "5.7.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+                    "dev": true
+                },
+                "supports-color": {
+                    "version": "5.5.0",
+                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+                    "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+                    "dev": true,
+                    "requires": {
+                        "has-flag": "^3.0.0"
+                    }
+                }
+            }
+        },
+        "vscode-jsonrpc": {
+            "version": "8.0.0-next.7",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz",
+            "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ=="
+        },
+        "vscode-languageclient": {
+            "version": "8.0.0-next.14",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz",
+            "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==",
+            "requires": {
+                "minimatch": "^3.0.4",
+                "semver": "^7.3.5",
+                "vscode-languageserver-protocol": "3.17.0-next.16"
+            }
+        },
+        "vscode-languageserver-protocol": {
+            "version": "3.17.0-next.16",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz",
+            "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==",
+            "requires": {
+                "vscode-jsonrpc": "8.0.0-next.7",
+                "vscode-languageserver-types": "3.17.0-next.9"
+            }
+        },
+        "vscode-languageserver-types": {
+            "version": "3.17.0-next.9",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz",
+            "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A=="
+        },
+        "which": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+            "dev": true,
+            "requires": {
+                "isexe": "^2.0.0"
+            }
+        },
+        "word-wrap": {
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+            "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+            "dev": true
+        },
+        "wrap-ansi": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+            "requires": {
+                "ansi-styles": "^4.0.0",
+                "string-width": "^4.1.0",
+                "strip-ansi": "^6.0.0"
+            }
+        },
+        "wrappy": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+            "dev": true
+        },
+        "xml2js": {
+            "version": "0.4.23",
+            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+            "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+            "dev": true,
+            "requires": {
+                "sax": ">=0.6.0",
+                "xmlbuilder": "~11.0.0"
+            }
+        },
+        "xmlbuilder": {
+            "version": "11.0.1",
+            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+            "dev": true
+        },
+        "y18n": {
+            "version": "5.0.8",
+            "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+            "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+        },
+        "yallist": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+        },
+        "yargs": {
+            "version": "17.5.1",
+            "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
+            "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
+            "requires": {
+                "cliui": "^7.0.2",
+                "escalade": "^3.1.1",
+                "get-caller-file": "^2.0.5",
+                "require-directory": "^2.1.1",
+                "string-width": "^4.2.3",
+                "y18n": "^5.0.5",
+                "yargs-parser": "^21.0.0"
+            }
+        },
+        "yargs-parser": {
+            "version": "21.0.1",
+            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
+            "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg=="
+        },
+        "yauzl": {
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+            "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+            "dev": true,
+            "requires": {
+                "buffer-crc32": "~0.2.3",
+                "fd-slicer": "~1.1.0"
+            }
+        },
+        "yazl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+            "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+            "dev": true,
+            "requires": {
+                "buffer-crc32": "~0.2.3"
+            }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
new file mode 100644
index 00000000000..a13798d8b36
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -0,0 +1,1613 @@
+{
+    "name": "rust-analyzer",
+    "displayName": "rust-analyzer",
+    "description": "Rust language support for Visual Studio Code",
+    "private": true,
+    "icon": "icon.png",
+    "version": "0.5.0-dev",
+    "releaseTag": null,
+    "publisher": "rust-lang",
+    "repository": {
+        "url": "https://github.com/rust-lang/rust-analyzer.git",
+        "type": "git"
+    },
+    "homepage": "https://rust-analyzer.github.io/",
+    "license": "MIT OR Apache-2.0",
+    "keywords": [
+        "rust"
+    ],
+    "categories": [
+        "Programming Languages"
+    ],
+    "engines": {
+        "vscode": "^1.66.0"
+    },
+    "enabledApiProposals": [],
+    "scripts": {
+        "vscode:prepublish": "npm run build-base -- --minify",
+        "package": "vsce package -o rust-analyzer.vsix",
+        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
+        "build": "npm run build-base -- --sourcemap",
+        "watch": "npm run build-base -- --sourcemap --watch",
+        "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
+        "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
+        "pretest": "tsc && npm run build",
+        "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js"
+    },
+    "dependencies": {
+        "d3": "^7.6.1",
+        "d3-graphviz": "^4.1.1",
+        "vscode-languageclient": "^8.0.0-next.14"
+    },
+    "devDependencies": {
+        "@types/node": "~16.11.7",
+        "@types/vscode": "~1.66.0",
+        "@typescript-eslint/eslint-plugin": "^5.30.5",
+        "@typescript-eslint/parser": "^5.30.5",
+        "@vscode/test-electron": "^2.1.5",
+        "cross-env": "^7.0.3",
+        "esbuild": "^0.14.48",
+        "eslint": "^8.19.0",
+        "eslint-config-prettier": "^8.5.0",
+        "ovsx": "^0.5.1",
+        "prettier": "^2.7.1",
+        "tslib": "^2.4.0",
+        "typescript": "^4.7.4",
+        "vsce": "^2.9.2"
+    },
+    "activationEvents": [
+        "onLanguage:rust",
+        "onCommand:rust-analyzer.analyzerStatus",
+        "onCommand:rust-analyzer.memoryUsage",
+        "onCommand:rust-analyzer.reloadWorkspace",
+        "workspaceContains:*/Cargo.toml",
+        "workspaceContains:*/rust-project.json"
+    ],
+    "main": "./out/main",
+    "contributes": {
+        "taskDefinitions": [
+            {
+                "type": "cargo",
+                "required": [
+                    "command"
+                ],
+                "properties": {
+                    "label": {
+                        "type": "string"
+                    },
+                    "command": {
+                        "type": "string"
+                    },
+                    "args": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        }
+                    },
+                    "env": {
+                        "type": "object",
+                        "patternProperties": {
+                            ".+": {
+                                "type": "string"
+                            }
+                        }
+                    }
+                }
+            }
+        ],
+        "commands": [
+            {
+                "command": "rust-analyzer.syntaxTree",
+                "title": "Show Syntax Tree",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.viewHir",
+                "title": "View Hir",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.viewFileText",
+                "title": "View File Text (as seen by the server)",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.viewItemTree",
+                "title": "Debug ItemTree",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.viewCrateGraph",
+                "title": "View Crate Graph",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.viewFullCrateGraph",
+                "title": "View Crate Graph (Full)",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.expandMacro",
+                "title": "Expand macro recursively",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.matchingBrace",
+                "title": "Find matching brace",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.parentModule",
+                "title": "Locate parent module",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.joinLines",
+                "title": "Join lines",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.run",
+                "title": "Run",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.copyRunCommandLine",
+                "title": "Copy Run Command Line",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.debug",
+                "title": "Debug",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.newDebugConfig",
+                "title": "Generate launch configuration",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.analyzerStatus",
+                "title": "Status",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.memoryUsage",
+                "title": "Memory Usage (Clears Database)",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.shuffleCrateGraph",
+                "title": "Shuffle Crate Graph",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.reloadWorkspace",
+                "title": "Reload workspace",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.reload",
+                "title": "Restart server",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.onEnter",
+                "title": "Enhanced enter key",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.ssr",
+                "title": "Structural Search Replace",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.serverVersion",
+                "title": "Show RA Version",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.toggleInlayHints",
+                "title": "Toggle inlay hints",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.openDocs",
+                "title": "Open docs under cursor",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.openCargoToml",
+                "title": "Open Cargo.toml",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.peekTests",
+                "title": "Peek related tests",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.moveItemUp",
+                "title": "Move item up",
+                "category": "Rust Analyzer"
+            },
+            {
+                "command": "rust-analyzer.moveItemDown",
+                "title": "Move item down",
+                "category": "Rust Analyzer"
+            }
+        ],
+        "keybindings": [
+            {
+                "command": "rust-analyzer.parentModule",
+                "key": "ctrl+shift+u",
+                "when": "editorTextFocus && editorLangId == rust"
+            },
+            {
+                "command": "rust-analyzer.matchingBrace",
+                "key": "ctrl+shift+m",
+                "when": "editorTextFocus && editorLangId == rust"
+            },
+            {
+                "command": "rust-analyzer.joinLines",
+                "key": "ctrl+shift+j",
+                "when": "editorTextFocus && editorLangId == rust"
+            }
+        ],
+        "configuration": {
+            "type": "object",
+            "title": "Rust Analyzer",
+            "properties": {
+                "rust-analyzer.cargoRunner": {
+                    "type": [
+                        "null",
+                        "string"
+                    ],
+                    "default": null,
+                    "description": "Custom cargo runner extension ID."
+                },
+                "rust-analyzer.runnableEnv": {
+                    "anyOf": [
+                        {
+                            "type": "null"
+                        },
+                        {
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "properties": {
+                                    "mask": {
+                                        "type": "string",
+                                        "description": "Runnable name mask"
+                                    },
+                                    "env": {
+                                        "type": "object",
+                                        "description": "Variables in form of { \"key\": \"value\"}"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "type": "object",
+                            "description": "Variables in form of { \"key\": \"value\"}"
+                        }
+                    ],
+                    "default": null,
+                    "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
+                },
+                "rust-analyzer.server.path": {
+                    "type": [
+                        "null",
+                        "string"
+                    ],
+                    "scope": "machine-overridable",
+                    "default": null,
+                    "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)."
+                },
+                "rust-analyzer.server.extraEnv": {
+                    "type": [
+                        "null",
+                        "object"
+                    ],
+                    "additionalProperties": {
+                        "type": [
+                            "string",
+                            "number"
+                        ]
+                    },
+                    "default": null,
+                    "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
+                },
+                "rust-analyzer.trace.server": {
+                    "type": "string",
+                    "scope": "window",
+                    "enum": [
+                        "off",
+                        "messages",
+                        "verbose"
+                    ],
+                    "enumDescriptions": [
+                        "No traces",
+                        "Error only",
+                        "Full log"
+                    ],
+                    "default": "off",
+                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
+                },
+                "rust-analyzer.trace.extension": {
+                    "description": "Enable logging of VS Code extensions itself.",
+                    "type": "boolean",
+                    "default": false
+                },
+                "rust-analyzer.debug.engine": {
+                    "type": "string",
+                    "enum": [
+                        "auto",
+                        "vadimcn.vscode-lldb",
+                        "ms-vscode.cpptools"
+                    ],
+                    "default": "auto",
+                    "description": "Preferred debug engine.",
+                    "markdownEnumDescriptions": [
+                        "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
+                        "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
+                        "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
+                    ]
+                },
+                "rust-analyzer.debug.sourceFileMap": {
+                    "type": [
+                        "object",
+                        "string"
+                    ],
+                    "const": "auto",
+                    "description": "Optional source file mappings passed to the debug engine.",
+                    "default": {
+                        "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
+                    }
+                },
+                "rust-analyzer.debug.openDebugPane": {
+                    "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
+                    "type": "boolean",
+                    "default": false
+                },
+                "rust-analyzer.debug.engineSettings": {
+                    "type": "object",
+                    "default": {},
+                    "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
+                },
+                "rust-analyzer.restartServerOnConfigChange": {
+                    "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "$generated-start": {},
+                "rust-analyzer.assist.expressionFillDefault": {
+                    "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
+                    "default": "todo",
+                    "type": "string",
+                    "enum": [
+                        "todo",
+                        "default"
+                    ],
+                    "enumDescriptions": [
+                        "Fill missing expressions with the `todo` macro",
+                        "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
+                    ]
+                },
+                "rust-analyzer.cachePriming.enable": {
+                    "markdownDescription": "Warm up caches on project load.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cachePriming.numThreads": {
+                    "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
+                    "default": 0,
+                    "type": "number",
+                    "minimum": 0,
+                    "maximum": 255
+                },
+                "rust-analyzer.cargo.autoreload": {
+                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cargo.buildScripts.enable": {
+                    "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cargo.buildScripts.overrideCommand": {
+                    "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "array"
+                    ],
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
+                    "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cargo.features": {
+                    "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
+                    "default": [],
+                    "anyOf": [
+                        {
+                            "type": "string",
+                            "enum": [
+                                "all"
+                            ],
+                            "enumDescriptions": [
+                                "Pass `--all-features` to cargo"
+                            ]
+                        },
+                        {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
+                    ]
+                },
+                "rust-analyzer.cargo.noDefaultFeatures": {
+                    "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cargo.noSysroot": {
+                    "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.cargo.target": {
+                    "markdownDescription": "Compilation target override (target triple).",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
+                "rust-analyzer.cargo.unsetTest": {
+                    "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
+                    "default": [
+                        "core"
+                    ],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.checkOnSave.allTargets": {
+                    "markdownDescription": "Check all targets and tests (`--all-targets`).",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.checkOnSave.command": {
+                    "markdownDescription": "Cargo command to use for `cargo check`.",
+                    "default": "check",
+                    "type": "string"
+                },
+                "rust-analyzer.checkOnSave.enable": {
+                    "markdownDescription": "Run specified `cargo check` command for diagnostics on save.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.checkOnSave.extraArgs": {
+                    "markdownDescription": "Extra arguments for `cargo check`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.checkOnSave.features": {
+                    "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
+                    "default": null,
+                    "anyOf": [
+                        {
+                            "type": "string",
+                            "enum": [
+                                "all"
+                            ],
+                            "enumDescriptions": [
+                                "Pass `--all-features` to cargo"
+                            ]
+                        },
+                        {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        },
+                        {
+                            "type": "null"
+                        }
+                    ]
+                },
+                "rust-analyzer.checkOnSave.noDefaultFeatures": {
+                    "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "boolean"
+                    ]
+                },
+                "rust-analyzer.checkOnSave.overrideCommand": {
+                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "array"
+                    ],
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.checkOnSave.target": {
+                    "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
+                "rust-analyzer.completion.autoimport.enable": {
+                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.completion.autoself.enable": {
+                    "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.completion.callable.snippets": {
+                    "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.",
+                    "default": "fill_arguments",
+                    "type": "string",
+                    "enum": [
+                        "fill_arguments",
+                        "add_parentheses",
+                        "none"
+                    ],
+                    "enumDescriptions": [
+                        "Add call parentheses and pre-fill arguments.",
+                        "Add call parentheses.",
+                        "Do no snippet completions for callables."
+                    ]
+                },
+                "rust-analyzer.completion.postfix.enable": {
+                    "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.completion.privateEditable.enable": {
+                    "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.completion.snippets.custom": {
+                    "markdownDescription": "Custom completion snippets.",
+                    "default": {
+                        "Arc::new": {
+                            "postfix": "arc",
+                            "body": "Arc::new(${receiver})",
+                            "requires": "std::sync::Arc",
+                            "description": "Put the expression into an `Arc`",
+                            "scope": "expr"
+                        },
+                        "Rc::new": {
+                            "postfix": "rc",
+                            "body": "Rc::new(${receiver})",
+                            "requires": "std::rc::Rc",
+                            "description": "Put the expression into an `Rc`",
+                            "scope": "expr"
+                        },
+                        "Box::pin": {
+                            "postfix": "pinbox",
+                            "body": "Box::pin(${receiver})",
+                            "requires": "std::boxed::Box",
+                            "description": "Put the expression into a pinned `Box`",
+                            "scope": "expr"
+                        },
+                        "Ok": {
+                            "postfix": "ok",
+                            "body": "Ok(${receiver})",
+                            "description": "Wrap the expression in a `Result::Ok`",
+                            "scope": "expr"
+                        },
+                        "Err": {
+                            "postfix": "err",
+                            "body": "Err(${receiver})",
+                            "description": "Wrap the expression in a `Result::Err`",
+                            "scope": "expr"
+                        },
+                        "Some": {
+                            "postfix": "some",
+                            "body": "Some(${receiver})",
+                            "description": "Wrap the expression in an `Option::Some`",
+                            "scope": "expr"
+                        }
+                    },
+                    "type": "object"
+                },
+                "rust-analyzer.diagnostics.disabled": {
+                    "markdownDescription": "List of rust-analyzer diagnostics to disable.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    },
+                    "uniqueItems": true
+                },
+                "rust-analyzer.diagnostics.enable": {
+                    "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.diagnostics.experimental.enable": {
+                    "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.diagnostics.remapPrefix": {
+                    "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.",
+                    "default": {},
+                    "type": "object"
+                },
+                "rust-analyzer.diagnostics.warningsAsHint": {
+                    "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.diagnostics.warningsAsInfo": {
+                    "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.files.excludeDirs": {
+                    "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.files.watcher": {
+                    "markdownDescription": "Controls file watching implementation.",
+                    "default": "client",
+                    "type": "string",
+                    "enum": [
+                        "client",
+                        "server"
+                    ],
+                    "enumDescriptions": [
+                        "Use the client (editor) to watch files for changes",
+                        "Use server-side file watching"
+                    ]
+                },
+                "rust-analyzer.highlightRelated.breakPoints.enable": {
+                    "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.highlightRelated.exitPoints.enable": {
+                    "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.highlightRelated.references.enable": {
+                    "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.highlightRelated.yieldPoints.enable": {
+                    "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.debug.enable": {
+                    "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.enable": {
+                    "markdownDescription": "Whether to show HoverActions in Rust files.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.gotoTypeDef.enable": {
+                    "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.implementations.enable": {
+                    "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.references.enable": {
+                    "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.actions.run.enable": {
+                    "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.documentation.enable": {
+                    "markdownDescription": "Whether to show documentation on hover.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.hover.links.enable": {
+                    "markdownDescription": "Use markdown syntax for links in hover.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.imports.granularity.enforce": {
+                    "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.imports.granularity.group": {
+                    "markdownDescription": "How imports should be grouped into use statements.",
+                    "default": "crate",
+                    "type": "string",
+                    "enum": [
+                        "preserve",
+                        "crate",
+                        "module",
+                        "item"
+                    ],
+                    "enumDescriptions": [
+                        "Do not change the granularity of any imports and preserve the original structure written by the developer.",
+                        "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
+                        "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
+                        "Flatten imports so that each has its own use statement."
+                    ]
+                },
+                "rust-analyzer.imports.group.enable": {
+                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.imports.merge.glob": {
+                    "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.imports.prefix": {
+                    "markdownDescription": "The path structure for newly inserted paths to use.",
+                    "default": "plain",
+                    "type": "string",
+                    "enum": [
+                        "plain",
+                        "self",
+                        "crate"
+                    ],
+                    "enumDescriptions": [
+                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
+                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
+                        "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
+                    ]
+                },
+                "rust-analyzer.inlayHints.bindingModeHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for binding modes.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.chainingHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for method chains.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.closingBraceHints.enable": {
+                    "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.closingBraceHints.minLines": {
+                    "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
+                    "default": 25,
+                    "type": "integer",
+                    "minimum": 0
+                },
+                "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for return types of closures.",
+                    "default": "never",
+                    "type": "string",
+                    "enum": [
+                        "always",
+                        "never",
+                        "with_block"
+                    ],
+                    "enumDescriptions": [
+                        "Always show type hints for return types of closures.",
+                        "Never show type hints for return types of closures.",
+                        "Only show type hints for return types of closures with blocks."
+                    ]
+                },
+                "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
+                    "default": "never",
+                    "type": "string",
+                    "enum": [
+                        "always",
+                        "never",
+                        "skip_trivial"
+                    ],
+                    "enumDescriptions": [
+                        "Always show lifetime elision hints.",
+                        "Never show lifetime elision hints.",
+                        "Only show lifetime elision hints if a return type is involved."
+                    ]
+                },
+                "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": {
+                    "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.maxLength": {
+                    "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
+                    "default": 25,
+                    "type": [
+                        "null",
+                        "integer"
+                    ],
+                    "minimum": 0
+                },
+                "rust-analyzer.inlayHints.parameterHints.enable": {
+                    "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.reborrowHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
+                    "default": "never",
+                    "type": "string",
+                    "enum": [
+                        "always",
+                        "never",
+                        "mutable"
+                    ],
+                    "enumDescriptions": [
+                        "Always show reborrow hints.",
+                        "Never show reborrow hints.",
+                        "Only show mutable reborrow hints."
+                    ]
+                },
+                "rust-analyzer.inlayHints.renderColons": {
+                    "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.typeHints.enable": {
+                    "markdownDescription": "Whether to show inlay type hints for variables.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
+                    "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
+                    "markdownDescription": "Whether to hide inlay type hints for constructors.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.joinLines.joinAssignments": {
+                    "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.joinLines.joinElseIf": {
+                    "markdownDescription": "Join lines inserts else between consecutive ifs.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.joinLines.removeTrailingComma": {
+                    "markdownDescription": "Join lines removes trailing commas.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.joinLines.unwrapTrivialBlock": {
+                    "markdownDescription": "Join lines unwraps trivial blocks.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.debug.enable": {
+                    "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.enable": {
+                    "markdownDescription": "Whether to show CodeLens in Rust files.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.forceCustomCommands": {
+                    "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.implementations.enable": {
+                    "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.references.adt.enable": {
+                    "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.references.enumVariant.enable": {
+                    "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.references.method.enable": {
+                    "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.references.trait.enable": {
+                    "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.lens.run.enable": {
+                    "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.linkedProjects": {
+                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": [
+                            "string",
+                            "object"
+                        ]
+                    }
+                },
+                "rust-analyzer.lru.capacity": {
+                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "integer"
+                    ],
+                    "minimum": 0
+                },
+                "rust-analyzer.notifications.cargoTomlNotFound": {
+                    "markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.procMacro.attributes.enable": {
+                    "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.procMacro.enable": {
+                    "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.procMacro.ignored": {
+                    "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
+                    "default": {},
+                    "type": "object"
+                },
+                "rust-analyzer.procMacro.server": {
+                    "markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
+                "rust-analyzer.runnables.command": {
+                    "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
+                "rust-analyzer.runnables.extraArgs": {
+                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.rustc.source": {
+                    "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
+                "rust-analyzer.rustfmt.extraArgs": {
+                    "markdownDescription": "Additional arguments to `rustfmt`.",
+                    "default": [],
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.rustfmt.overrideCommand": {
+                    "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "array"
+                    ],
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "rust-analyzer.rustfmt.rangeFormatting.enable": {
+                    "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.strings.enable": {
+                    "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.signatureInfo.detail": {
+                    "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.",
+                    "default": "full",
+                    "type": "string",
+                    "enum": [
+                        "full",
+                        "parameters"
+                    ],
+                    "enumDescriptions": [
+                        "Show the entire signature.",
+                        "Show only the parameters."
+                    ]
+                },
+                "rust-analyzer.signatureInfo.documentation.enable": {
+                    "markdownDescription": "Show documentation.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.typing.autoClosingAngleBrackets.enable": {
+                    "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.workspace.symbol.search.kind": {
+                    "markdownDescription": "Workspace symbol search kind.",
+                    "default": "only_types",
+                    "type": "string",
+                    "enum": [
+                        "only_types",
+                        "all_symbols"
+                    ],
+                    "enumDescriptions": [
+                        "Search for types only.",
+                        "Search for all symbols kinds."
+                    ]
+                },
+                "rust-analyzer.workspace.symbol.search.limit": {
+                    "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.",
+                    "default": 128,
+                    "type": "integer",
+                    "minimum": 0
+                },
+                "rust-analyzer.workspace.symbol.search.scope": {
+                    "markdownDescription": "Workspace symbol search scope.",
+                    "default": "workspace",
+                    "type": "string",
+                    "enum": [
+                        "workspace",
+                        "workspace_and_dependencies"
+                    ],
+                    "enumDescriptions": [
+                        "Search in current workspace only.",
+                        "Search in current workspace and dependencies."
+                    ]
+                },
+                "$generated-end": {}
+            }
+        },
+        "problemPatterns": [
+            {
+                "name": "rustc",
+                "patterns": [
+                    {
+                        "regexp": "^(warning|warn|error)(?:\\[(.*?)\\])?: (.*)$",
+                        "severity": 1,
+                        "code": 2,
+                        "message": 3
+                    },
+                    {
+                        "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$",
+                        "file": 1,
+                        "line": 2,
+                        "column": 3
+                    }
+                ]
+            },
+            {
+                "name": "rustc-json",
+                "patterns": [
+                    {
+                        "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$",
+                        "message": 1,
+                        "file": 2,
+                        "line": 3,
+                        "endLine": 4,
+                        "column": 5,
+                        "endColumn": 6
+                    }
+                ]
+            }
+        ],
+        "languages": [
+            {
+                "id": "ra_syntax_tree",
+                "extensions": [
+                    ".rast"
+                ]
+            },
+            {
+                "id": "rust",
+                "extensions": [
+                    ".rs"
+                ],
+                "aliases": [
+                    "Rust",
+                    "rs"
+                ],
+                "configuration": "language-configuration.json"
+            }
+        ],
+        "grammars": [
+            {
+                "language": "ra_syntax_tree",
+                "scopeName": "source.ra_syntax_tree",
+                "path": "ra_syntax_tree.tmGrammar.json"
+            }
+        ],
+        "problemMatchers": [
+            {
+                "name": "rustc",
+                "owner": "rustc",
+                "source": "rustc",
+                "fileLocation": [
+                    "autoDetect",
+                    "${workspaceRoot}"
+                ],
+                "pattern": "$rustc"
+            },
+            {
+                "name": "rustc-json",
+                "owner": "rustc",
+                "source": "rustc",
+                "fileLocation": [
+                    "autoDetect",
+                    "${workspaceRoot}"
+                ],
+                "pattern": "$rustc-json"
+            },
+            {
+                "name": "rustc-watch",
+                "owner": "rustc",
+                "source": "rustc",
+                "fileLocation": [
+                    "autoDetect",
+                    "${workspaceRoot}"
+                ],
+                "background": {
+                    "beginsPattern": "^\\[Running\\b",
+                    "endsPattern": "^\\[Finished running\\b"
+                },
+                "pattern": "$rustc"
+            }
+        ],
+        "colors": [
+            {
+                "id": "rust_analyzer.syntaxTreeBorder",
+                "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
+                "defaults": {
+                    "dark": "#ffffff",
+                    "light": "#b700ff",
+                    "highContrast": "#b700ff"
+                }
+            }
+        ],
+        "semanticTokenTypes": [
+            {
+                "id": "angle",
+                "description": "Style for < or >",
+                "superType": "punctuation"
+            },
+            {
+                "id": "arithmetic",
+                "description": "Style for arithmetic operators",
+                "superType": "operator"
+            },
+            {
+                "id": "attribute",
+                "description": "Style for attributes"
+            },
+            {
+                "id": "attributeBracket",
+                "description": "Style for attribute invocation brackets, that is the `#[` and `]` tokens",
+                "superType": "punctuation"
+            },
+            {
+                "id": "bitwise",
+                "description": "Style for bitwise operators",
+                "superType": "operator"
+            },
+            {
+                "id": "boolean",
+                "description": "Style for boolean literals",
+                "superType": "keyword"
+            },
+            {
+                "id": "brace",
+                "description": "Style for { or }",
+                "superType": "punctuation"
+            },
+            {
+                "id": "bracket",
+                "description": "Style for [ or ]",
+                "superType": "punctuation"
+            },
+            {
+                "id": "builtinAttribute",
+                "description": "Style for builtin attributes",
+                "superType": "attribute"
+            },
+            {
+                "id": "builtinType",
+                "description": "Style for builtin types",
+                "superType": "type"
+            },
+            {
+                "id": "character",
+                "description": "Style for character literals",
+                "superType": "string"
+            },
+            {
+                "id": "colon",
+                "description": "Style for :",
+                "superType": "punctuation"
+            },
+            {
+                "id": "comma",
+                "description": "Style for ,",
+                "superType": "punctuation"
+            },
+            {
+                "id": "comparison",
+                "description": "Style for comparison operators",
+                "superType": "operator"
+            },
+            {
+                "id": "constParameter",
+                "description": "Style for const generics"
+            },
+            {
+                "id": "derive",
+                "description": "Style for derives",
+                "superType": "attribute"
+            },
+            {
+                "id": "dot",
+                "description": "Style for .",
+                "superType": "punctuation"
+            },
+            {
+                "id": "escapeSequence",
+                "description": "Style for char escapes in strings"
+            },
+            {
+                "id": "formatSpecifier",
+                "description": "Style for {} placeholders in format strings"
+            },
+            {
+                "id": "label",
+                "description": "Style for labels"
+            },
+            {
+                "id": "lifetime",
+                "description": "Style for lifetimes"
+            },
+            {
+                "id": "logical",
+                "description": "Style for logic operators",
+                "superType": "operator"
+            },
+            {
+                "id": "macroBang",
+                "description": "Style for the ! token of macro calls",
+                "superType": "punctuation"
+            },
+            {
+                "id": "operator",
+                "description": "Style for operators",
+                "superType": "punctuation"
+            },
+            {
+                "id": "parenthesis",
+                "description": "Style for ( or )",
+                "superType": "punctuation"
+            },
+            {
+                "id": "punctuation",
+                "description": "Style for generic punctuation"
+            },
+            {
+                "id": "selfKeyword",
+                "description": "Style for the self keyword",
+                "superType": "keyword"
+            },
+            {
+                "id": "selfTypeKeyword",
+                "description": "Style for the self type keyword",
+                "superType": "keyword"
+            },
+            {
+                "id": "semicolon",
+                "description": "Style for ;",
+                "superType": "punctuation"
+            },
+            {
+                "id": "typeAlias",
+                "description": "Style for type aliases",
+                "superType": "type"
+            },
+            {
+                "id": "union",
+                "description": "Style for C-style untagged unions",
+                "superType": "type"
+            },
+            {
+                "id": "unresolvedReference",
+                "description": "Style for names which can not be resolved due to compilation errors"
+            }
+        ],
+        "semanticTokenModifiers": [
+            {
+                "id": "async",
+                "description": "Style for async functions and the `async` and `await` keywords"
+            },
+            {
+                "id": "attribute",
+                "description": "Style for elements within attributes"
+            },
+            {
+                "id": "callable",
+                "description": "Style for locals whose types implements one of the `Fn*` traits"
+            },
+            {
+                "id": "constant",
+                "description": "Style for compile-time constants"
+            },
+            {
+                "id": "consuming",
+                "description": "Style for locals that are being consumed when use in a function call"
+            },
+            {
+                "id": "controlFlow",
+                "description": "Style for control-flow related tokens, this includes the `?` operator"
+            },
+            {
+                "id": "crateRoot",
+                "description": "Style for names resolving to a crate root"
+            },
+            {
+                "id": "injected",
+                "description": "Style for doc-string injected highlighting like rust source blocks in documentation"
+            },
+            {
+                "id": "intraDocLink",
+                "description": "Style for intra doc links in doc-strings"
+            },
+            {
+                "id": "library",
+                "description": "Style for items that are defined outside of the current crate"
+            },
+            {
+                "id": "mutable",
+                "description": "Style for mutable locals and statics as well as functions taking `&mut self`"
+            },
+            {
+                "id": "public",
+                "description": "Style for items that are from the current crate and are `pub`"
+            },
+            {
+                "id": "reference",
+                "description": "Style for locals behind a reference and functions taking `self` by reference"
+            },
+            {
+                "id": "trait",
+                "description": "Style for associated trait items"
+            },
+            {
+                "id": "unsafe",
+                "description": "Style for unsafe operations, like unsafe function calls, as well as the `unsafe` token"
+            }
+        ],
+        "semanticTokenScopes": [
+            {
+                "language": "rust",
+                "scopes": {
+                    "attribute": [
+                        "meta.attribute.rust"
+                    ],
+                    "boolean": [
+                        "constant.language.boolean.rust"
+                    ],
+                    "builtinType": [
+                        "support.type.primitive.rust"
+                    ],
+                    "constParameter": [
+                        "constant.other.caps.rust"
+                    ],
+                    "enum": [
+                        "entity.name.type.enum.rust"
+                    ],
+                    "formatSpecifier": [
+                        "punctuation.section.embedded.rust"
+                    ],
+                    "function": [
+                        "entity.name.function.rust"
+                    ],
+                    "interface": [
+                        "entity.name.type.trait.rust"
+                    ],
+                    "keyword": [
+                        "keyword.other.rust"
+                    ],
+                    "keyword.controlFlow": [
+                        "keyword.control.rust"
+                    ],
+                    "lifetime": [
+                        "storage.modifier.lifetime.rust"
+                    ],
+                    "macroBang": [
+                        "entity.name.function.macro.rust"
+                    ],
+                    "method": [
+                        "entity.name.function.rust"
+                    ],
+                    "struct": [
+                        "entity.name.type.struct.rust"
+                    ],
+                    "typeAlias": [
+                        "entity.name.type.declaration.rust"
+                    ],
+                    "union": [
+                        "entity.name.type.union.rust"
+                    ],
+                    "variable": [
+                        "variable.other.rust"
+                    ],
+                    "variable.constant": [
+                        "variable.other.constant.rust"
+                    ],
+                    "*.mutable": [
+                        "markup.underline"
+                    ]
+                }
+            }
+        ],
+        "menus": {
+            "commandPalette": [
+                {
+                    "command": "rust-analyzer.syntaxTree",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.viewHir",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.viewFileText",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.expandMacro",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.matchingBrace",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.parentModule",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.joinLines",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.run",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.debug",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.newDebugConfig",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.analyzerStatus",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.memoryUsage",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.reloadWorkspace",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.reload",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.onEnter",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.ssr",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.serverVersion",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.toggleInlayHints",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.openDocs",
+                    "when": "inRustProject"
+                },
+                {
+                    "command": "rust-analyzer.openCargoToml",
+                    "when": "inRustProject"
+                }
+            ],
+            "editor/context": [
+                {
+                    "command": "rust-analyzer.peekTests",
+                    "when": "inRustProject",
+                    "group": "navigation@1000"
+                }
+            ]
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json b/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json
new file mode 100644
index 00000000000..279e7bafa0b
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json
@@ -0,0 +1,29 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+
+    "scopeName": "source.ra_syntax_tree",
+    "patterns": [
+        { "include": "#node_type" },
+        { "include": "#node_range_index" },
+        { "include": "#token_text" }
+    ],
+    "repository": {
+        "node_type": {
+            "match": "^\\s*([A-Z_][A-Z_0-9]*?)@",
+            "captures": {
+                "1": {
+                    "name": "entity.name.class"
+                }
+            }
+        },
+        "node_range_index": {
+            "match": "\\d+",
+            "name": "constant.numeric"
+        },
+        "token_text": {
+            "match": "\".+\"",
+            "name": "string"
+        }
+    },
+    "fileTypes": ["rast"]
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
new file mode 100644
index 00000000000..e57fb20e2cf
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
@@ -0,0 +1,215 @@
+import * as vscode from "vscode";
+
+import { Ctx, Disposable } from "./ctx";
+import { RustEditor, isRustEditor } from "./util";
+
+// FIXME: consider implementing this via the Tree View API?
+// https://code.visualstudio.com/api/extension-guides/tree-view
+export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
+    private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
+        borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"),
+        borderStyle: "solid",
+        borderWidth: "2px",
+    });
+    private rustEditor: undefined | RustEditor;
+
+    // Lazy rust token range -> syntax tree file range.
+    private readonly rust2Ast = new Lazy(() => {
+        const astEditor = this.findAstTextEditor();
+        if (!this.rustEditor || !astEditor) return undefined;
+
+        const buf: [vscode.Range, vscode.Range][] = [];
+        for (let i = 0; i < astEditor.document.lineCount; ++i) {
+            const astLine = astEditor.document.lineAt(i);
+
+            // Heuristically look for nodes with quoted text (which are token nodes)
+            const isTokenNode = astLine.text.lastIndexOf('"') >= 0;
+            if (!isTokenNode) continue;
+
+            const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text);
+            if (!rustRange) continue;
+
+            buf.push([rustRange, this.findAstNodeRange(astLine)]);
+        }
+        return buf;
+    });
+
+    constructor(ctx: Ctx) {
+        ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this));
+        ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
+        vscode.workspace.onDidCloseTextDocument(
+            this.onDidCloseTextDocument,
+            this,
+            ctx.subscriptions
+        );
+        vscode.workspace.onDidChangeTextDocument(
+            this.onDidChangeTextDocument,
+            this,
+            ctx.subscriptions
+        );
+        vscode.window.onDidChangeVisibleTextEditors(
+            this.onDidChangeVisibleTextEditors,
+            this,
+            ctx.subscriptions
+        );
+
+        ctx.pushCleanup(this);
+    }
+    dispose() {
+        this.setRustEditor(undefined);
+    }
+
+    private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+        if (
+            this.rustEditor &&
+            event.document.uri.toString() === this.rustEditor.document.uri.toString()
+        ) {
+            this.rust2Ast.reset();
+        }
+    }
+
+    private onDidCloseTextDocument(doc: vscode.TextDocument) {
+        if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) {
+            this.setRustEditor(undefined);
+        }
+    }
+
+    private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) {
+        if (!this.findAstTextEditor()) {
+            this.setRustEditor(undefined);
+            return;
+        }
+        this.setRustEditor(editors.find(isRustEditor));
+    }
+
+    private findAstTextEditor(): undefined | vscode.TextEditor {
+        return vscode.window.visibleTextEditors.find(
+            (it) => it.document.uri.scheme === "rust-analyzer"
+        );
+    }
+
+    private setRustEditor(newRustEditor: undefined | RustEditor) {
+        if (this.rustEditor && this.rustEditor !== newRustEditor) {
+            this.rustEditor.setDecorations(this.astDecorationType, []);
+            this.rust2Ast.reset();
+        }
+        this.rustEditor = newRustEditor;
+    }
+
+    // additional positional params are omitted
+    provideDefinition(
+        doc: vscode.TextDocument,
+        pos: vscode.Position
+    ): vscode.ProviderResult<vscode.DefinitionLink[]> {
+        if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) {
+            return;
+        }
+
+        const astEditor = this.findAstTextEditor();
+        if (!astEditor) return;
+
+        const rust2AstRanges = this.rust2Ast
+            .get()
+            ?.find(([rustRange, _]) => rustRange.contains(pos));
+        if (!rust2AstRanges) return;
+
+        const [rustFileRange, astFileRange] = rust2AstRanges;
+
+        astEditor.revealRange(astFileRange);
+        astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end);
+
+        return [
+            {
+                targetRange: astFileRange,
+                targetUri: astEditor.document.uri,
+                originSelectionRange: rustFileRange,
+                targetSelectionRange: astFileRange,
+            },
+        ];
+    }
+
+    // additional positional params are omitted
+    provideHover(
+        doc: vscode.TextDocument,
+        hoverPosition: vscode.Position
+    ): vscode.ProviderResult<vscode.Hover> {
+        if (!this.rustEditor) return;
+
+        const astFileLine = doc.lineAt(hoverPosition.line);
+
+        const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text);
+        if (!rustFileRange) return;
+
+        this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]);
+        this.rustEditor.revealRange(rustFileRange);
+
+        const rustSourceCode = this.rustEditor.document.getText(rustFileRange);
+        const astFileRange = this.findAstNodeRange(astFileLine);
+
+        return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange);
+    }
+
+    private findAstNodeRange(astLine: vscode.TextLine): vscode.Range {
+        const lineOffset = astLine.range.start;
+        const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex);
+        const end = lineOffset.translate(undefined, astLine.text.trimEnd().length);
+        return new vscode.Range(begin, end);
+    }
+
+    private parseRustTextRange(
+        doc: vscode.TextDocument,
+        astLine: string
+    ): undefined | vscode.Range {
+        const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine);
+        if (!parsedRange) return;
+
+        const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
+
+        return new vscode.Range(begin, end);
+    }
+
+    // Memoize the last value, otherwise the CPU is at 100% single core
+    // with quadratic lookups when we build rust2Ast cache
+    cache?: { doc: vscode.TextDocument; offset: number; line: number };
+
+    positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position {
+        if (doc.eol === vscode.EndOfLine.LF) {
+            return doc.positionAt(targetOffset);
+        }
+
+        // Dirty workaround for crlf line endings
+        // We are still in this prehistoric era of carriage returns here...
+
+        let line = 0;
+        let offset = 0;
+
+        const cache = this.cache;
+        if (cache?.doc === doc && cache.offset <= targetOffset) {
+            ({ line, offset } = cache);
+        }
+
+        while (true) {
+            const lineLenWithLf = doc.lineAt(line).text.length + 1;
+            if (offset + lineLenWithLf > targetOffset) {
+                this.cache = { doc, offset, line };
+                return doc.positionAt(targetOffset + line);
+            }
+            offset += lineLenWithLf;
+            line += 1;
+        }
+    }
+}
+
+class Lazy<T> {
+    val: undefined | T;
+
+    constructor(private readonly compute: () => undefined | T) {}
+
+    get() {
+        return this.val ?? (this.val = this.compute());
+    }
+
+    reset() {
+        this.val = undefined;
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
new file mode 100644
index 00000000000..8a2dea6b35b
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -0,0 +1,299 @@
+import * as lc from "vscode-languageclient/node";
+import * as vscode from "vscode";
+import * as ra from "../src/lsp_ext";
+import * as Is from "vscode-languageclient/lib/common/utils/is";
+import { assert } from "./util";
+import { WorkspaceEdit } from "vscode";
+import { Workspace } from "./ctx";
+import { updateConfig } from "./config";
+import { substituteVariablesInEnv } from "./config";
+import { outputChannel, traceOutputChannel } from "./main";
+import { randomUUID } from "crypto";
+
+export interface Env {
+    [name: string]: string;
+}
+
+// Command URIs have a form of command:command-name?arguments, where
+// arguments is a percent-encoded array of data we want to pass along to
+// the command function. For "Show References" this is a list of all file
+// URIs with locations of every reference, and it can get quite long.
+//
+// To work around it we use an intermediary linkToCommand command. When
+// we render a command link, a reference to a command with all its arguments
+// is stored in a map, and instead a linkToCommand link is rendered
+// with the key to that map.
+export const LINKED_COMMANDS = new Map<string, ra.CommandLink>();
+
+// For now the map is cleaned up periodically (I've set it to every
+// 10 minutes). In general case we'll probably need to introduce TTLs or
+// flags to denote ephemeral links (like these in hover popups) and
+// persistent links and clean those separately. But for now simply keeping
+// the last few links in the map should be good enough. Likewise, we could
+// add code to remove a target command from the map after the link is
+// clicked, but assuming most links in hover sheets won't be clicked anyway
+// this code won't change the overall memory use much.
+setInterval(function cleanupOlderCommandLinks() {
+    // keys are returned in insertion order, we'll keep a few
+    // of recent keys available, and clean the rest
+    const keys = [...LINKED_COMMANDS.keys()];
+    const keysToRemove = keys.slice(0, keys.length - 10);
+    for (const key of keysToRemove) {
+        LINKED_COMMANDS.delete(key);
+    }
+}, 10 * 60 * 1000);
+
+function renderCommand(cmd: ra.CommandLink): string {
+    const commandId = randomUUID();
+    LINKED_COMMANDS.set(commandId, cmd);
+    return `[${cmd.title}](command:rust-analyzer.linkToCommand?${encodeURIComponent(
+        JSON.stringify([commandId])
+    )} '${cmd.tooltip}')`;
+}
+
+function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
+    const text = actions
+        .map(
+            (group) =>
+                (group.title ? group.title + " " : "") +
+                group.commands.map(renderCommand).join(" | ")
+        )
+        .join("___");
+
+    const result = new vscode.MarkdownString(text);
+    result.isTrusted = true;
+    return result;
+}
+
+export async function createClient(
+    serverPath: string,
+    workspace: Workspace,
+    extraEnv: Env
+): Promise<lc.LanguageClient> {
+    // '.' Is the fallback if no folder is open
+    // TODO?: Workspace folders support Uri's (eg: file://test.txt).
+    // It might be a good idea to test if the uri points to a file.
+
+    const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv));
+    const run: lc.Executable = {
+        command: serverPath,
+        options: { env: newEnv },
+    };
+    const serverOptions: lc.ServerOptions = {
+        run,
+        debug: run,
+    };
+
+    let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+
+    // Update outdated user configs
+    await updateConfig(initializationOptions).catch((err) => {
+        void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`);
+    });
+
+    if (workspace.kind === "Detached Files") {
+        initializationOptions = {
+            detachedFiles: workspace.files.map((file) => file.uri.fsPath),
+            ...initializationOptions,
+        };
+    }
+
+    const clientOptions: lc.LanguageClientOptions = {
+        documentSelector: [{ scheme: "file", language: "rust" }],
+        initializationOptions,
+        diagnosticCollectionName: "rustc",
+        traceOutputChannel: traceOutputChannel(),
+        outputChannel: outputChannel(),
+        middleware: {
+            async provideHover(
+                document: vscode.TextDocument,
+                position: vscode.Position,
+                token: vscode.CancellationToken,
+                _next: lc.ProvideHoverSignature
+            ) {
+                const editor = vscode.window.activeTextEditor;
+                const positionOrRange = editor?.selection?.contains(position)
+                    ? client.code2ProtocolConverter.asRange(editor.selection)
+                    : client.code2ProtocolConverter.asPosition(position);
+                return client
+                    .sendRequest(
+                        ra.hover,
+                        {
+                            textDocument:
+                                client.code2ProtocolConverter.asTextDocumentIdentifier(document),
+                            position: positionOrRange,
+                        },
+                        token
+                    )
+                    .then(
+                        (result) => {
+                            const hover = client.protocol2CodeConverter.asHover(result);
+                            if (hover) {
+                                const actions = (<any>result).actions;
+                                if (actions) {
+                                    hover.contents.push(renderHoverActions(actions));
+                                }
+                            }
+                            return hover;
+                        },
+                        (error) => {
+                            client.handleFailedRequest(lc.HoverRequest.type, token, error, null);
+                            return Promise.resolve(null);
+                        }
+                    );
+            },
+            // Using custom handling of CodeActions to support action groups and snippet edits.
+            // Note that this means we have to re-implement lazy edit resolving ourselves as well.
+            async provideCodeActions(
+                document: vscode.TextDocument,
+                range: vscode.Range,
+                context: vscode.CodeActionContext,
+                token: vscode.CancellationToken,
+                _next: lc.ProvideCodeActionsSignature
+            ) {
+                const params: lc.CodeActionParams = {
+                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
+                    range: client.code2ProtocolConverter.asRange(range),
+                    context: await client.code2ProtocolConverter.asCodeActionContext(
+                        context,
+                        token
+                    ),
+                };
+                return client.sendRequest(lc.CodeActionRequest.type, params, token).then(
+                    async (values) => {
+                        if (values === null) return undefined;
+                        const result: (vscode.CodeAction | vscode.Command)[] = [];
+                        const groups = new Map<
+                            string,
+                            { index: number; items: vscode.CodeAction[] }
+                        >();
+                        for (const item of values) {
+                            // In our case we expect to get code edits only from diagnostics
+                            if (lc.CodeAction.is(item)) {
+                                assert(
+                                    !item.command,
+                                    "We don't expect to receive commands in CodeActions"
+                                );
+                                const action = await client.protocol2CodeConverter.asCodeAction(
+                                    item,
+                                    token
+                                );
+                                result.push(action);
+                                continue;
+                            }
+                            assert(
+                                isCodeActionWithoutEditsAndCommands(item),
+                                "We don't expect edits or commands here"
+                            );
+                            const kind = client.protocol2CodeConverter.asCodeActionKind(
+                                (item as any).kind
+                            );
+                            const action = new vscode.CodeAction(item.title, kind);
+                            const group = (item as any).group;
+                            action.command = {
+                                command: "rust-analyzer.resolveCodeAction",
+                                title: item.title,
+                                arguments: [item],
+                            };
+
+                            // Set a dummy edit, so that VS Code doesn't try to resolve this.
+                            action.edit = new WorkspaceEdit();
+
+                            if (group) {
+                                let entry = groups.get(group);
+                                if (!entry) {
+                                    entry = { index: result.length, items: [] };
+                                    groups.set(group, entry);
+                                    result.push(action);
+                                }
+                                entry.items.push(action);
+                            } else {
+                                result.push(action);
+                            }
+                        }
+                        for (const [group, { index, items }] of groups) {
+                            if (items.length === 1) {
+                                result[index] = items[0];
+                            } else {
+                                const action = new vscode.CodeAction(group);
+                                action.kind = items[0].kind;
+                                action.command = {
+                                    command: "rust-analyzer.applyActionGroup",
+                                    title: "",
+                                    arguments: [
+                                        items.map((item) => {
+                                            return {
+                                                label: item.title,
+                                                arguments: item.command!.arguments![0],
+                                            };
+                                        }),
+                                    ],
+                                };
+
+                                // Set a dummy edit, so that VS Code doesn't try to resolve this.
+                                action.edit = new WorkspaceEdit();
+
+                                result[index] = action;
+                            }
+                        }
+                        return result;
+                    },
+                    (_error) => undefined
+                );
+            },
+        },
+        markdown: {
+            supportHtml: true,
+        },
+    };
+
+    const client = new lc.LanguageClient(
+        "rust-analyzer",
+        "Rust Analyzer Language Server",
+        serverOptions,
+        clientOptions
+    );
+
+    // To turn on all proposed features use: client.registerProposedFeatures();
+    client.registerFeature(new ExperimentalFeatures());
+
+    return client;
+}
+
+class ExperimentalFeatures implements lc.StaticFeature {
+    fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
+        const caps: any = capabilities.experimental ?? {};
+        caps.snippetTextEdit = true;
+        caps.codeActionGroup = true;
+        caps.hoverActions = true;
+        caps.serverStatusNotification = true;
+        caps.commands = {
+            commands: [
+                "rust-analyzer.runSingle",
+                "rust-analyzer.debugSingle",
+                "rust-analyzer.showReferences",
+                "rust-analyzer.gotoLocation",
+                "editor.action.triggerParameterHints",
+            ],
+        };
+        capabilities.experimental = caps;
+    }
+    initialize(
+        _capabilities: lc.ServerCapabilities<any>,
+        _documentSelector: lc.DocumentSelector | undefined
+    ): void {}
+    dispose(): void {}
+}
+
+function isCodeActionWithoutEditsAndCommands(value: any): boolean {
+    const candidate: lc.CodeAction = value;
+    return (
+        candidate &&
+        Is.string(candidate.title) &&
+        (candidate.diagnostics === void 0 ||
+            Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
+        (candidate.kind === void 0 || Is.string(candidate.kind)) &&
+        candidate.edit === void 0 &&
+        candidate.command === void 0
+    );
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
new file mode 100644
index 00000000000..bf55329ca1f
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -0,0 +1,952 @@
+import * as vscode from "vscode";
+import * as lc from "vscode-languageclient";
+import * as ra from "./lsp_ext";
+import * as path from "path";
+
+import { Ctx, Cmd } from "./ctx";
+import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
+import { spawnSync } from "child_process";
+import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
+import { AstInspector } from "./ast_inspector";
+import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util";
+import { startDebugSession, makeDebugConfig } from "./debug";
+import { LanguageClient } from "vscode-languageclient/node";
+import { LINKED_COMMANDS } from "./client";
+
+export * from "./ast_inspector";
+export * from "./run";
+
+export function analyzerStatus(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+
+        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
+            if (!vscode.window.activeTextEditor) return "";
+
+            const params: ra.AnalyzerStatusParams = {};
+            const doc = ctx.activeRustEditor?.document;
+            if (doc != null) {
+                params.textDocument =
+                    ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
+            }
+            return ctx.client.sendRequest(ra.analyzerStatus, params);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp)
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        void (await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true,
+        }));
+    };
+}
+
+export function memoryUsage(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+
+        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
+            if (!vscode.window.activeTextEditor) return "";
+
+            return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
+                return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
+            });
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp)
+    );
+
+    return async () => {
+        tdcp.eventEmitter.fire(tdcp.uri);
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
+    };
+}
+
+export function shuffleCrateGraph(ctx: Ctx): Cmd {
+    return async () => {
+        const client = ctx.client;
+        if (!client) return;
+
+        await client.sendRequest(ra.shuffleCrateGraph);
+    };
+}
+
+export function matchingBrace(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const response = await client.sendRequest(ra.matchingBrace, {
+            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                editor.document
+            ),
+            positions: editor.selections.map((s) =>
+                client.code2ProtocolConverter.asPosition(s.active)
+            ),
+        });
+        editor.selections = editor.selections.map((sel, idx) => {
+            const active = client.protocol2CodeConverter.asPosition(response[idx]);
+            const anchor = sel.isEmpty ? active : sel.anchor;
+            return new vscode.Selection(anchor, active);
+        });
+        editor.revealRange(editor.selection);
+    };
+}
+
+export function joinLines(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
+            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
+            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                editor.document
+            ),
+        });
+        const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
+        await editor.edit((builder) => {
+            textEdits.forEach((edit: any) => {
+                builder.replace(edit.range, edit.newText);
+            });
+        });
+    };
+}
+
+export function moveItemUp(ctx: Ctx): Cmd {
+    return moveItem(ctx, ra.Direction.Up);
+}
+
+export function moveItemDown(ctx: Ctx): Cmd {
+    return moveItem(ctx, ra.Direction.Down);
+}
+
+export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const lcEdits = await client.sendRequest(ra.moveItem, {
+            range: client.code2ProtocolConverter.asRange(editor.selection),
+            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                editor.document
+            ),
+            direction,
+        });
+
+        if (!lcEdits) return;
+
+        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
+        await applySnippetTextEdits(editor, edits);
+    };
+}
+
+export function onEnter(ctx: Ctx): Cmd {
+    async function handleKeypress() {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+
+        if (!editor || !client) return false;
+
+        const lcEdits = await client
+            .sendRequest(ra.onEnter, {
+                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                    editor.document
+                ),
+                position: client.code2ProtocolConverter.asPosition(editor.selection.active),
+            })
+            .catch((_error: any) => {
+                // client.handleFailedRequest(OnEnterRequest.type, error, null);
+                return null;
+            });
+        if (!lcEdits) return false;
+
+        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
+        await applySnippetTextEdits(editor, edits);
+        return true;
+    }
+
+    return async () => {
+        if (await handleKeypress()) return;
+
+        await vscode.commands.executeCommand("default:type", { text: "\n" });
+    };
+}
+
+export function parentModule(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = vscode.window.activeTextEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+        if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
+
+        const locations = await client.sendRequest(ra.parentModule, {
+            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                editor.document
+            ),
+            position: client.code2ProtocolConverter.asPosition(editor.selection.active),
+        });
+        if (!locations) return;
+
+        if (locations.length === 1) {
+            const loc = locations[0];
+
+            const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
+            const range = client.protocol2CodeConverter.asRange(loc.targetRange);
+
+            const doc = await vscode.workspace.openTextDocument(uri);
+            const e = await vscode.window.showTextDocument(doc);
+            e.selection = new vscode.Selection(range.start, range.start);
+            e.revealRange(range, vscode.TextEditorRevealType.InCenter);
+        } else {
+            const uri = editor.document.uri.toString();
+            const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
+            await showReferencesImpl(
+                client,
+                uri,
+                position,
+                locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange))
+            );
+        }
+    };
+}
+
+export function openCargoToml(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const response = await client.sendRequest(ra.openCargoToml, {
+            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                editor.document
+            ),
+        });
+        if (!response) return;
+
+        const uri = client.protocol2CodeConverter.asUri(response.uri);
+        const range = client.protocol2CodeConverter.asRange(response.range);
+
+        const doc = await vscode.workspace.openTextDocument(uri);
+        const e = await vscode.window.showTextDocument(doc);
+        e.selection = new vscode.Selection(range.start, range.start);
+        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
+    };
+}
+
+export function ssr(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = vscode.window.activeTextEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const position = editor.selection.active;
+        const selections = editor.selections;
+        const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+            editor.document
+        );
+
+        const options: vscode.InputBoxOptions = {
+            value: "() ==>> ()",
+            prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ",
+            validateInput: async (x: string) => {
+                try {
+                    await client.sendRequest(ra.ssr, {
+                        query: x,
+                        parseOnly: true,
+                        textDocument,
+                        position,
+                        selections,
+                    });
+                } catch (e) {
+                    return e.toString();
+                }
+                return null;
+            },
+        };
+        const request = await vscode.window.showInputBox(options);
+        if (!request) return;
+
+        await vscode.window.withProgress(
+            {
+                location: vscode.ProgressLocation.Notification,
+                title: "Structured search replace in progress...",
+                cancellable: false,
+            },
+            async (_progress, token) => {
+                const edit = await client.sendRequest(ra.ssr, {
+                    query: request,
+                    parseOnly: false,
+                    textDocument,
+                    position,
+                    selections,
+                });
+
+                await vscode.workspace.applyEdit(
+                    await client.protocol2CodeConverter.asWorkspaceEdit(edit, token)
+                );
+            }
+        );
+    };
+}
+
+export function serverVersion(ctx: Ctx): Cmd {
+    return async () => {
+        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
+        const versionString = stdout.slice(`rust-analyzer `.length).trim();
+
+        void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
+    };
+}
+
+export function toggleInlayHints(_ctx: Ctx): Cmd {
+    return async () => {
+        const config = vscode.workspace.getConfiguration("editor.inlayHints", {
+            languageId: "rust",
+        });
+        const value = !config.get("enabled");
+        await config.update("enabled", value, vscode.ConfigurationTarget.Global);
+    };
+}
+
+// Opens the virtual file that will show the syntax tree
+//
+// The contents of the file come from the `TextDocumentContentProvider`
+export function syntaxTree(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        constructor() {
+            vscode.workspace.onDidChangeTextDocument(
+                this.onDidChangeTextDocument,
+                this,
+                ctx.subscriptions
+            );
+            vscode.window.onDidChangeActiveTextEditor(
+                this.onDidChangeActiveTextEditor,
+                this,
+                ctx.subscriptions
+            );
+        }
+
+        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+            if (isRustDocument(event.document)) {
+                // We need to order this after language server updates, but there's no API for that.
+                // Hence, good old sleep().
+                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
+            }
+        }
+        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
+            if (editor && isRustEditor(editor)) {
+                this.eventEmitter.fire(this.uri);
+            }
+        }
+
+        provideTextDocumentContent(
+            uri: vscode.Uri,
+            ct: vscode.CancellationToken
+        ): vscode.ProviderResult<string> {
+            const rustEditor = ctx.activeRustEditor;
+            if (!rustEditor) return "";
+
+            // When the range based query is enabled we take the range of the selection
+            const range =
+                uri.query === "range=true" && !rustEditor.selection.isEmpty
+                    ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
+                    : null;
+
+            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
+            return ctx.client.sendRequest(ra.syntaxTree, params, ct);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    void new AstInspector(ctx);
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp)
+    );
+    ctx.pushCleanup(
+        vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
+            brackets: [["[", ")"]],
+        })
+    );
+
+    return async () => {
+        const editor = vscode.window.activeTextEditor;
+        const rangeEnabled = !!editor && !editor.selection.isEmpty;
+
+        const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri;
+
+        const document = await vscode.workspace.openTextDocument(uri);
+
+        tdcp.eventEmitter.fire(uri);
+
+        void (await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true,
+        }));
+    };
+}
+
+// Opens the virtual file that will show the HIR of the function containing the cursor position
+//
+// The contents of the file come from the `TextDocumentContentProvider`
+export function viewHir(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        constructor() {
+            vscode.workspace.onDidChangeTextDocument(
+                this.onDidChangeTextDocument,
+                this,
+                ctx.subscriptions
+            );
+            vscode.window.onDidChangeActiveTextEditor(
+                this.onDidChangeActiveTextEditor,
+                this,
+                ctx.subscriptions
+            );
+        }
+
+        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+            if (isRustDocument(event.document)) {
+                // We need to order this after language server updates, but there's no API for that.
+                // Hence, good old sleep().
+                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
+            }
+        }
+        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
+            if (editor && isRustEditor(editor)) {
+                this.eventEmitter.fire(this.uri);
+            }
+        }
+
+        provideTextDocumentContent(
+            _uri: vscode.Uri,
+            ct: vscode.CancellationToken
+        ): vscode.ProviderResult<string> {
+            const rustEditor = ctx.activeRustEditor;
+            const client = ctx.client;
+            if (!rustEditor || !client) return "";
+
+            const params = {
+                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
+                    rustEditor.document
+                ),
+                position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active),
+            };
+            return client.sendRequest(ra.viewHir, params, ct);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp)
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        void (await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true,
+        }));
+    };
+}
+
+export function viewFileText(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        constructor() {
+            vscode.workspace.onDidChangeTextDocument(
+                this.onDidChangeTextDocument,
+                this,
+                ctx.subscriptions
+            );
+            vscode.window.onDidChangeActiveTextEditor(
+                this.onDidChangeActiveTextEditor,
+                this,
+                ctx.subscriptions
+            );
+        }
+
+        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+            if (isRustDocument(event.document)) {
+                // We need to order this after language server updates, but there's no API for that.
+                // Hence, good old sleep().
+                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
+            }
+        }
+        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
+            if (editor && isRustEditor(editor)) {
+                this.eventEmitter.fire(this.uri);
+            }
+        }
+
+        provideTextDocumentContent(
+            _uri: vscode.Uri,
+            ct: vscode.CancellationToken
+        ): vscode.ProviderResult<string> {
+            const rustEditor = ctx.activeRustEditor;
+            const client = ctx.client;
+            if (!rustEditor || !client) return "";
+
+            const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
+                rustEditor.document
+            );
+            return client.sendRequest(ra.viewFileText, params, ct);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp)
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        void (await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true,
+        }));
+    };
+}
+
+export function viewItemTree(ctx: Ctx): Cmd {
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs");
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        constructor() {
+            vscode.workspace.onDidChangeTextDocument(
+                this.onDidChangeTextDocument,
+                this,
+                ctx.subscriptions
+            );
+            vscode.window.onDidChangeActiveTextEditor(
+                this.onDidChangeActiveTextEditor,
+                this,
+                ctx.subscriptions
+            );
+        }
+
+        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+            if (isRustDocument(event.document)) {
+                // We need to order this after language server updates, but there's no API for that.
+                // Hence, good old sleep().
+                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
+            }
+        }
+        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
+            if (editor && isRustEditor(editor)) {
+                this.eventEmitter.fire(this.uri);
+            }
+        }
+
+        provideTextDocumentContent(
+            _uri: vscode.Uri,
+            ct: vscode.CancellationToken
+        ): vscode.ProviderResult<string> {
+            const rustEditor = ctx.activeRustEditor;
+            const client = ctx.client;
+            if (!rustEditor || !client) return "";
+
+            const params = {
+                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
+                    rustEditor.document
+                ),
+            };
+            return client.sendRequest(ra.viewItemTree, params, ct);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp)
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        void (await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true,
+        }));
+    };
+}
+
+function crateGraph(ctx: Ctx, full: boolean): Cmd {
+    return async () => {
+        const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules"));
+
+        const panel = vscode.window.createWebviewPanel(
+            "rust-analyzer.crate-graph",
+            "rust-analyzer crate graph",
+            vscode.ViewColumn.Two,
+            {
+                enableScripts: true,
+                retainContextWhenHidden: true,
+                localResourceRoots: [nodeModulesPath],
+            }
+        );
+        const params = {
+            full: full,
+        };
+
+        const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params);
+        const uri = panel.webview.asWebviewUri(nodeModulesPath);
+
+        const html = `
+            <!DOCTYPE html>
+            <meta charset="utf-8">
+            <head>
+                <style>
+                    /* Fill the entire view */
+                    html, body { margin:0; padding:0; overflow:hidden }
+                    svg { position:fixed; top:0; left:0; height:100%; width:100% }
+
+                    /* Disable the graphviz backgroud and fill the polygons */
+                    .graph > polygon { display:none; }
+                    :is(.node,.edge) polygon { fill: white; }
+
+                    /* Invert the line colours for dark themes */
+                    body:not(.vscode-light) .edge path { stroke: white; }
+                </style>
+            </head>
+            <body>
+                <script type="text/javascript" src="${uri}/d3/dist/d3.min.js"></script>
+                <script type="text/javascript" src="${uri}/@hpcc-js/wasm/dist/index.min.js"></script>
+                <script type="text/javascript" src="${uri}/d3-graphviz/build/d3-graphviz.min.js"></script>
+                <div id="graph"></div>
+                <script>
+                    let graph = d3.select("#graph")
+                                  .graphviz()
+                                  .fit(true)
+                                  .zoomScaleExtent([0.1, Infinity])
+                                  .renderDot(\`${dot}\`);
+
+                    d3.select(window).on("click", (event) => {
+                        if (event.ctrlKey) {
+                            graph.resetZoom(d3.transition().duration(100));
+                        }
+                    });
+                </script>
+            </body>
+            `;
+
+        panel.webview.html = html;
+    };
+}
+
+export function viewCrateGraph(ctx: Ctx): Cmd {
+    return crateGraph(ctx, false);
+}
+
+export function viewFullCrateGraph(ctx: Ctx): Cmd {
+    return crateGraph(ctx, true);
+}
+
+// Opens the virtual file that will show the syntax tree
+//
+// The contents of the file come from the `TextDocumentContentProvider`
+export function expandMacro(ctx: Ctx): Cmd {
+    function codeFormat(expanded: ra.ExpandedMacro): string {
+        let result = `// Recursive expansion of ${expanded.name}! macro\n`;
+        result += "// " + "=".repeat(result.length - 3);
+        result += "\n\n";
+        result += expanded.expansion;
+
+        return result;
+    }
+
+    const tdcp = new (class implements vscode.TextDocumentContentProvider {
+        uri = vscode.Uri.parse("rust-analyzer-expand-macro://expandMacro/[EXPANSION].rs");
+        eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
+            const editor = vscode.window.activeTextEditor;
+            const client = ctx.client;
+            if (!editor || !client) return "";
+
+            const position = editor.selection.active;
+
+            const expanded = await client.sendRequest(ra.expandMacro, {
+                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                    editor.document
+                ),
+                position,
+            });
+
+            if (expanded == null) return "Not available";
+
+            return codeFormat(expanded);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    })();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp)
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
+    };
+}
+
+export function reloadWorkspace(ctx: Ctx): Cmd {
+    return async () => ctx.client.sendRequest(ra.reloadWorkspace);
+}
+
+async function showReferencesImpl(
+    client: LanguageClient,
+    uri: string,
+    position: lc.Position,
+    locations: lc.Location[]
+) {
+    if (client) {
+        await vscode.commands.executeCommand(
+            "editor.action.showReferences",
+            vscode.Uri.parse(uri),
+            client.protocol2CodeConverter.asPosition(position),
+            locations.map(client.protocol2CodeConverter.asLocation)
+        );
+    }
+}
+
+export function showReferences(ctx: Ctx): Cmd {
+    return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
+        await showReferencesImpl(ctx.client, uri, position, locations);
+    };
+}
+
+export function applyActionGroup(_ctx: Ctx): Cmd {
+    return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
+        const selectedAction = await vscode.window.showQuickPick(actions);
+        if (!selectedAction) return;
+        await vscode.commands.executeCommand(
+            "rust-analyzer.resolveCodeAction",
+            selectedAction.arguments
+        );
+    };
+}
+
+export function gotoLocation(ctx: Ctx): Cmd {
+    return async (locationLink: lc.LocationLink) => {
+        const client = ctx.client;
+        if (client) {
+            const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
+            let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
+            // collapse the range to a cursor position
+            range = range.with({ end: range.start });
+
+            await vscode.window.showTextDocument(uri, { selection: range });
+        }
+    };
+}
+
+export function openDocs(ctx: Ctx): Cmd {
+    return async () => {
+        const client = ctx.client;
+        const editor = vscode.window.activeTextEditor;
+        if (!editor || !client) {
+            return;
+        }
+
+        const position = editor.selection.active;
+        const textDocument = { uri: editor.document.uri.toString() };
+
+        const doclink = await client.sendRequest(ra.openDocs, { position, textDocument });
+
+        if (doclink != null) {
+            await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink));
+        }
+    };
+}
+
+export function resolveCodeAction(ctx: Ctx): Cmd {
+    const client = ctx.client;
+    return async (params: lc.CodeAction) => {
+        params.command = undefined;
+        const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
+        if (!item.edit) {
+            return;
+        }
+        const itemEdit = item.edit;
+        const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
+        // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
+        // snippet edits on our own
+        const lcFileSystemEdit = {
+            ...itemEdit,
+            documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change),
+        };
+        const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(
+            lcFileSystemEdit
+        );
+        await vscode.workspace.applyEdit(fileSystemEdit);
+        await applySnippetWorkspaceEdit(edit);
+        if (item.command != null) {
+            await vscode.commands.executeCommand(item.command.command, item.command.arguments);
+        }
+    };
+}
+
+export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
+    return async (edit: vscode.WorkspaceEdit) => {
+        await applySnippetWorkspaceEdit(edit);
+    };
+}
+
+export function run(ctx: Ctx): Cmd {
+    let prevRunnable: RunnableQuickPick | undefined;
+
+    return async () => {
+        const item = await selectRunnable(ctx, prevRunnable);
+        if (!item) return;
+
+        item.detail = "rerun";
+        prevRunnable = item;
+        const task = await createTask(item.runnable, ctx.config);
+        return await vscode.tasks.executeTask(task);
+    };
+}
+
+export function peekTests(ctx: Ctx): Cmd {
+    const client = ctx.client;
+
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        if (!editor || !client) return;
+
+        await vscode.window.withProgress(
+            {
+                location: vscode.ProgressLocation.Notification,
+                title: "Looking for tests...",
+                cancellable: false,
+            },
+            async (_progress, _token) => {
+                const uri = editor.document.uri.toString();
+                const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
+
+                const tests = await client.sendRequest(ra.relatedTests, {
+                    textDocument: { uri: uri },
+                    position: position,
+                });
+                const locations: lc.Location[] = tests.map((it) =>
+                    lc.Location.create(
+                        it.runnable.location!.targetUri,
+                        it.runnable.location!.targetSelectionRange
+                    )
+                );
+
+                await showReferencesImpl(client, uri, position, locations);
+            }
+        );
+    };
+}
+
+export function runSingle(ctx: Ctx): Cmd {
+    return async (runnable: ra.Runnable) => {
+        const editor = ctx.activeRustEditor;
+        if (!editor) return;
+
+        const task = await createTask(runnable, ctx.config);
+        task.group = vscode.TaskGroup.Build;
+        task.presentationOptions = {
+            reveal: vscode.TaskRevealKind.Always,
+            panel: vscode.TaskPanelKind.Dedicated,
+            clear: true,
+        };
+
+        return vscode.tasks.executeTask(task);
+    };
+}
+
+export function copyRunCommandLine(ctx: Ctx) {
+    let prevRunnable: RunnableQuickPick | undefined;
+    return async () => {
+        const item = await selectRunnable(ctx, prevRunnable);
+        if (!item) return;
+        const args = createArgs(item.runnable);
+        const commandLine = ["cargo", ...args].join(" ");
+        await vscode.env.clipboard.writeText(commandLine);
+        await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
+    };
+}
+
+export function debug(ctx: Ctx): Cmd {
+    let prevDebuggee: RunnableQuickPick | undefined;
+
+    return async () => {
+        const item = await selectRunnable(ctx, prevDebuggee, true);
+        if (!item) return;
+
+        item.detail = "restart";
+        prevDebuggee = item;
+        return await startDebugSession(ctx, item.runnable);
+    };
+}
+
+export function debugSingle(ctx: Ctx): Cmd {
+    return async (config: ra.Runnable) => {
+        await startDebugSession(ctx, config);
+    };
+}
+
+export function newDebugConfig(ctx: Ctx): Cmd {
+    return async () => {
+        const item = await selectRunnable(ctx, undefined, true, false);
+        if (!item) return;
+
+        await makeDebugConfig(ctx, item.runnable);
+    };
+}
+
+export function linkToCommand(ctx: Ctx): Cmd {
+    return async (commandId: string) => {
+        const link = LINKED_COMMANDS.get(commandId);
+        if (ctx.client && link) {
+            const { command, arguments: args = [] } = link;
+            await vscode.commands.executeCommand(command, ...args);
+        }
+    };
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
new file mode 100644
index 00000000000..b04f18890b9
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -0,0 +1,394 @@
+import path = require("path");
+import * as vscode from "vscode";
+import { Env } from "./client";
+import { log } from "./util";
+
+export type UpdatesChannel = "stable" | "nightly";
+
+const NIGHTLY_TAG = "nightly";
+
+export type RunnableEnvCfg =
+    | undefined
+    | Record<string, string>
+    | { mask?: string; env: Record<string, string> }[];
+
+export class Config {
+    readonly extensionId = "rust-lang.rust-analyzer";
+
+    readonly rootSection = "rust-analyzer";
+    private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map(
+        (opt) => `${this.rootSection}.${opt}`
+    );
+    private readonly requiresReloadOpts = [
+        "cargo",
+        "procMacro",
+        "files",
+        "lens", // works as lens.*
+    ]
+        .map((opt) => `${this.rootSection}.${opt}`)
+        .concat(this.requiresWorkspaceReloadOpts);
+
+    readonly package: {
+        version: string;
+        releaseTag: string | null;
+        enableProposedApi: boolean | undefined;
+    } = vscode.extensions.getExtension(this.extensionId)!.packageJSON;
+
+    readonly globalStorageUri: vscode.Uri;
+
+    constructor(ctx: vscode.ExtensionContext) {
+        this.globalStorageUri = ctx.globalStorageUri;
+        vscode.workspace.onDidChangeConfiguration(
+            this.onDidChangeConfiguration,
+            this,
+            ctx.subscriptions
+        );
+        this.refreshLogging();
+    }
+
+    private refreshLogging() {
+        log.setEnabled(this.traceExtension);
+        log.info("Extension version:", this.package.version);
+
+        const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
+        log.info("Using configuration", Object.fromEntries(cfg));
+    }
+
+    private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
+        this.refreshLogging();
+
+        const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
+            event.affectsConfiguration(opt)
+        );
+
+        if (!requiresReloadOpt) return;
+
+        const requiresWorkspaceReloadOpt = this.requiresWorkspaceReloadOpts.find((opt) =>
+            event.affectsConfiguration(opt)
+        );
+
+        if (!requiresWorkspaceReloadOpt && this.restartServerOnConfigChange) {
+            await vscode.commands.executeCommand("rust-analyzer.reload");
+            return;
+        }
+
+        const message = requiresWorkspaceReloadOpt
+            ? `Changing "${requiresWorkspaceReloadOpt}" requires a window reload`
+            : `Changing "${requiresReloadOpt}" requires a reload`;
+        const userResponse = await vscode.window.showInformationMessage(message, "Reload now");
+
+        if (userResponse === "Reload now") {
+            const command = requiresWorkspaceReloadOpt
+                ? "workbench.action.reloadWindow"
+                : "rust-analyzer.reload";
+            if (userResponse === "Reload now") {
+                await vscode.commands.executeCommand(command);
+            }
+        }
+    }
+
+    // We don't do runtime config validation here for simplicity. More on stackoverflow:
+    // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
+
+    private get cfg(): vscode.WorkspaceConfiguration {
+        return vscode.workspace.getConfiguration(this.rootSection);
+    }
+
+    /**
+     * Beware that postfix `!` operator erases both `null` and `undefined`.
+     * This is why the following doesn't work as expected:
+     *
+     * ```ts
+     * const nullableNum = vscode
+     *  .workspace
+     *  .getConfiguration
+     *  .getConfiguration("rust-analyzer")
+     *  .get<number | null>(path)!;
+     *
+     * // What happens is that type of `nullableNum` is `number` but not `null | number`:
+     * const fullFledgedNum: number = nullableNum;
+     * ```
+     * So this getter handles this quirk by not requiring the caller to use postfix `!`
+     */
+    private get<T>(path: string): T {
+        return this.cfg.get<T>(path)!;
+    }
+
+    get serverPath() {
+        return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
+    }
+    get serverExtraEnv(): Env {
+        const extraEnv =
+            this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {};
+        return Object.fromEntries(
+            Object.entries(extraEnv).map(([k, v]) => [k, typeof v !== "string" ? v.toString() : v])
+        );
+    }
+    get traceExtension() {
+        return this.get<boolean>("trace.extension");
+    }
+
+    get cargoRunner() {
+        return this.get<string | undefined>("cargoRunner");
+    }
+
+    get runnableEnv() {
+        return this.get<RunnableEnvCfg>("runnableEnv");
+    }
+
+    get restartServerOnConfigChange() {
+        return this.get<boolean>("restartServerOnConfigChange");
+    }
+
+    get debug() {
+        let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
+        if (sourceFileMap !== "auto") {
+            // "/rustc/<id>" used by suggestions only.
+            const { ["/rustc/<id>"]: _, ...trimmed } =
+                this.get<Record<string, string>>("debug.sourceFileMap");
+            sourceFileMap = trimmed;
+        }
+
+        return {
+            engine: this.get<string>("debug.engine"),
+            engineSettings: this.get<object>("debug.engineSettings"),
+            openDebugPane: this.get<boolean>("debug.openDebugPane"),
+            sourceFileMap: sourceFileMap,
+        };
+    }
+
+    get hoverActions() {
+        return {
+            enable: this.get<boolean>("hover.actions.enable"),
+            implementations: this.get<boolean>("hover.actions.implementations.enable"),
+            references: this.get<boolean>("hover.actions.references.enable"),
+            run: this.get<boolean>("hover.actions.run.enable"),
+            debug: this.get<boolean>("hover.actions.debug.enable"),
+            gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"),
+        };
+    }
+
+    get currentExtensionIsNightly() {
+        return this.package.releaseTag === NIGHTLY_TAG;
+    }
+}
+
+export async function updateConfig(config: vscode.WorkspaceConfiguration) {
+    const renames = [
+        ["assist.allowMergingIntoGlobImports", "imports.merge.glob"],
+        ["assist.exprFillDefault", "assist.expressionFillDefault"],
+        ["assist.importEnforceGranularity", "imports.granularity.enforce"],
+        ["assist.importGranularity", "imports.granularity.group"],
+        ["assist.importMergeBehavior", "imports.granularity.group"],
+        ["assist.importMergeBehaviour", "imports.granularity.group"],
+        ["assist.importGroup", "imports.group.enable"],
+        ["assist.importPrefix", "imports.prefix"],
+        ["primeCaches.enable", "cachePriming.enable"],
+        ["cache.warmup", "cachePriming.enable"],
+        ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"],
+        ["cargo.runBuildScripts", "cargo.buildScripts.enable"],
+        ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"],
+        ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"],
+        ["completion.snippets", "completion.snippets.custom"],
+        ["diagnostics.enableExperimental", "diagnostics.experimental.enable"],
+        ["experimental.procAttrMacros", "procMacro.attributes.enable"],
+        ["highlighting.strings", "semanticHighlighting.strings.enable"],
+        ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"],
+        ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"],
+        ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"],
+        ["highlightRelated.references", "highlightRelated.references.enable"],
+        ["hover.documentation", "hover.documentation.enable"],
+        ["hover.linksInHover", "hover.links.enable"],
+        ["hoverActions.linksInHover", "hover.links.enable"],
+        ["hoverActions.debug", "hover.actions.debug.enable"],
+        ["hoverActions.enable", "hover.actions.enable.enable"],
+        ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"],
+        ["hoverActions.implementations", "hover.actions.implementations.enable"],
+        ["hoverActions.references", "hover.actions.references.enable"],
+        ["hoverActions.run", "hover.actions.run.enable"],
+        ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"],
+        ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"],
+        ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"],
+        ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"],
+        ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"],
+        ["inlayHints.typeHints", "inlayHints.typeHints.enable"],
+        ["lruCapacity", "lru.capacity"],
+        ["runnables.cargoExtraArgs", "runnables.extraArgs"],
+        ["runnables.overrideCargo", "runnables.command"],
+        ["rustcSource", "rustc.source"],
+        ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"],
+    ];
+
+    for (const [oldKey, newKey] of renames) {
+        const inspect = config.inspect(oldKey);
+        if (inspect !== undefined) {
+            const valMatrix = [
+                {
+                    val: inspect.globalValue,
+                    langVal: inspect.globalLanguageValue,
+                    target: vscode.ConfigurationTarget.Global,
+                },
+                {
+                    val: inspect.workspaceFolderValue,
+                    langVal: inspect.workspaceFolderLanguageValue,
+                    target: vscode.ConfigurationTarget.WorkspaceFolder,
+                },
+                {
+                    val: inspect.workspaceValue,
+                    langVal: inspect.workspaceLanguageValue,
+                    target: vscode.ConfigurationTarget.Workspace,
+                },
+            ];
+            for (const { val, langVal, target } of valMatrix) {
+                const patch = (val: unknown) => {
+                    // some of the updates we do only append "enable" or "custom"
+                    // that means on the next run we would find these again, but as objects with
+                    // these properties causing us to destroy the config
+                    // so filter those already updated ones out
+                    return (
+                        val !== undefined &&
+                        !(
+                            typeof val === "object" &&
+                            val !== null &&
+                            (oldKey === "completion.snippets" || !val.hasOwnProperty("custom"))
+                        )
+                    );
+                };
+                if (patch(val)) {
+                    await config.update(newKey, val, target, false);
+                    await config.update(oldKey, undefined, target, false);
+                }
+                if (patch(langVal)) {
+                    await config.update(newKey, langVal, target, true);
+                    await config.update(oldKey, undefined, target, true);
+                }
+            }
+        }
+    }
+}
+
+export function substituteVariablesInEnv(env: Env): Env {
+    const missingDeps = new Set<string>();
+    // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
+    // to follow the same convention for our dependency tracking
+    const definedEnvKeys = new Set(Object.keys(env).map((key) => `env:${key}`));
+    const envWithDeps = Object.fromEntries(
+        Object.entries(env).map(([key, value]) => {
+            const deps = new Set<string>();
+            const depRe = new RegExp(/\${(?<depName>.+?)}/g);
+            let match = undefined;
+            while ((match = depRe.exec(value))) {
+                const depName = match.groups!.depName;
+                deps.add(depName);
+                // `depName` at this point can have a form of `expression` or
+                // `prefix:expression`
+                if (!definedEnvKeys.has(depName)) {
+                    missingDeps.add(depName);
+                }
+            }
+            return [`env:${key}`, { deps: [...deps], value }];
+        })
+    );
+
+    const resolved = new Set<string>();
+    for (const dep of missingDeps) {
+        const match = /(?<prefix>.*?):(?<body>.+)/.exec(dep);
+        if (match) {
+            const { prefix, body } = match.groups!;
+            if (prefix === "env") {
+                const envName = body;
+                envWithDeps[dep] = {
+                    value: process.env[envName] ?? "",
+                    deps: [],
+                };
+                resolved.add(dep);
+            } else {
+                // we can't handle other prefixes at the moment
+                // leave values as is, but still mark them as resolved
+                envWithDeps[dep] = {
+                    value: "${" + dep + "}",
+                    deps: [],
+                };
+                resolved.add(dep);
+            }
+        } else {
+            envWithDeps[dep] = {
+                value: computeVscodeVar(dep),
+                deps: [],
+            };
+        }
+    }
+    const toResolve = new Set(Object.keys(envWithDeps));
+
+    let leftToResolveSize;
+    do {
+        leftToResolveSize = toResolve.size;
+        for (const key of toResolve) {
+            if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) {
+                envWithDeps[key].value = envWithDeps[key].value.replace(
+                    /\${(?<depName>.+?)}/g,
+                    (_wholeMatch, depName) => {
+                        return envWithDeps[depName].value;
+                    }
+                );
+                resolved.add(key);
+                toResolve.delete(key);
+            }
+        }
+    } while (toResolve.size > 0 && toResolve.size < leftToResolveSize);
+
+    const resolvedEnv: Env = {};
+    for (const key of Object.keys(env)) {
+        resolvedEnv[key] = envWithDeps[`env:${key}`].value;
+    }
+    return resolvedEnv;
+}
+
+function computeVscodeVar(varName: string): string {
+    // https://code.visualstudio.com/docs/editor/variables-reference
+    const supportedVariables: { [k: string]: () => string } = {
+        workspaceFolder: () => {
+            const folders = vscode.workspace.workspaceFolders ?? [];
+            if (folders.length === 1) {
+                // TODO: support for remote workspaces?
+                return folders[0].uri.fsPath;
+            } else if (folders.length > 1) {
+                // could use currently opened document to detect the correct
+                // workspace. However, that would be determined by the document
+                // user has opened on Editor startup. Could lead to
+                // unpredictable workspace selection in practice.
+                // It's better to pick the first one
+                return folders[0].uri.fsPath;
+            } else {
+                // no workspace opened
+                return "";
+            }
+        },
+
+        workspaceFolderBasename: () => {
+            const workspaceFolder = computeVscodeVar("workspaceFolder");
+            if (workspaceFolder) {
+                return path.basename(workspaceFolder);
+            } else {
+                return "";
+            }
+        },
+
+        cwd: () => process.cwd(),
+
+        // see
+        // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81
+        // or
+        // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56
+        execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath,
+
+        pathSeparator: () => path.sep,
+    };
+
+    if (varName in supportedVariables) {
+        return supportedVariables[varName]();
+    } else {
+        // can't resolve, keep the expression as is
+        return "${" + varName + "}";
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
new file mode 100644
index 00000000000..26510011d43
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -0,0 +1,122 @@
+import * as vscode from "vscode";
+import * as lc from "vscode-languageclient/node";
+import * as ra from "./lsp_ext";
+
+import { Config } from "./config";
+import { createClient } from "./client";
+import { isRustEditor, RustEditor } from "./util";
+import { ServerStatusParams } from "./lsp_ext";
+
+export type Workspace =
+    | {
+          kind: "Workspace Folder";
+      }
+    | {
+          kind: "Detached Files";
+          files: vscode.TextDocument[];
+      };
+
+export class Ctx {
+    private constructor(
+        readonly config: Config,
+        private readonly extCtx: vscode.ExtensionContext,
+        readonly client: lc.LanguageClient,
+        readonly serverPath: string,
+        readonly statusBar: vscode.StatusBarItem
+    ) {}
+
+    static async create(
+        config: Config,
+        extCtx: vscode.ExtensionContext,
+        serverPath: string,
+        workspace: Workspace
+    ): Promise<Ctx> {
+        const client = await createClient(serverPath, workspace, config.serverExtraEnv);
+
+        const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
+        extCtx.subscriptions.push(statusBar);
+        statusBar.text = "rust-analyzer";
+        statusBar.tooltip = "ready";
+        statusBar.command = "rust-analyzer.analyzerStatus";
+        statusBar.show();
+
+        const res = new Ctx(config, extCtx, client, serverPath, statusBar);
+
+        res.pushCleanup(client.start());
+        await client.onReady();
+        client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params));
+        return res;
+    }
+
+    get activeRustEditor(): RustEditor | undefined {
+        const editor = vscode.window.activeTextEditor;
+        return editor && isRustEditor(editor) ? editor : undefined;
+    }
+
+    get visibleRustEditors(): RustEditor[] {
+        return vscode.window.visibleTextEditors.filter(isRustEditor);
+    }
+
+    registerCommand(name: string, factory: (ctx: Ctx) => Cmd) {
+        const fullName = `rust-analyzer.${name}`;
+        const cmd = factory(this);
+        const d = vscode.commands.registerCommand(fullName, cmd);
+        this.pushCleanup(d);
+    }
+
+    get extensionPath(): string {
+        return this.extCtx.extensionPath;
+    }
+
+    get globalState(): vscode.Memento {
+        return this.extCtx.globalState;
+    }
+
+    get subscriptions(): Disposable[] {
+        return this.extCtx.subscriptions;
+    }
+
+    setServerStatus(status: ServerStatusParams) {
+        let icon = "";
+        const statusBar = this.statusBar;
+        switch (status.health) {
+            case "ok":
+                statusBar.tooltip = status.message ?? "Ready";
+                statusBar.command = undefined;
+                statusBar.color = undefined;
+                statusBar.backgroundColor = undefined;
+                break;
+            case "warning":
+                statusBar.tooltip =
+                    (status.message ? status.message + "\n" : "") + "Click to reload.";
+
+                statusBar.command = "rust-analyzer.reloadWorkspace";
+                statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
+                statusBar.backgroundColor = new vscode.ThemeColor(
+                    "statusBarItem.warningBackground"
+                );
+                icon = "$(warning) ";
+                break;
+            case "error":
+                statusBar.tooltip =
+                    (status.message ? status.message + "\n" : "") + "Click to reload.";
+
+                statusBar.command = "rust-analyzer.reloadWorkspace";
+                statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground");
+                statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
+                icon = "$(error) ";
+                break;
+        }
+        if (!status.quiescent) icon = "$(sync~spin) ";
+        statusBar.text = `${icon}rust-analyzer`;
+    }
+
+    pushCleanup(d: Disposable) {
+        this.extCtx.subscriptions.push(d);
+    }
+}
+
+export interface Disposable {
+    dispose(): void;
+}
+export type Cmd = (...args: any[]) => unknown;
diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts
new file mode 100644
index 00000000000..bd45599227e
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/debug.ts
@@ -0,0 +1,202 @@
+import * as os from "os";
+import * as vscode from "vscode";
+import * as path from "path";
+import * as ra from "./lsp_ext";
+
+import { Cargo, getRustcId, getSysroot } from "./toolchain";
+import { Ctx } from "./ctx";
+import { prepareEnv } from "./run";
+
+const debugOutput = vscode.window.createOutputChannel("Debug");
+type DebugConfigProvider = (
+    config: ra.Runnable,
+    executable: string,
+    env: Record<string, string>,
+    sourceFileMap?: Record<string, string>
+) => vscode.DebugConfiguration;
+
+export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
+    const scope = ctx.activeRustEditor?.document.uri;
+    if (!scope) return;
+
+    const debugConfig = await getDebugConfiguration(ctx, runnable);
+    if (!debugConfig) return;
+
+    const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
+    const configurations = wsLaunchSection.get<any[]>("configurations") || [];
+
+    const index = configurations.findIndex((c) => c.name === debugConfig.name);
+    if (index !== -1) {
+        const answer = await vscode.window.showErrorMessage(
+            `Launch configuration '${debugConfig.name}' already exists!`,
+            "Cancel",
+            "Update"
+        );
+        if (answer === "Cancel") return;
+
+        configurations[index] = debugConfig;
+    } else {
+        configurations.push(debugConfig);
+    }
+
+    await wsLaunchSection.update("configurations", configurations);
+}
+
+export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promise<boolean> {
+    let debugConfig: vscode.DebugConfiguration | undefined = undefined;
+    let message = "";
+
+    const wsLaunchSection = vscode.workspace.getConfiguration("launch");
+    const configurations = wsLaunchSection.get<any[]>("configurations") || [];
+
+    const index = configurations.findIndex((c) => c.name === runnable.label);
+    if (-1 !== index) {
+        debugConfig = configurations[index];
+        message = " (from launch.json)";
+        debugOutput.clear();
+    } else {
+        debugConfig = await getDebugConfiguration(ctx, runnable);
+    }
+
+    if (!debugConfig) return false;
+
+    debugOutput.appendLine(`Launching debug configuration${message}:`);
+    debugOutput.appendLine(JSON.stringify(debugConfig, null, 2));
+    return vscode.debug.startDebugging(undefined, debugConfig);
+}
+
+async function getDebugConfiguration(
+    ctx: Ctx,
+    runnable: ra.Runnable
+): Promise<vscode.DebugConfiguration | undefined> {
+    const editor = ctx.activeRustEditor;
+    if (!editor) return;
+
+    const knownEngines: Record<string, DebugConfigProvider> = {
+        "vadimcn.vscode-lldb": getLldbDebugConfig,
+        "ms-vscode.cpptools": getCppvsDebugConfig,
+    };
+    const debugOptions = ctx.config.debug;
+
+    let debugEngine = null;
+    if (debugOptions.engine === "auto") {
+        for (var engineId in knownEngines) {
+            debugEngine = vscode.extensions.getExtension(engineId);
+            if (debugEngine) break;
+        }
+    } else {
+        debugEngine = vscode.extensions.getExtension(debugOptions.engine);
+    }
+
+    if (!debugEngine) {
+        await vscode.window.showErrorMessage(
+            `Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)` +
+                ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`
+        );
+        return;
+    }
+
+    debugOutput.clear();
+    if (ctx.config.debug.openDebugPane) {
+        debugOutput.show(true);
+    }
+    // folder exists or RA is not active.
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+    const workspaceFolders = vscode.workspace.workspaceFolders!;
+    const isMultiFolderWorkspace = workspaceFolders.length > 1;
+    const firstWorkspace = workspaceFolders[0];
+    const workspace =
+        !isMultiFolderWorkspace || !runnable.args.workspaceRoot
+            ? firstWorkspace
+            : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) ||
+              firstWorkspace;
+
+    const wsFolder = path.normalize(workspace.uri.fsPath);
+    const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : "";
+    function simplifyPath(p: string): string {
+        // see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed
+        return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}");
+    }
+
+    const executable = await getDebugExecutable(runnable);
+    const env = prepareEnv(runnable, ctx.config.runnableEnv);
+    let sourceFileMap = debugOptions.sourceFileMap;
+    if (sourceFileMap === "auto") {
+        // let's try to use the default toolchain
+        const commitHash = await getRustcId(wsFolder);
+        const sysroot = await getSysroot(wsFolder);
+        const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
+        sourceFileMap = {};
+        sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
+    }
+
+    const debugConfig = knownEngines[debugEngine.id](
+        runnable,
+        simplifyPath(executable),
+        env,
+        sourceFileMap
+    );
+    if (debugConfig.type in debugOptions.engineSettings) {
+        const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
+        for (var key in settingsMap) {
+            debugConfig[key] = settingsMap[key];
+        }
+    }
+
+    if (debugConfig.name === "run binary") {
+        // The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs,
+        // fn to_lsp_runnable(...) with RunnableKind::Bin
+        debugConfig.name = `run ${path.basename(executable)}`;
+    }
+
+    if (debugConfig.cwd) {
+        debugConfig.cwd = simplifyPath(debugConfig.cwd);
+    }
+
+    return debugConfig;
+}
+
+async function getDebugExecutable(runnable: ra.Runnable): Promise<string> {
+    const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput);
+    const executable = await cargo.executableFromArgs(runnable.args.cargoArgs);
+
+    // if we are here, there were no compilation errors.
+    return executable;
+}
+
+function getLldbDebugConfig(
+    runnable: ra.Runnable,
+    executable: string,
+    env: Record<string, string>,
+    sourceFileMap?: Record<string, string>
+): vscode.DebugConfiguration {
+    return {
+        type: "lldb",
+        request: "launch",
+        name: runnable.label,
+        program: executable,
+        args: runnable.args.executableArgs,
+        cwd: runnable.args.workspaceRoot,
+        sourceMap: sourceFileMap,
+        sourceLanguages: ["rust"],
+        env,
+    };
+}
+
+function getCppvsDebugConfig(
+    runnable: ra.Runnable,
+    executable: string,
+    env: Record<string, string>,
+    sourceFileMap?: Record<string, string>
+): vscode.DebugConfiguration {
+    return {
+        type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg",
+        request: "launch",
+        name: runnable.label,
+        program: executable,
+        args: runnable.args.executableArgs,
+        cwd: runnable.args.workspaceRoot,
+        sourceFileMap,
+        env,
+    };
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
new file mode 100644
index 00000000000..f80af78a74a
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -0,0 +1,180 @@
+/**
+ * This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations.
+ */
+
+import * as lc from "vscode-languageclient";
+
+export interface AnalyzerStatusParams {
+    textDocument?: lc.TextDocumentIdentifier;
+}
+export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>(
+    "rust-analyzer/analyzerStatus"
+);
+export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
+export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph");
+
+export interface ServerStatusParams {
+    health: "ok" | "warning" | "error";
+    quiescent: boolean;
+    message?: string;
+}
+export const serverStatus = new lc.NotificationType<ServerStatusParams>(
+    "experimental/serverStatus"
+);
+
+export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
+
+export const hover = new lc.RequestType<HoverParams, lc.Hover | null, void>("textDocument/hover");
+
+export interface HoverParams extends lc.WorkDoneProgressParams {
+    textDocument: lc.TextDocumentIdentifier;
+    position: lc.Range | lc.Position;
+}
+
+export interface SyntaxTreeParams {
+    textDocument: lc.TextDocumentIdentifier;
+    range: lc.Range | null;
+}
+export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>(
+    "rust-analyzer/syntaxTree"
+);
+
+export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>(
+    "rust-analyzer/viewHir"
+);
+
+export const viewFileText = new lc.RequestType<lc.TextDocumentIdentifier, string, void>(
+    "rust-analyzer/viewFileText"
+);
+
+export interface ViewItemTreeParams {
+    textDocument: lc.TextDocumentIdentifier;
+}
+
+export const viewItemTree = new lc.RequestType<ViewItemTreeParams, string, void>(
+    "rust-analyzer/viewItemTree"
+);
+
+export interface ViewCrateGraphParams {
+    full: boolean;
+}
+
+export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>(
+    "rust-analyzer/viewCrateGraph"
+);
+
+export interface ExpandMacroParams {
+    textDocument: lc.TextDocumentIdentifier;
+    position: lc.Position;
+}
+export interface ExpandedMacro {
+    name: string;
+    expansion: string;
+}
+export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>(
+    "rust-analyzer/expandMacro"
+);
+
+export interface MatchingBraceParams {
+    textDocument: lc.TextDocumentIdentifier;
+    positions: lc.Position[];
+}
+export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>(
+    "experimental/matchingBrace"
+);
+
+export const parentModule = new lc.RequestType<
+    lc.TextDocumentPositionParams,
+    lc.LocationLink[] | null,
+    void
+>("experimental/parentModule");
+
+export interface JoinLinesParams {
+    textDocument: lc.TextDocumentIdentifier;
+    ranges: lc.Range[];
+}
+export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>(
+    "experimental/joinLines"
+);
+
+export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>(
+    "experimental/onEnter"
+);
+
+export interface RunnablesParams {
+    textDocument: lc.TextDocumentIdentifier;
+    position: lc.Position | null;
+}
+
+export interface Runnable {
+    label: string;
+    location?: lc.LocationLink;
+    kind: "cargo";
+    args: {
+        workspaceRoot?: string;
+        cargoArgs: string[];
+        cargoExtraArgs: string[];
+        executableArgs: string[];
+        expectTest?: boolean;
+        overrideCargo?: string;
+    };
+}
+export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>(
+    "experimental/runnables"
+);
+
+export interface TestInfo {
+    runnable: Runnable;
+}
+
+export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>(
+    "rust-analyzer/relatedTests"
+);
+
+export interface SsrParams {
+    query: string;
+    parseOnly: boolean;
+    textDocument: lc.TextDocumentIdentifier;
+    position: lc.Position;
+    selections: readonly lc.Range[];
+}
+export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr");
+
+export interface CommandLink extends lc.Command {
+    /**
+     * A tooltip for the command, when represented in the UI.
+     */
+    tooltip?: string;
+}
+
+export interface CommandLinkGroup {
+    title?: string;
+    commands: CommandLink[];
+}
+
+export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>(
+    "experimental/externalDocs"
+);
+
+export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>(
+    "experimental/openCargoToml"
+);
+
+export interface OpenCargoTomlParams {
+    textDocument: lc.TextDocumentIdentifier;
+}
+
+export const moveItem = new lc.RequestType<MoveItemParams, lc.TextEdit[], void>(
+    "experimental/moveItem"
+);
+
+export interface MoveItemParams {
+    textDocument: lc.TextDocumentIdentifier;
+    range: lc.Range;
+    direction: Direction;
+}
+
+export const enum Direction {
+    Up = "Up",
+    Down = "Down",
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
new file mode 100644
index 00000000000..9ae20ddc4ac
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -0,0 +1,403 @@
+import * as vscode from "vscode";
+import * as lc from "vscode-languageclient/node";
+import * as os from "os";
+
+import * as commands from "./commands";
+import { Ctx } from "./ctx";
+import { Config } from "./config";
+import { log, isValidExecutable, isRustDocument } from "./util";
+import { PersistentState } from "./persistent_state";
+import { activateTaskProvider } from "./tasks";
+import { setContextValue } from "./util";
+import { exec } from "child_process";
+
+let ctx: Ctx | undefined;
+
+const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
+
+let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
+export function traceOutputChannel() {
+    if (!TRACE_OUTPUT_CHANNEL) {
+        TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel(
+            "Rust Analyzer Language Server Trace"
+        );
+    }
+    return TRACE_OUTPUT_CHANNEL;
+}
+let OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
+export function outputChannel() {
+    if (!OUTPUT_CHANNEL) {
+        OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rust Analyzer Language Server");
+    }
+    return OUTPUT_CHANNEL;
+}
+
+export interface RustAnalyzerExtensionApi {
+    client: lc.LanguageClient;
+}
+
+export async function activate(
+    context: vscode.ExtensionContext
+): Promise<RustAnalyzerExtensionApi> {
+    // VS Code doesn't show a notification when an extension fails to activate
+    // so we do it ourselves.
+    return await tryActivate(context).catch((err) => {
+        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
+        throw err;
+    });
+}
+
+async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
+    const config = new Config(context);
+    const state = new PersistentState(context.globalState);
+    const serverPath = await bootstrap(context, config, state).catch((err) => {
+        let message = "bootstrap error. ";
+
+        message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
+        message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
+
+        log.error("Bootstrap error", err);
+        throw new Error(message);
+    });
+
+    if ((vscode.workspace.workspaceFolders || []).length === 0) {
+        const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
+            isRustDocument(document)
+        );
+        if (rustDocuments.length > 0) {
+            ctx = await Ctx.create(config, context, serverPath, {
+                kind: "Detached Files",
+                files: rustDocuments,
+            });
+        } else {
+            throw new Error("no rust files are opened");
+        }
+    } else {
+        // Note: we try to start the server before we activate type hints so that it
+        // registers its `onDidChangeDocument` handler before us.
+        //
+        // This a horribly, horribly wrong way to deal with this problem.
+        ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" });
+        ctx.pushCleanup(activateTaskProvider(ctx.config));
+    }
+    await initCommonContext(context, ctx);
+
+    warnAboutExtensionConflicts();
+
+    ctx.pushCleanup(configureLanguage());
+
+    vscode.workspace.onDidChangeConfiguration(
+        (_) =>
+            ctx?.client
+                ?.sendNotification("workspace/didChangeConfiguration", { settings: "" })
+                .catch(log.error),
+        null,
+        ctx.subscriptions
+    );
+
+    return {
+        client: ctx.client,
+    };
+}
+
+async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
+    // Register a "dumb" onEnter command for the case where server fails to
+    // start.
+    //
+    // FIXME: refactor command registration code such that commands are
+    // **always** registered, even if the server does not start. Use API like
+    // this perhaps?
+    //
+    // ```TypeScript
+    // registerCommand(
+    //    factory: (Ctx) => ((Ctx) => any),
+    //    fallback: () => any = () => vscode.window.showErrorMessage(
+    //        "rust-analyzer is not available"
+    //    ),
+    // )
+    const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () =>
+        vscode.commands.executeCommand("default:type", { text: "\n" })
+    );
+    context.subscriptions.push(defaultOnEnter);
+
+    await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
+
+    // Commands which invokes manually via command palette, shortcut, etc.
+
+    // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895
+    ctx.registerCommand("reload", (_) => async () => {
+        void vscode.window.showInformationMessage("Reloading rust-analyzer...");
+        await doDeactivate();
+        while (context.subscriptions.length > 0) {
+            try {
+                context.subscriptions.pop()!.dispose();
+            } catch (err) {
+                log.error("Dispose error:", err);
+            }
+        }
+        await activate(context).catch(log.error);
+    });
+
+    ctx.registerCommand("analyzerStatus", commands.analyzerStatus);
+    ctx.registerCommand("memoryUsage", commands.memoryUsage);
+    ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph);
+    ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace);
+    ctx.registerCommand("matchingBrace", commands.matchingBrace);
+    ctx.registerCommand("joinLines", commands.joinLines);
+    ctx.registerCommand("parentModule", commands.parentModule);
+    ctx.registerCommand("syntaxTree", commands.syntaxTree);
+    ctx.registerCommand("viewHir", commands.viewHir);
+    ctx.registerCommand("viewFileText", commands.viewFileText);
+    ctx.registerCommand("viewItemTree", commands.viewItemTree);
+    ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph);
+    ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph);
+    ctx.registerCommand("expandMacro", commands.expandMacro);
+    ctx.registerCommand("run", commands.run);
+    ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine);
+    ctx.registerCommand("debug", commands.debug);
+    ctx.registerCommand("newDebugConfig", commands.newDebugConfig);
+    ctx.registerCommand("openDocs", commands.openDocs);
+    ctx.registerCommand("openCargoToml", commands.openCargoToml);
+    ctx.registerCommand("peekTests", commands.peekTests);
+    ctx.registerCommand("moveItemUp", commands.moveItemUp);
+    ctx.registerCommand("moveItemDown", commands.moveItemDown);
+
+    defaultOnEnter.dispose();
+    ctx.registerCommand("onEnter", commands.onEnter);
+
+    ctx.registerCommand("ssr", commands.ssr);
+    ctx.registerCommand("serverVersion", commands.serverVersion);
+    ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints);
+
+    // Internal commands which are invoked by the server.
+    ctx.registerCommand("runSingle", commands.runSingle);
+    ctx.registerCommand("debugSingle", commands.debugSingle);
+    ctx.registerCommand("showReferences", commands.showReferences);
+    ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand);
+    ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction);
+    ctx.registerCommand("applyActionGroup", commands.applyActionGroup);
+    ctx.registerCommand("gotoLocation", commands.gotoLocation);
+
+    ctx.registerCommand("linkToCommand", commands.linkToCommand);
+}
+
+export async function deactivate() {
+    TRACE_OUTPUT_CHANNEL?.dispose();
+    TRACE_OUTPUT_CHANNEL = null;
+    OUTPUT_CHANNEL?.dispose();
+    OUTPUT_CHANNEL = null;
+    await doDeactivate();
+}
+
+async function doDeactivate() {
+    await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
+    await ctx?.client.stop();
+    ctx = undefined;
+}
+
+async function bootstrap(
+    context: vscode.ExtensionContext,
+    config: Config,
+    state: PersistentState
+): Promise<string> {
+    const path = await getServer(context, config, state);
+    if (!path) {
+        throw new Error(
+            "Rust Analyzer Language Server is not available. " +
+                "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
+        );
+    }
+
+    log.info("Using server binary at", path);
+
+    if (!isValidExecutable(path)) {
+        if (config.serverPath) {
+            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
+            Consider removing this config or making a valid server binary available at that path.`);
+        } else {
+            throw new Error(`Failed to execute ${path} --version`);
+        }
+    }
+
+    return path;
+}
+
+async function patchelf(dest: vscode.Uri): Promise<void> {
+    await vscode.window.withProgress(
+        {
+            location: vscode.ProgressLocation.Notification,
+            title: "Patching rust-analyzer for NixOS",
+        },
+        async (progress, _) => {
+            const expression = `
+            {srcStr, pkgs ? import <nixpkgs> {}}:
+                pkgs.stdenv.mkDerivation {
+                    name = "rust-analyzer";
+                    src = /. + srcStr;
+                    phases = [ "installPhase" "fixupPhase" ];
+                    installPhase = "cp $src $out";
+                    fixupPhase = ''
+                    chmod 755 $out
+                    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
+                    '';
+                }
+            `;
+            const origFile = vscode.Uri.file(dest.fsPath + "-orig");
+            await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
+            try {
+                progress.report({ message: "Patching executable", increment: 20 });
+                await new Promise((resolve, reject) => {
+                    const handle = exec(
+                        `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
+                        (err, stdout, stderr) => {
+                            if (err != null) {
+                                reject(Error(stderr));
+                            } else {
+                                resolve(stdout);
+                            }
+                        }
+                    );
+                    handle.stdin?.write(expression);
+                    handle.stdin?.end();
+                });
+            } finally {
+                await vscode.workspace.fs.delete(origFile);
+            }
+        }
+    );
+}
+
+async function getServer(
+    context: vscode.ExtensionContext,
+    config: Config,
+    state: PersistentState
+): Promise<string | undefined> {
+    const explicitPath = serverPath(config);
+    if (explicitPath) {
+        if (explicitPath.startsWith("~/")) {
+            return os.homedir() + explicitPath.slice("~".length);
+        }
+        return explicitPath;
+    }
+    if (config.package.releaseTag === null) return "rust-analyzer";
+
+    const ext = process.platform === "win32" ? ".exe" : "";
+    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
+    const bundledExists = await vscode.workspace.fs.stat(bundled).then(
+        () => true,
+        () => false
+    );
+    if (bundledExists) {
+        let server = bundled;
+        if (await isNixOs()) {
+            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
+            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
+            let exists = await vscode.workspace.fs.stat(dest).then(
+                () => true,
+                () => false
+            );
+            if (exists && config.package.version !== state.serverVersion) {
+                await vscode.workspace.fs.delete(dest);
+                exists = false;
+            }
+            if (!exists) {
+                await vscode.workspace.fs.copy(bundled, dest);
+                await patchelf(dest);
+            }
+            server = dest;
+        }
+        await state.updateServerVersion(config.package.version);
+        return server.fsPath;
+    }
+
+    await state.updateServerVersion(undefined);
+    await vscode.window.showErrorMessage(
+        "Unfortunately we don't ship binaries for your platform yet. " +
+            "You need to manually clone the rust-analyzer repository and " +
+            "run `cargo xtask install --server` to build the language server from sources. " +
+            "If you feel that your platform should be supported, please create an issue " +
+            "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
+            "will consider it."
+    );
+    return undefined;
+}
+
+function serverPath(config: Config): string | null {
+    return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
+}
+
+async function isNixOs(): Promise<boolean> {
+    try {
+        const contents = (
+            await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
+        ).toString();
+        const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
+        return idString.indexOf("nixos") !== -1;
+    } catch {
+        return false;
+    }
+}
+
+function warnAboutExtensionConflicts() {
+    if (vscode.extensions.getExtension("rust-lang.rust")) {
+        vscode.window
+            .showWarningMessage(
+                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
+                    "plugins enabled. These are known to conflict and cause various functions of " +
+                    "both plugins to not work correctly. You should disable one of them.",
+                "Got it"
+            )
+            .then(() => {}, console.error);
+    }
+}
+
+/**
+ * Sets up additional language configuration that's impossible to do via a
+ * separate language-configuration.json file. See [1] for more information.
+ *
+ * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
+ */
+function configureLanguage(): vscode.Disposable {
+    const indentAction = vscode.IndentAction.None;
+    return vscode.languages.setLanguageConfiguration("rust", {
+        onEnterRules: [
+            {
+                // Doc single-line comment
+                // e.g. ///|
+                beforeText: /^\s*\/{3}.*$/,
+                action: { indentAction, appendText: "/// " },
+            },
+            {
+                // Parent doc single-line comment
+                // e.g. //!|
+                beforeText: /^\s*\/{2}\!.*$/,
+                action: { indentAction, appendText: "//! " },
+            },
+            {
+                // Begins an auto-closed multi-line comment (standard or parent doc)
+                // e.g. /** | */ or /*! | */
+                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
+                afterText: /^\s*\*\/$/,
+                action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
+            },
+            {
+                // Begins a multi-line comment (standard or parent doc)
+                // e.g. /** ...| or /*! ...|
+                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
+                action: { indentAction, appendText: " * " },
+            },
+            {
+                // Continues a multi-line comment
+                // e.g.  * ...|
+                beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
+                action: { indentAction, appendText: "* " },
+            },
+            {
+                // Dedents after closing a multi-line comment
+                // e.g.  */|
+                beforeText: /^(\ \ )*\ \*\/\s*$/,
+                action: { indentAction, removeText: 1 },
+            },
+        ],
+    });
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/persistent_state.ts b/src/tools/rust-analyzer/editors/code/src/persistent_state.ts
new file mode 100644
index 00000000000..8964a78dc32
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/persistent_state.ts
@@ -0,0 +1,20 @@
+import * as vscode from "vscode";
+import { log } from "./util";
+
+export class PersistentState {
+    constructor(private readonly globalState: vscode.Memento) {
+        const { serverVersion } = this;
+        log.info("PersistentState:", { serverVersion });
+    }
+
+    /**
+     * Version of the extension that installed the server.
+     * Used to check if we need to run patchelf again on NixOS.
+     */
+    get serverVersion(): string | undefined {
+        return this.globalState.get("serverVersion");
+    }
+    async updateServerVersion(value: string | undefined) {
+        await this.globalState.update("serverVersion", value);
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
new file mode 100644
index 00000000000..22e5eda6827
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -0,0 +1,175 @@
+import * as vscode from "vscode";
+import * as lc from "vscode-languageclient";
+import * as ra from "./lsp_ext";
+import * as tasks from "./tasks";
+
+import { Ctx } from "./ctx";
+import { makeDebugConfig } from "./debug";
+import { Config, RunnableEnvCfg } from "./config";
+
+const quickPickButtons = [
+    { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
+];
+
+export async function selectRunnable(
+    ctx: Ctx,
+    prevRunnable?: RunnableQuickPick,
+    debuggeeOnly = false,
+    showButtons: boolean = true
+): Promise<RunnableQuickPick | undefined> {
+    const editor = ctx.activeRustEditor;
+    const client = ctx.client;
+    if (!editor || !client) return;
+
+    const textDocument: lc.TextDocumentIdentifier = {
+        uri: editor.document.uri.toString(),
+    };
+
+    const runnables = await client.sendRequest(ra.runnables, {
+        textDocument,
+        position: client.code2ProtocolConverter.asPosition(editor.selection.active),
+    });
+    const items: RunnableQuickPick[] = [];
+    if (prevRunnable) {
+        items.push(prevRunnable);
+    }
+    for (const r of runnables) {
+        if (prevRunnable && JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)) {
+            continue;
+        }
+
+        if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) {
+            continue;
+        }
+        items.push(new RunnableQuickPick(r));
+    }
+
+    if (items.length === 0) {
+        // it is the debug case, run always has at least 'cargo check ...'
+        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
+        await vscode.window.showErrorMessage("There's no debug target!");
+        return;
+    }
+
+    return await new Promise((resolve) => {
+        const disposables: vscode.Disposable[] = [];
+        const close = (result?: RunnableQuickPick) => {
+            resolve(result);
+            disposables.forEach((d) => d.dispose());
+        };
+
+        const quickPick = vscode.window.createQuickPick<RunnableQuickPick>();
+        quickPick.items = items;
+        quickPick.title = "Select Runnable";
+        if (showButtons) {
+            quickPick.buttons = quickPickButtons;
+        }
+        disposables.push(
+            quickPick.onDidHide(() => close()),
+            quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
+            quickPick.onDidTriggerButton(async (_button) => {
+                await makeDebugConfig(ctx, quickPick.activeItems[0].runnable);
+                close();
+            }),
+            quickPick.onDidChangeActive((active) => {
+                if (showButtons && active.length > 0) {
+                    if (active[0].label.startsWith("cargo")) {
+                        // save button makes no sense for `cargo test` or `cargo check`
+                        quickPick.buttons = [];
+                    } else if (quickPick.buttons.length === 0) {
+                        quickPick.buttons = quickPickButtons;
+                    }
+                }
+            }),
+            quickPick
+        );
+        quickPick.show();
+    });
+}
+
+export class RunnableQuickPick implements vscode.QuickPickItem {
+    public label: string;
+    public description?: string | undefined;
+    public detail?: string | undefined;
+    public picked?: boolean | undefined;
+
+    constructor(public runnable: ra.Runnable) {
+        this.label = runnable.label;
+    }
+}
+
+export function prepareEnv(
+    runnable: ra.Runnable,
+    runnableEnvCfg: RunnableEnvCfg
+): Record<string, string> {
+    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
+
+    if (runnable.args.expectTest) {
+        env["UPDATE_EXPECT"] = "1";
+    }
+
+    Object.assign(env, process.env as { [key: string]: string });
+
+    if (runnableEnvCfg) {
+        if (Array.isArray(runnableEnvCfg)) {
+            for (const it of runnableEnvCfg) {
+                if (!it.mask || new RegExp(it.mask).test(runnable.label)) {
+                    Object.assign(env, it.env);
+                }
+            }
+        } else {
+            Object.assign(env, runnableEnvCfg);
+        }
+    }
+
+    return env;
+}
+
+export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
+    if (runnable.kind !== "cargo") {
+        // rust-analyzer supports only one kind, "cargo"
+        // do not use tasks.TASK_TYPE here, these are completely different meanings.
+
+        throw `Unexpected runnable kind: ${runnable.kind}`;
+    }
+
+    const args = createArgs(runnable);
+
+    const definition: tasks.CargoTaskDefinition = {
+        type: tasks.TASK_TYPE,
+        command: args[0], // run, test, etc...
+        args: args.slice(1),
+        cwd: runnable.args.workspaceRoot || ".",
+        env: prepareEnv(runnable, config.runnableEnv),
+        overrideCargo: runnable.args.overrideCargo,
+    };
+
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+    const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
+    const cargoTask = await tasks.buildCargoTask(
+        target,
+        definition,
+        runnable.label,
+        args,
+        config.cargoRunner,
+        true
+    );
+
+    cargoTask.presentationOptions.clear = true;
+    // Sadly, this doesn't prevent focus stealing if the terminal is currently
+    // hidden, and will become revealed due to task exucution.
+    cargoTask.presentationOptions.focus = false;
+
+    return cargoTask;
+}
+
+export function createArgs(runnable: ra.Runnable): string[] {
+    const args = [...runnable.args.cargoArgs]; // should be a copy!
+    if (runnable.args.cargoExtraArgs) {
+        args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options.
+    }
+    if (runnable.args.executableArgs.length > 0) {
+        args.push("--", ...runnable.args.executableArgs);
+    }
+    return args;
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts
new file mode 100644
index 00000000000..299d29c27ee
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts
@@ -0,0 +1,87 @@
+import * as vscode from "vscode";
+
+import { assert } from "./util";
+
+export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
+    if (edit.entries().length === 1) {
+        const [uri, edits] = edit.entries()[0];
+        const editor = await editorFromUri(uri);
+        if (editor) await applySnippetTextEdits(editor, edits);
+        return;
+    }
+    for (const [uri, edits] of edit.entries()) {
+        const editor = await editorFromUri(uri);
+        if (editor) {
+            await editor.edit((builder) => {
+                for (const indel of edits) {
+                    assert(
+                        !parseSnippet(indel.newText),
+                        `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`
+                    );
+                    builder.replace(indel.range, indel.newText);
+                }
+            });
+        }
+    }
+}
+
+async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undefined> {
+    if (vscode.window.activeTextEditor?.document.uri !== uri) {
+        // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed
+        await vscode.window.showTextDocument(uri, {});
+    }
+    return vscode.window.visibleTextEditors.find(
+        (it) => it.document.uri.toString() === uri.toString()
+    );
+}
+
+export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) {
+    const selections: vscode.Selection[] = [];
+    let lineDelta = 0;
+    await editor.edit((builder) => {
+        for (const indel of edits) {
+            const parsed = parseSnippet(indel.newText);
+            if (parsed) {
+                const [newText, [placeholderStart, placeholderLength]] = parsed;
+                const prefix = newText.substr(0, placeholderStart);
+                const lastNewline = prefix.lastIndexOf("\n");
+
+                const startLine = indel.range.start.line + lineDelta + countLines(prefix);
+                const startColumn =
+                    lastNewline === -1
+                        ? indel.range.start.character + placeholderStart
+                        : prefix.length - lastNewline - 1;
+                const endColumn = startColumn + placeholderLength;
+                selections.push(
+                    new vscode.Selection(
+                        new vscode.Position(startLine, startColumn),
+                        new vscode.Position(startLine, endColumn)
+                    )
+                );
+                builder.replace(indel.range, newText);
+            } else {
+                builder.replace(indel.range, indel.newText);
+            }
+            lineDelta +=
+                countLines(indel.newText) - (indel.range.end.line - indel.range.start.line);
+        }
+    });
+    if (selections.length > 0) editor.selections = selections;
+    if (selections.length === 1) {
+        editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport);
+    }
+}
+
+function parseSnippet(snip: string): [string, [number, number]] | undefined {
+    const m = snip.match(/\$(0|\{0:([^}]*)\})/);
+    if (!m) return undefined;
+    const placeholder = m[2] ?? "";
+    if (m.index == null) return undefined;
+    const range: [number, number] = [m.index, placeholder.length];
+    const insert = snip.replace(m[0], placeholder);
+    return [insert, range];
+}
+
+function countLines(text: string): number {
+    return (text.match(/\n/g) || []).length;
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts
new file mode 100644
index 00000000000..e6239deeb21
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts
@@ -0,0 +1,138 @@
+import * as vscode from "vscode";
+import * as toolchain from "./toolchain";
+import { Config } from "./config";
+import { log } from "./util";
+
+// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
+// our configuration should be compatible with it so use the same key.
+export const TASK_TYPE = "cargo";
+export const TASK_SOURCE = "rust";
+
+export interface CargoTaskDefinition extends vscode.TaskDefinition {
+    command?: string;
+    args?: string[];
+    cwd?: string;
+    env?: { [key: string]: string };
+    overrideCargo?: string;
+}
+
+class CargoTaskProvider implements vscode.TaskProvider {
+    private readonly config: Config;
+
+    constructor(config: Config) {
+        this.config = config;
+    }
+
+    async provideTasks(): Promise<vscode.Task[]> {
+        // Detect Rust tasks. Currently we do not do any actual detection
+        // of tasks (e.g. aliases in .cargo/config) and just return a fixed
+        // set of tasks that always exist. These tasks cannot be removed in
+        // tasks.json - only tweaked.
+
+        const defs = [
+            { command: "build", group: vscode.TaskGroup.Build },
+            { command: "check", group: vscode.TaskGroup.Build },
+            { command: "clippy", group: vscode.TaskGroup.Build },
+            { command: "test", group: vscode.TaskGroup.Test },
+            { command: "clean", group: vscode.TaskGroup.Clean },
+            { command: "run", group: undefined },
+        ];
+
+        const tasks: vscode.Task[] = [];
+        for (const workspaceTarget of vscode.workspace.workspaceFolders || []) {
+            for (const def of defs) {
+                const vscodeTask = await buildCargoTask(
+                    workspaceTarget,
+                    { type: TASK_TYPE, command: def.command },
+                    `cargo ${def.command}`,
+                    [def.command],
+                    this.config.cargoRunner
+                );
+                vscodeTask.group = def.group;
+                tasks.push(vscodeTask);
+            }
+        }
+
+        return tasks;
+    }
+
+    async resolveTask(task: vscode.Task): Promise<vscode.Task | undefined> {
+        // VSCode calls this for every cargo task in the user's tasks.json,
+        // we need to inform VSCode how to execute that command by creating
+        // a ShellExecution for it.
+
+        const definition = task.definition as CargoTaskDefinition;
+
+        if (definition.type === TASK_TYPE && definition.command) {
+            const args = [definition.command].concat(definition.args ?? []);
+            return await buildCargoTask(
+                task.scope,
+                definition,
+                task.name,
+                args,
+                this.config.cargoRunner
+            );
+        }
+
+        return undefined;
+    }
+}
+
+export async function buildCargoTask(
+    scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
+    definition: CargoTaskDefinition,
+    name: string,
+    args: string[],
+    customRunner?: string,
+    throwOnError: boolean = false
+): Promise<vscode.Task> {
+    let exec: vscode.ProcessExecution | vscode.ShellExecution | undefined = undefined;
+
+    if (customRunner) {
+        const runnerCommand = `${customRunner}.buildShellExecution`;
+        try {
+            const runnerArgs = { kind: TASK_TYPE, args, cwd: definition.cwd, env: definition.env };
+            const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs);
+            if (customExec) {
+                if (customExec instanceof vscode.ShellExecution) {
+                    exec = customExec;
+                } else {
+                    log.debug("Invalid cargo ShellExecution", customExec);
+                    throw "Invalid cargo ShellExecution.";
+                }
+            }
+            // fallback to default processing
+        } catch (e) {
+            if (throwOnError) throw `Cargo runner '${customRunner}' failed! ${e}`;
+            // fallback to default processing
+        }
+    }
+
+    if (!exec) {
+        // Check whether we must use a user-defined substitute for cargo.
+        // Split on spaces to allow overrides like "wrapper cargo".
+        const overrideCargo = definition.overrideCargo ?? definition.overrideCargo;
+        const cargoPath = await toolchain.cargoPath();
+        const cargoCommand = overrideCargo?.split(" ") ?? [cargoPath];
+
+        const fullCommand = [...cargoCommand, ...args];
+
+        exec = new vscode.ProcessExecution(fullCommand[0], fullCommand.slice(1), definition);
+    }
+
+    return new vscode.Task(
+        definition,
+        // scope can sometimes be undefined. in these situations we default to the workspace taskscope as
+        // recommended by the official docs: https://code.visualstudio.com/api/extension-guides/task-provider#task-provider)
+        scope ?? vscode.TaskScope.Workspace,
+        name,
+        TASK_SOURCE,
+        exec,
+        ["$rustc"]
+    );
+}
+
+export function activateTaskProvider(config: Config): vscode.Disposable {
+    const provider = new CargoTaskProvider(config);
+    return vscode.tasks.registerTaskProvider(TASK_TYPE, provider);
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
new file mode 100644
index 00000000000..bac163da9f3
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts
@@ -0,0 +1,203 @@
+import * as cp from "child_process";
+import * as os from "os";
+import * as path from "path";
+import * as readline from "readline";
+import * as vscode from "vscode";
+import { execute, log, memoizeAsync } from "./util";
+
+interface CompilationArtifact {
+    fileName: string;
+    name: string;
+    kind: string;
+    isTest: boolean;
+}
+
+export interface ArtifactSpec {
+    cargoArgs: string[];
+    filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[];
+}
+
+export class Cargo {
+    constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) {}
+
+    // Made public for testing purposes
+    static artifactSpec(args: readonly string[]): ArtifactSpec {
+        const cargoArgs = [...args, "--message-format=json"];
+
+        // arguments for a runnable from the quick pick should be updated.
+        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
+        switch (cargoArgs[0]) {
+            case "run":
+                cargoArgs[0] = "build";
+                break;
+            case "test": {
+                if (!cargoArgs.includes("--no-run")) {
+                    cargoArgs.push("--no-run");
+                }
+                break;
+            }
+        }
+
+        const result: ArtifactSpec = { cargoArgs: cargoArgs };
+        if (cargoArgs[0] === "test" || cargoArgs[0] === "bench") {
+            // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests
+            // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"}
+            result.filter = (artifacts) => artifacts.filter((it) => it.isTest);
+        }
+
+        return result;
+    }
+
+    private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
+        const artifacts: CompilationArtifact[] = [];
+
+        try {
+            await this.runCargo(
+                spec.cargoArgs,
+                (message) => {
+                    if (message.reason === "compiler-artifact" && message.executable) {
+                        const isBinary = message.target.crate_types.includes("bin");
+                        const isBuildScript = message.target.kind.includes("custom-build");
+                        if ((isBinary && !isBuildScript) || message.profile.test) {
+                            artifacts.push({
+                                fileName: message.executable,
+                                name: message.target.name,
+                                kind: message.target.kind[0],
+                                isTest: message.profile.test,
+                            });
+                        }
+                    } else if (message.reason === "compiler-message") {
+                        this.output.append(message.message.rendered);
+                    }
+                },
+                (stderr) => this.output.append(stderr)
+            );
+        } catch (err) {
+            this.output.show(true);
+            throw new Error(`Cargo invocation has failed: ${err}`);
+        }
+
+        return spec.filter?.(artifacts) ?? artifacts;
+    }
+
+    async executableFromArgs(args: readonly string[]): Promise<string> {
+        const artifacts = await this.getArtifacts(Cargo.artifactSpec(args));
+
+        if (artifacts.length === 0) {
+            throw new Error("No compilation artifacts");
+        } else if (artifacts.length > 1) {
+            throw new Error("Multiple compilation artifacts are not supported.");
+        }
+
+        return artifacts[0].fileName;
+    }
+
+    private async runCargo(
+        cargoArgs: string[],
+        onStdoutJson: (obj: any) => void,
+        onStderrString: (data: string) => void
+    ): Promise<number> {
+        const path = await cargoPath();
+        return await new Promise((resolve, reject) => {
+            const cargo = cp.spawn(path, cargoArgs, {
+                stdio: ["ignore", "pipe", "pipe"],
+                cwd: this.rootFolder,
+            });
+
+            cargo.on("error", (err) => reject(new Error(`could not launch cargo: ${err}`)));
+
+            cargo.stderr.on("data", (chunk) => onStderrString(chunk.toString()));
+
+            const rl = readline.createInterface({ input: cargo.stdout });
+            rl.on("line", (line) => {
+                const message = JSON.parse(line);
+                onStdoutJson(message);
+            });
+
+            cargo.on("exit", (exitCode, _) => {
+                if (exitCode === 0) resolve(exitCode);
+                else reject(new Error(`exit code: ${exitCode}.`));
+            });
+        });
+    }
+}
+
+/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/
+export async function getSysroot(dir: string): Promise<string> {
+    const rustcPath = await getPathForExecutable("rustc");
+
+    // do not memoize the result because the toolchain may change between runs
+    return await execute(`${rustcPath} --print sysroot`, { cwd: dir });
+}
+
+export async function getRustcId(dir: string): Promise<string> {
+    const rustcPath = await getPathForExecutable("rustc");
+
+    // do not memoize the result because the toolchain may change between runs
+    const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
+    const rx = /commit-hash:\s(.*)$/m;
+
+    return rx.exec(data)![1];
+}
+
+/** Mirrors `toolchain::cargo()` implementation */
+export function cargoPath(): Promise<string> {
+    return getPathForExecutable("cargo");
+}
+
+/** Mirrors `toolchain::get_path_for_executable()` implementation */
+export const getPathForExecutable = memoizeAsync(
+    // We apply caching to decrease file-system interactions
+    async (executableName: "cargo" | "rustc" | "rustup"): Promise<string> => {
+        {
+            const envVar = process.env[executableName.toUpperCase()];
+            if (envVar) return envVar;
+        }
+
+        if (await lookupInPath(executableName)) return executableName;
+
+        try {
+            // hmm, `os.homedir()` seems to be infallible
+            // it is not mentioned in docs and cannot be infered by the type signature...
+            const standardPath = vscode.Uri.joinPath(
+                vscode.Uri.file(os.homedir()),
+                ".cargo",
+                "bin",
+                executableName
+            );
+
+            if (await isFileAtUri(standardPath)) return standardPath.fsPath;
+        } catch (err) {
+            log.error("Failed to read the fs info", err);
+        }
+        return executableName;
+    }
+);
+
+async function lookupInPath(exec: string): Promise<boolean> {
+    const paths = process.env.PATH ?? "";
+
+    const candidates = paths.split(path.delimiter).flatMap((dirInPath) => {
+        const candidate = path.join(dirInPath, exec);
+        return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate];
+    });
+
+    for await (const isFile of candidates.map(isFileAtPath)) {
+        if (isFile) {
+            return true;
+        }
+    }
+    return false;
+}
+
+async function isFileAtPath(path: string): Promise<boolean> {
+    return isFileAtUri(vscode.Uri.file(path));
+}
+
+async function isFileAtUri(uri: vscode.Uri): Promise<boolean> {
+    try {
+        return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0;
+    } catch {
+        return false;
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts
new file mode 100644
index 00000000000..cd91932bb60
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/util.ts
@@ -0,0 +1,168 @@
+import * as lc from "vscode-languageclient/node";
+import * as vscode from "vscode";
+import { strict as nativeAssert } from "assert";
+import { exec, ExecOptions, spawnSync } from "child_process";
+import { inspect } from "util";
+
+export function assert(condition: boolean, explanation: string): asserts condition {
+    try {
+        nativeAssert(condition, explanation);
+    } catch (err) {
+        log.error(`Assertion failed:`, explanation);
+        throw err;
+    }
+}
+
+export const log = new (class {
+    private enabled = true;
+    private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
+
+    setEnabled(yes: boolean): void {
+        log.enabled = yes;
+    }
+
+    // Hint: the type [T, ...T[]] means a non-empty array
+    debug(...msg: [unknown, ...unknown[]]): void {
+        if (!log.enabled) return;
+        log.write("DEBUG", ...msg);
+    }
+
+    info(...msg: [unknown, ...unknown[]]): void {
+        log.write("INFO", ...msg);
+    }
+
+    warn(...msg: [unknown, ...unknown[]]): void {
+        debugger;
+        log.write("WARN", ...msg);
+    }
+
+    error(...msg: [unknown, ...unknown[]]): void {
+        debugger;
+        log.write("ERROR", ...msg);
+        log.output.show(true);
+    }
+
+    private write(label: string, ...messageParts: unknown[]): void {
+        const message = messageParts.map(log.stringify).join(" ");
+        const dateTime = new Date().toLocaleString();
+        log.output.appendLine(`${label} [${dateTime}]: ${message}`);
+    }
+
+    private stringify(val: unknown): string {
+        if (typeof val === "string") return val;
+        return inspect(val, {
+            colors: false,
+            depth: 6, // heuristic
+        });
+    }
+})();
+
+export async function sendRequestWithRetry<TParam, TRet>(
+    client: lc.LanguageClient,
+    reqType: lc.RequestType<TParam, TRet, unknown>,
+    param: TParam,
+    token?: vscode.CancellationToken
+): Promise<TRet> {
+    // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3...
+    for (const delay of [40, 160, 640, 2560, 10240, null]) {
+        try {
+            return await (token
+                ? client.sendRequest(reqType, param, token)
+                : client.sendRequest(reqType, param));
+        } catch (error) {
+            if (delay === null) {
+                log.warn("LSP request timed out", { method: reqType.method, param, error });
+                throw error;
+            }
+            if (error.code === lc.LSPErrorCodes.RequestCancelled) {
+                throw error;
+            }
+
+            if (error.code !== lc.LSPErrorCodes.ContentModified) {
+                log.warn("LSP request failed", { method: reqType.method, param, error });
+                throw error;
+            }
+            await sleep(delay);
+        }
+    }
+    throw "unreachable";
+}
+
+export function sleep(ms: number) {
+    return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+export type RustDocument = vscode.TextDocument & { languageId: "rust" };
+export type RustEditor = vscode.TextEditor & { document: RustDocument };
+
+export function isRustDocument(document: vscode.TextDocument): document is RustDocument {
+    // Prevent corrupted text (particularly via inlay hints) in diff views
+    // by allowing only `file` schemes
+    // unfortunately extensions that use diff views not always set this
+    // to something different than 'file' (see ongoing bug: #4608)
+    return document.languageId === "rust" && document.uri.scheme === "file";
+}
+
+export function isCargoTomlDocument(document: vscode.TextDocument): document is RustDocument {
+    // ideally `document.languageId` should be 'toml' but user maybe not have toml extension installed
+    return document.uri.scheme === "file" && document.fileName.endsWith("Cargo.toml");
+}
+
+export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
+    return isRustDocument(editor.document);
+}
+
+export function isValidExecutable(path: string): boolean {
+    log.debug("Checking availability of a binary at", path);
+
+    const res = spawnSync(path, ["--version"], { encoding: "utf8" });
+
+    const printOutput = res.error && (res.error as any).code !== "ENOENT" ? log.warn : log.debug;
+    printOutput(path, "--version:", res);
+
+    return res.status === 0;
+}
+
+/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */
+export function setContextValue(key: string, value: any): Thenable<void> {
+    return vscode.commands.executeCommand("setContext", key, value);
+}
+
+/**
+ * Returns a higher-order function that caches the results of invoking the
+ * underlying async function.
+ */
+export function memoizeAsync<Ret, TThis, Param extends string>(
+    func: (this: TThis, arg: Param) => Promise<Ret>
+) {
+    const cache = new Map<string, Ret>();
+
+    return async function (this: TThis, arg: Param) {
+        const cached = cache.get(arg);
+        if (cached) return cached;
+
+        const result = await func.call(this, arg);
+        cache.set(arg, result);
+
+        return result;
+    };
+}
+
+/** Awaitable wrapper around `child_process.exec` */
+export function execute(command: string, options: ExecOptions): Promise<string> {
+    return new Promise((resolve, reject) => {
+        exec(command, options, (err, stdout, stderr) => {
+            if (err) {
+                reject(err);
+                return;
+            }
+
+            if (stderr) {
+                reject(new Error(stderr));
+                return;
+            }
+
+            resolve(stdout.trimEnd());
+        });
+    });
+}
diff --git a/src/tools/rust-analyzer/editors/code/tests/runTests.ts b/src/tools/rust-analyzer/editors/code/tests/runTests.ts
new file mode 100644
index 00000000000..08632ec3b49
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tests/runTests.ts
@@ -0,0 +1,43 @@
+import * as path from "path";
+import * as fs from "fs";
+
+import { runTests } from "@vscode/test-electron";
+
+async function main() {
+    // The folder containing the Extension Manifest package.json
+    // Passed to `--extensionDevelopmentPath`
+    const extensionDevelopmentPath = path.resolve(__dirname, "../../");
+
+    // Minimum supported version.
+    const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, "package.json"));
+    const json = JSON.parse(jsonData.toString());
+    let minimalVersion: string = json.engines.vscode;
+    if (minimalVersion.startsWith("^")) minimalVersion = minimalVersion.slice(1);
+
+    const launchArgs = ["--disable-extensions", extensionDevelopmentPath];
+
+    // All test suites (either unit tests or integration tests) should be in subfolders.
+    const extensionTestsPath = path.resolve(__dirname, "./unit/index");
+
+    // Run tests using the minimal supported version.
+    await runTests({
+        version: minimalVersion,
+        launchArgs,
+        extensionDevelopmentPath,
+        extensionTestsPath,
+    });
+
+    // and the latest one
+    await runTests({
+        version: "stable",
+        launchArgs,
+        extensionDevelopmentPath,
+        extensionTestsPath,
+    });
+}
+
+main().catch((err) => {
+    // eslint-disable-next-line no-console
+    console.error("Failed to run tests", err);
+    process.exit(1);
+});
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/index.ts b/src/tools/rust-analyzer/editors/code/tests/unit/index.ts
new file mode 100644
index 00000000000..2fa223bed4a
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/index.ts
@@ -0,0 +1,84 @@
+import { readdir } from "fs/promises";
+import * as path from "path";
+
+class Test {
+    readonly name: string;
+    readonly promise: Promise<void>;
+
+    constructor(name: string, promise: Promise<void>) {
+        this.name = name;
+        this.promise = promise;
+    }
+}
+
+class Suite {
+    tests: Test[];
+
+    constructor() {
+        this.tests = [];
+    }
+
+    public addTest(name: string, f: () => Promise<void>): void {
+        const test = new Test(name, f());
+        this.tests.push(test);
+    }
+
+    public async run(): Promise<void> {
+        let failed = 0;
+        for (const test of this.tests) {
+            try {
+                await test.promise;
+                ok(`  ✔ ${test.name}`);
+            } catch (e) {
+                error(`  ✖︎ ${test.name}\n  ${e.stack}`);
+                failed += 1;
+            }
+        }
+        if (failed) {
+            const plural = failed > 1 ? "s" : "";
+            throw new Error(`${failed} failed test${plural}`);
+        }
+    }
+}
+
+export class Context {
+    public async suite(name: string, f: (ctx: Suite) => void): Promise<void> {
+        const ctx = new Suite();
+        f(ctx);
+        try {
+            ok(`⌛︎ ${name}`);
+            await ctx.run();
+            ok(`✔ ${name}`);
+        } catch (e) {
+            error(`✖︎ ${name}\n  ${e.stack}`);
+            throw e;
+        }
+    }
+}
+
+export async function run(): Promise<void> {
+    const context = new Context();
+
+    const testFiles = (await readdir(path.resolve(__dirname))).filter((name) =>
+        name.endsWith(".test.js")
+    );
+    for (const testFile of testFiles) {
+        try {
+            const testModule = require(path.resolve(__dirname, testFile));
+            await testModule.getTests(context);
+        } catch (e) {
+            error(`${e}`);
+            throw e;
+        }
+    }
+}
+
+function ok(message: string): void {
+    // eslint-disable-next-line no-console
+    console.log(`\x1b[32m${message}\x1b[0m`);
+}
+
+function error(message: string): void {
+    // eslint-disable-next-line no-console
+    console.error(`\x1b[31m${message}\x1b[0m`);
+}
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts
new file mode 100644
index 00000000000..0531e064d2d
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts
@@ -0,0 +1,99 @@
+import * as assert from "assert";
+import { Cargo } from "../../src/toolchain";
+import { Context } from ".";
+
+export async function getTests(ctx: Context) {
+    await ctx.suite("Launch configuration/Lens", (suite) => {
+        suite.addTest("A binary", async () => {
+            const args = Cargo.artifactSpec([
+                "build",
+                "--package",
+                "pkg_name",
+                "--bin",
+                "pkg_name",
+            ]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "build",
+                "--package",
+                "pkg_name",
+                "--bin",
+                "pkg_name",
+                "--message-format=json",
+            ]);
+            assert.deepStrictEqual(args.filter, undefined);
+        });
+
+        suite.addTest("One of Multiple Binaries", async () => {
+            const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "build",
+                "--package",
+                "pkg_name",
+                "--bin",
+                "bin1",
+                "--message-format=json",
+            ]);
+            assert.deepStrictEqual(args.filter, undefined);
+        });
+
+        suite.addTest("A test", async () => {
+            const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "test",
+                "--package",
+                "pkg_name",
+                "--lib",
+                "--no-run",
+                "--message-format=json",
+            ]);
+            assert.notDeepStrictEqual(args.filter, undefined);
+        });
+    });
+
+    await ctx.suite("Launch configuration/QuickPick", (suite) => {
+        suite.addTest("A binary", async () => {
+            const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "build",
+                "--package",
+                "pkg_name",
+                "--bin",
+                "pkg_name",
+                "--message-format=json",
+            ]);
+            assert.deepStrictEqual(args.filter, undefined);
+        });
+
+        suite.addTest("One of Multiple Binaries", async () => {
+            const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "build",
+                "--package",
+                "pkg_name",
+                "--bin",
+                "bin2",
+                "--message-format=json",
+            ]);
+            assert.deepStrictEqual(args.filter, undefined);
+        });
+
+        suite.addTest("A test", async () => {
+            const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]);
+
+            assert.deepStrictEqual(args.cargoArgs, [
+                "test",
+                "--package",
+                "pkg_name",
+                "--lib",
+                "--message-format=json",
+                "--no-run",
+            ]);
+            assert.notDeepStrictEqual(args.filter, undefined);
+        });
+    });
+}
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
new file mode 100644
index 00000000000..b7d59e399dd
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts
@@ -0,0 +1,121 @@
+import * as assert from "assert";
+import { prepareEnv } from "../../src/run";
+import { RunnableEnvCfg } from "../../src/config";
+import { Context } from ".";
+import * as ra from "../../src/lsp_ext";
+
+function makeRunnable(label: string): ra.Runnable {
+    return {
+        label,
+        kind: "cargo",
+        args: {
+            cargoArgs: [],
+            executableArgs: [],
+            cargoExtraArgs: [],
+        },
+    };
+}
+
+function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> {
+    const runnable = makeRunnable(runnableName);
+    return prepareEnv(runnable, config);
+}
+
+export async function getTests(ctx: Context) {
+    await ctx.suite("Runnable env", (suite) => {
+        suite.addTest("Global config works", async () => {
+            const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" });
+            assert.strictEqual(binEnv["GLOBAL"], "g");
+
+            const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" });
+            assert.strictEqual(testEnv["GLOBAL"], "g");
+        });
+
+        suite.addTest("null mask works", async () => {
+            const config = [
+                {
+                    env: { DATA: "data" },
+                },
+            ];
+            const binEnv = fakePrepareEnv("run project_name", config);
+            assert.strictEqual(binEnv["DATA"], "data");
+
+            const testEnv = fakePrepareEnv("test some::mod::test_name", config);
+            assert.strictEqual(testEnv["DATA"], "data");
+        });
+
+        suite.addTest("order works", async () => {
+            const config = [
+                {
+                    env: { DATA: "data" },
+                },
+                {
+                    env: { DATA: "newdata" },
+                },
+            ];
+            const binEnv = fakePrepareEnv("run project_name", config);
+            assert.strictEqual(binEnv["DATA"], "newdata");
+
+            const testEnv = fakePrepareEnv("test some::mod::test_name", config);
+            assert.strictEqual(testEnv["DATA"], "newdata");
+        });
+
+        suite.addTest("mask works", async () => {
+            const config = [
+                {
+                    env: { DATA: "data" },
+                },
+                {
+                    mask: "^run",
+                    env: { DATA: "rundata" },
+                },
+                {
+                    mask: "special_test$",
+                    env: { DATA: "special_test" },
+                },
+            ];
+            const binEnv = fakePrepareEnv("run project_name", config);
+            assert.strictEqual(binEnv["DATA"], "rundata");
+
+            const testEnv = fakePrepareEnv("test some::mod::test_name", config);
+            assert.strictEqual(testEnv["DATA"], "data");
+
+            const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config);
+            assert.strictEqual(specialTestEnv["DATA"], "special_test");
+        });
+
+        suite.addTest("exact test name works", async () => {
+            const config = [
+                {
+                    env: { DATA: "data" },
+                },
+                {
+                    mask: "some::mod::test_name",
+                    env: { DATA: "test special" },
+                },
+            ];
+            const testEnv = fakePrepareEnv("test some::mod::test_name", config);
+            assert.strictEqual(testEnv["DATA"], "test special");
+
+            const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
+            assert.strictEqual(specialTestEnv["DATA"], "data");
+        });
+
+        suite.addTest("test mod name works", async () => {
+            const config = [
+                {
+                    env: { DATA: "data" },
+                },
+                {
+                    mask: "some::mod",
+                    env: { DATA: "mod special" },
+                },
+            ];
+            const testEnv = fakePrepareEnv("test some::mod::test_name", config);
+            assert.strictEqual(testEnv["DATA"], "mod special");
+
+            const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
+            assert.strictEqual(specialTestEnv["DATA"], "mod special");
+        });
+    });
+}
diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts
new file mode 100644
index 00000000000..224cea5a232
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts
@@ -0,0 +1,61 @@
+import * as assert from "assert";
+import { Context } from ".";
+import { substituteVariablesInEnv } from "../../src/config";
+
+export async function getTests(ctx: Context) {
+    await ctx.suite("Server Env Settings", (suite) => {
+        suite.addTest("Replacing Env Variables", async () => {
+            const envJson = {
+                USING_MY_VAR: "${env:MY_VAR} test ${env:MY_VAR}",
+                MY_VAR: "test",
+            };
+            const expectedEnv = {
+                USING_MY_VAR: "test test test",
+                MY_VAR: "test",
+            };
+            const actualEnv = await substituteVariablesInEnv(envJson);
+            assert.deepStrictEqual(actualEnv, expectedEnv);
+        });
+
+        suite.addTest("Circular dependencies remain as is", async () => {
+            const envJson = {
+                A_USES_B: "${env:B_USES_A}",
+                B_USES_A: "${env:A_USES_B}",
+                C_USES_ITSELF: "${env:C_USES_ITSELF}",
+                D_USES_C: "${env:C_USES_ITSELF}",
+                E_IS_ISOLATED: "test",
+                F_USES_E: "${env:E_IS_ISOLATED}",
+            };
+            const expectedEnv = {
+                A_USES_B: "${env:B_USES_A}",
+                B_USES_A: "${env:A_USES_B}",
+                C_USES_ITSELF: "${env:C_USES_ITSELF}",
+                D_USES_C: "${env:C_USES_ITSELF}",
+                E_IS_ISOLATED: "test",
+                F_USES_E: "test",
+            };
+            const actualEnv = await substituteVariablesInEnv(envJson);
+            assert.deepStrictEqual(actualEnv, expectedEnv);
+        });
+
+        suite.addTest("Should support external variables", async () => {
+            const envJson = {
+                USING_EXTERNAL_VAR: "${env:TEST_VARIABLE} test ${env:TEST_VARIABLE}",
+            };
+            const expectedEnv = {
+                USING_EXTERNAL_VAR: "test test test",
+            };
+
+            const actualEnv = await substituteVariablesInEnv(envJson);
+            assert.deepStrictEqual(actualEnv, expectedEnv);
+        });
+
+        suite.addTest("should support VSCode variables", async () => {
+            const envJson = {
+                USING_VSCODE_VAR: "${workspaceFolderBasename}",
+            };
+            const actualEnv = await substituteVariablesInEnv(envJson);
+            assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, "code");
+        });
+    });
+}
diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json b/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json
new file mode 100644
index 00000000000..5e2b33ca39f
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json
@@ -0,0 +1,11 @@
+// Special typescript project file, used by eslint only.
+{
+    "extends": "./tsconfig.json",
+    "include": [
+        // repeated from base config's "include" setting
+        "src",
+        "tests",
+        // these are the eslint-only inclusions
+        ".eslintrc.js"
+    ]
+}
diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.json b/src/tools/rust-analyzer/editors/code/tsconfig.json
new file mode 100644
index 00000000000..42e2846858a
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/tsconfig.json
@@ -0,0 +1,19 @@
+{
+    "compilerOptions": {
+        "module": "commonjs",
+        "target": "es2021",
+        "outDir": "out",
+        "lib": ["es2021"],
+        "sourceMap": true,
+        "rootDir": ".",
+        "strict": true,
+        "useUnknownInCatchVariables": false,
+        "noUnusedLocals": true,
+        "noUnusedParameters": true,
+        "noImplicitReturns": true,
+        "noFallthroughCasesInSwitch": true,
+        "newLine": "LF"
+    },
+    "exclude": ["node_modules", ".vscode-test"],
+    "include": ["src", "tests"]
+}