diff --git a/rust-analyzer/editors/code/.eslintrc.js b/rust-analyzer/editors/code/.eslintrc.js new file mode 100644 index 00000000..c6bf410f --- /dev/null +++ b/rust-analyzer/editors/code/.eslintrc.js @@ -0,0 +1,38 @@ +module.exports = { + "env": { + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "camelcase": ["error"], + "eqeqeq": ["error", "always", { "null": "ignore" }], + "no-console": ["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" + } +}; diff --git a/rust-analyzer/editors/code/.gitignore b/rust-analyzer/editors/code/.gitignore new file mode 100644 index 00000000..d8a45ea8 --- /dev/null +++ b/rust-analyzer/editors/code/.gitignore @@ -0,0 +1,5 @@ +out +node_modules +.vscode-test/ +*.vsix +bundle diff --git a/rust-analyzer/editors/code/.vscodeignore b/rust-analyzer/editors/code/.vscodeignore new file mode 100644 index 00000000..7149ab79 --- /dev/null +++ b/rust-analyzer/editors/code/.vscodeignore @@ -0,0 +1,8 @@ +** +!out/src/main.js +!package.json +!package-lock.json +!ra_syntax_tree.tmGrammar.json +!rust.tmGrammar.json +!icon.png +!README.md diff --git a/rust-analyzer/editors/code/README.md b/rust-analyzer/editors/code/README.md new file mode 100644 index 00000000..336695d9 --- /dev/null +++ b/rust-analyzer/editors/code/README.md @@ -0,0 +1,5 @@ +# rust-analyzer + +Provides support for rust-analyzer: novel LSP server for the Rust programming language. + +See https://rust-analyzer.github.io/ for more information. diff --git a/rust-analyzer/editors/code/icon.png b/rust-analyzer/editors/code/icon.png new file mode 100644 index 00000000..072090c6 Binary files /dev/null and b/rust-analyzer/editors/code/icon.png differ diff --git a/rust-analyzer/editors/code/package-lock.json b/rust-analyzer/editors/code/package-lock.json new file mode 100644 index 00000000..4f94c2dc --- /dev/null +++ b/rust-analyzer/editors/code/package-lock.json @@ -0,0 +1,2580 @@ +{ + "name": "rust-analyzer", + "version": "0.4.0-dev", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.3.tgz", + "integrity": "sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz", + "integrity": "sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.3.tgz", + "integrity": "sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.3", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@rollup/plugin-commonjs": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-13.0.0.tgz", + "integrity": "sha512-Anxc3qgkAi7peAyesTqGYidG5GRim9jtg8xhmykNaZkImtvjA7Wsqep08D2mYsqw1IF7rA3lYfciLgzUSgRoqw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "commondir": "^1.0.1", + "estree-walker": "^1.0.1", + "glob": "^7.1.2", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.1.0.tgz", + "integrity": "sha512-ovq7ZM3JJYUUmEjjO+H8tnUdmQmdQudJB7xruX8LFZ1W2q8jXdPUS6SsIYip8ByOApu4RR7729Am9WhCeCMiHA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "deep-freeze": "^0.0.1", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + } + }, + "@rollup/pluginutils": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.10.tgz", + "integrity": "sha512-d44M7t+PjmMrASHbhgpSbVgtL6EFyX7J4mYxwQ/c5eoaE6N2VgCgEcWVzNnwycIloti+/MpwFr8qfw+nRw00sw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", + "dev": true + }, + "@types/node": { + "version": "12.7.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz", + "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", + "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/vscode": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.45.0.tgz", + "integrity": "sha512-b0Gyir7sPBCqiKLygAhn/AYVfzWD+SMPkWltBrIuPEyTOxSU1wVApWY/FcxYO2EWTRacoubTl4+gvZf86RkecA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz", + "integrity": "sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "3.4.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz", + "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "3.4.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz", + "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz", + "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "3.4.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.4.0.tgz", + "integrity": "sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "3.4.0", + "@typescript-eslint/typescript-estree": "3.4.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz", + "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "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-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "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" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array.prototype.map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", + "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.4" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "azure-devops-node-api": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz", + "integrity": "sha512-pMfGJ6gAQ7LRKTHgiRF+8iaUUeGAI0c8puLaqHLc7B8AR7W6GJLozK9RFeUHFjEGybC9/EB3r67WPd7e46zQ8w==", + "dev": true, + "requires": { + "os": "0.1.1", + "tunnel": "0.0.4", + "typed-rest-client": "1.2.0", + "underscore": "1.8.3" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "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==", + "dev": true, + "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" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "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" + } + }, + "cheerio": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.1", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + } + }, + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "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": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "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": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", + "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", + "dev": true, + "requires": { + "ansi-colors": "^3.2.1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "dev": true, + "requires": { + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.1.tgz", + "integrity": "sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.2.0", + "espree": "^7.1.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.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==", + "dev": true, + "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==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "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 + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", + "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", + "dev": true, + "requires": { + "acorn": "^7.2.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.2.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "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 + }, + "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-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": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "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" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "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": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "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==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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 + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "dev": true + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "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 + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", + "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.3.1", + "debug": "3.2.6", + "diff": "4.0.2", + "escape-string-regexp": "1.0.5", + "find-up": "4.1.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "object.assign": "4.1.0", + "promise.allsettled": "1.0.2", + "serialize-javascript": "3.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.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 + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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 + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "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" + } + }, + "os": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz", + "integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", + "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": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "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 + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise.allsettled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", + "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.1", + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "iterate-value": "^1.0.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "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 + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "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" + } + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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 + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.18.1.tgz", + "integrity": "sha512-w4X77ADA+WTGlapC8Z6yggdJtODw3SBl6R2LSkA7ZW5MtdkgcB7sfaSD1UWyx8diXbMcGIb0eI9gCx/dyqOgNQ==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "serialize-javascript": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", + "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "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 + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "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" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "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" + } + }, + "tslib": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", + "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } + } + }, + "tunnel": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", + "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=", + "dev": true + }, + "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.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typed-rest-client": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz", + "integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==", + "dev": true, + "requires": { + "tunnel": "0.0.4", + "underscore": "1.8.3" + } + }, + "typescript": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", + "dev": true + }, + "typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", + "dev": true, + "requires": { + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" + } + }, + "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.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-join": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", + "integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "vsce": { + "version": "1.75.0", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.75.0.tgz", + "integrity": "sha512-qyAQTmolxKWc9bV1z0yBTSH4WEIWhDueBJMKB0GUFD6lM4MiaU1zJ9BtzekUORZu094YeNSKz0RmVVuxfqPq0g==", + "dev": true, + "requires": { + "azure-devops-node-api": "^7.2.0", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.1", + "commander": "^2.8.1", + "denodeify": "^1.2.1", + "glob": "^7.0.6", + "leven": "^3.1.0", + "lodash": "^4.17.15", + "markdown-it": "^10.0.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "osenv": "^0.1.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "0.0.29", + "typed-rest-client": "1.2.0", + "url-join": "^1.1.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tmp": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "vscode-jsonrpc": { + "version": "5.1.0-next.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.1.0-next.1.tgz", + "integrity": "sha512-mwLDojZkbmpizSJSmp690oa9FB9jig18SIDGZeBCvFc2/LYSRvMm/WwWtMBJuJ1MfFh7rZXfQige4Uje5Z9NzA==" + }, + "vscode-languageclient": { + "version": "7.0.0-next.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0-next.1.tgz", + "integrity": "sha512-JrjCUhLpQZxQ5VpWpilOHDMhVsn0fdN5jBh1uFNhSr5c2loJvRdr9Km2EuSQOFfOQsBKx0+xvY8PbsypNEcJ6w==", + "requires": { + "semver": "^6.3.0", + "vscode-languageserver-protocol": "3.16.0-next.2" + } + }, + "vscode-languageserver-protocol": { + "version": "3.16.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0-next.2.tgz", + "integrity": "sha512-atmkGT/W6tF0cx4SaWFYtFs2UeSeC28RPiap9myv2YZTaTCFvTBEPNWrU5QRKfkyM0tbgtGo6T3UCQ8tkDpjzA==", + "requires": { + "vscode-jsonrpc": "5.1.0-next.1", + "vscode-languageserver-types": "3.16.0-next.1" + } + }, + "vscode-languageserver-types": { + "version": "3.16.0-next.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.1.tgz", + "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg==" + }, + "vscode-test": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz", + "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==", + "dev": true, + "requires": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.4", + "rimraf": "^2.6.3" + } + }, + "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" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.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 + }, + "workerpool": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", + "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "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/rust-analyzer/editors/code/package.json b/rust-analyzer/editors/code/package.json new file mode 100644 index 00000000..aac4ba94 --- /dev/null +++ b/rust-analyzer/editors/code/package.json @@ -0,0 +1,888 @@ +{ + "name": "rust-analyzer", + "displayName": "rust-analyzer", + "description": "An alternative rust language server to the RLS", + "preview": true, + "private": true, + "icon": "icon.png", + "version": "0.4.0-dev", + "releaseTag": null, + "publisher": "matklad", + "repository": { + "url": "https://github.com/rust-analyzer/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.44.1" + }, + "enableProposedApi": true, + "scripts": { + "vscode:prepublish": "tsc && rollup -c", + "package": "vsce package -o rust-analyzer.vsix", + "build": "tsc", + "watch": "tsc --watch", + "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests", + "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", + "pretest": "npm run build", + "test": "node ./out/tests/runTests.js" + }, + "dependencies": { + "node-fetch": "^2.6.0", + "vscode-languageclient": "7.0.0-next.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^13.0.0", + "@rollup/plugin-node-resolve": "^8.1.0", + "@types/glob": "^7.1.2", + "@types/mocha": "^7.0.2", + "@types/node": "~12.7.0", + "@types/node-fetch": "^2.5.7", + "@types/vscode": "^1.44.1", + "@typescript-eslint/eslint-plugin": "^3.4.0", + "@typescript-eslint/parser": "^3.4.0", + "eslint": "^7.3.1", + "glob": "^7.1.6", + "mocha": "^8.0.1", + "rollup": "^2.18.1", + "tslib": "^2.0.0", + "typescript": "^3.9.5", + "typescript-formatter": "^7.2.2", + "vsce": "^1.75.0", + "vscode-test": "^1.4.0" + }, + "activationEvents": [ + "onLanguage:rust", + "onCommand:rust-analyzer.analyzerStatus", + "onCommand:rust-analyzer.memoryUsage", + "onCommand:rust-analyzer.reloadWorkspace", + "workspaceContains:**/Cargo.toml" + ], + "main": "./out/src/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.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.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.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" + } + ], + "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.diagnostics.enable": { + "type": "boolean", + "default": true, + "markdownDescription": "Whether to show native rust-analyzer diagnostics." + }, + "rust-analyzer.lruCapacity": { + "type": [ + "null", + "integer" + ], + "default": null, + "minimum": 0, + "exclusiveMinimum": true, + "description": "Number of syntax trees rust-analyzer keeps in memory." + }, + "rust-analyzer.files.watcher": { + "type": "string", + "enum": [ + "client", + "notify" + ], + "default": "client", + "description": "Controls file watching implementation." + }, + "rust-analyzer.files.exclude": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Paths to exclude from analysis." + }, + "rust-analyzer.notifications.cargoTomlNotFound": { + "type": "boolean", + "default": true, + "markdownDescription": "Whether to show `can't find Cargo.toml` error message" + }, + "rust-analyzer.cargo.autoreload": { + "type": "boolean", + "default": true, + "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes" + }, + "rust-analyzer.cargo.noDefaultFeatures": { + "type": "boolean", + "default": false, + "markdownDescription": "Do not activate the `default` feature" + }, + "rust-analyzer.cargo.allFeatures": { + "type": "boolean", + "default": false, + "description": "Activate all available features" + }, + "rust-analyzer.cargo.features": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "List of features to activate" + }, + "rust-analyzer.cargo.loadOutDirsFromCheck": { + "type": "boolean", + "default": false, + "markdownDescription": "Run `cargo check` on startup to get the correct value for package OUT_DIRs" + }, + "rust-analyzer.cargo.target": { + "type": [ + "null", + "string" + ], + "default": null, + "description": "Specify the compilation target" + }, + "rust-analyzer.rustfmt.extraArgs": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Additional arguments to rustfmt" + }, + "rust-analyzer.rustfmt.overrideCommand": { + "type": [ + "null", + "array" + ], + "items": { + "type": "string", + "minItems": 1 + }, + "default": null, + "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for formatting." + }, + "rust-analyzer.checkOnSave.enable": { + "type": "boolean", + "default": true, + "markdownDescription": "Run specified `cargo check` command for diagnostics on save" + }, + "rust-analyzer.checkOnSave.extraArgs": { + "type": "array", + "items": { + "type": "string" + }, + "markdownDescription": "Extra arguments for `cargo check`", + "default": [] + }, + "rust-analyzer.checkOnSave.command": { + "type": "string", + "default": "check", + "markdownDescription": "Cargo command to use for `cargo check`" + }, + "rust-analyzer.checkOnSave.overrideCommand": { + "type": [ + "null", + "array" + ], + "items": { + "type": "string", + "minItems": 1 + }, + "default": null, + "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option." + }, + "rust-analyzer.checkOnSave.allTargets": { + "type": "boolean", + "default": true, + "markdownDescription": "Check all targets and tests (will be passed as `--all-targets`)" + }, + "rust-analyzer.checkOnSave.allFeatures": { + "type": [ + "null", + "boolean" + ], + "default": null, + "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`." + }, + "rust-analyzer.checkOnSave.features": { + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + }, + "default": null, + "description": "List of features to activate. Defaults to `rust-analyzer.cargo.features`." + }, + "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, + "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command." + }, + "rust-analyzer.inlayHints.enable": { + "type": "boolean", + "default": true, + "description": "Whether to show inlay hints" + }, + "rust-analyzer.inlayHints.typeHints": { + "type": "boolean", + "default": true, + "description": "Whether to show inlay type hints for variables." + }, + "rust-analyzer.inlayHints.chainingHints": { + "type": "boolean", + "default": true, + "description": "Whether to show inlay type hints for method chains." + }, + "rust-analyzer.inlayHints.parameterHints": { + "type": "boolean", + "default": true, + "description": "Whether to show function parameter name inlay hints at the call site." + }, + "rust-analyzer.inlayHints.maxLength": { + "type": [ + "null", + "integer" + ], + "default": 20, + "minimum": 0, + "exclusiveMinimum": true, + "description": "Maximum length for inlay hints" + }, + "rust-analyzer.completion.addCallParenthesis": { + "type": "boolean", + "default": true, + "description": "Whether to add parenthesis when completing functions" + }, + "rust-analyzer.completion.addCallArgumentSnippets": { + "type": "boolean", + "default": true, + "description": "Whether to add argument snippets when completing functions" + }, + "rust-analyzer.completion.postfix.enable": { + "type": "boolean", + "default": true, + "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." + }, + "rust-analyzer.callInfo.full": { + "type": "boolean", + "default": true, + "description": "Show function name and docs in parameter hints" + }, + "rust-analyzer.updates.channel": { + "type": "string", + "enum": [ + "stable", + "nightly" + ], + "default": "stable", + "markdownEnumDescriptions": [ + "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general", + "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**" + ], + "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs" + }, + "rust-analyzer.updates.askBeforeDownload": { + "type": "boolean", + "default": true, + "description": "Whether to ask for permission before downloading any files from the Internet" + }, + "rust-analyzer.serverPath": { + "type": [ + "null", + "string" + ], + "default": null, + "description": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used" + }, + "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.procMacro.enable": { + "description": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.", + "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", + "description": "Optional source file mappings passed to the debug engine.", + "default": { + "/rustc/": "${env:USERPROFILE}/.rustup/toolchains//lib/rustlib/src/rust" + } + }, + "rust-analyzer.debug.openDebugPane": { + "description": "Whether to open up the Debug Pane on debugging start.", + "type": "boolean", + "default": false + }, + "rust-analyzer.debug.engineSettings": { + "type": "object", + "default": {}, + "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" + }, + "rust-analyzer.lens.enable": { + "description": "Whether to show CodeLens in Rust files.", + "type": "boolean", + "default": true + }, + "rust-analyzer.lens.run": { + "markdownDescription": "Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.lens.debug": { + "markdownDescription": "Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.lens.implementations": { + "markdownDescription": "Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.hoverActions.enable": { + "description": "Whether to show HoverActions in Rust files.", + "type": "boolean", + "default": true + }, + "rust-analyzer.hoverActions.implementations": { + "markdownDescription": "Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.hoverActions.run": { + "markdownDescription": "Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.hoverActions.debug": { + "markdownDescription": "Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.hoverActions.gotoTypeDef": { + "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", + "type": "boolean", + "default": true + }, + "rust-analyzer.linkedProjects": { + "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format", + "type": "array", + "items": { + "type": [ + "string", + "object" + ] + }, + "default": null + }, + "rust-analyzer.withSysroot": { + "markdownDescription": "Internal config for debugging, disables loading of sysroot crates", + "type": "boolean", + "default": true + }, + "rust-analyzer.diagnostics.warningsAsInfo": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", + "default": [] + }, + "rust-analyzer.diagnostics.warningsAsHint": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "description": "List of warnings warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", + "default": [] + } + } + }, + "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" + ] + } + ], + "grammars": [ + { + "language": "rust", + "scopeName": "source.rust", + "path": "rust.tmGrammar.json" + }, + { + "language": "ra_syntax_tree", + "scopeName": "source.ra_syntax_tree", + "path": "ra_syntax_tree.tmGrammar.json" + } + ], + "problemMatchers": [ + { + "name": "rustc", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": "$rustc" + }, + { + "name": "rustc-json", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "pattern": "$rustc-json" + }, + { + "name": "rustc-watch", + "fileLocation": [ + "relative", + "${workspaceRoot}" + ], + "background": { + "beginsPattern": "^\\[Running\\b", + "endsPattern": "^\\[Finished running\\b" + }, + "pattern": "$rustc" + } + ], + "colors": [ + { + "id": "rust_analyzer.inlayHint", + "description": "Color for inlay hints", + "defaults": { + "dark": "#A0A0A0F0", + "light": "#747474", + "highContrast": "#BEBEBE" + } + }, + { + "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": "attribute", + "description": "Style for attributes" + }, + { + "id": "boolean", + "description": "Style for boolean literals", + "superType": "keyword" + }, + { + "id": "builtinType", + "description": "Style for builtin types", + "superType": "type" + }, + { + "id": "lifetime", + "description": "Style for lifetimes" + }, + { + "id": "selfKeyword", + "description": "Style for the self keyword", + "superType": "keyword" + }, + { + "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" + }, + { + "id": "formatSpecifier", + "description": "Style for {} placeholders in format strings" + } + ], + "semanticTokenModifiers": [ + { + "id": "attribute", + "description": "Style for elements within attributes" + }, + { + "id": "constant", + "description": "Style for compile-time constants" + }, + { + "id": "controlFlow", + "description": "Style for control flow keywords" + }, + { + "id": "mutable", + "description": "Style for mutable bindings" + }, + { + "id": "unsafe", + "description": "Style for unsafe operations" + } + ], + "semanticTokenScopes": [ + { + "language": "rust", + "scopes": { + "macro": [ + "entity.name.function.macro.rust" + ], + "attribute": [ + "meta.attribute.rust" + ], + "function.attribute": [ + "entity.name.function.attribute.rust" + ], + "boolean": [ + "constant.language.boolean.rust" + ], + "builtinType": [ + "support.type.primitive.rust" + ], + "lifetime": [ + "storage.modifier.lifetime.rust" + ], + "typeAlias": [ + "entity.name.type.typeAlias.rust" + ], + "union": [ + "entity.name.type.union.rust" + ], + "struct": [ + "entity.name.type.struct.rust" + ], + "keyword": [ + "keyword.other.rust" + ], + "keyword.controlFlow": [ + "keyword.control.rust" + ], + "variable.constant": [ + "variable.other.constant.rust" + ], + "formatSpecifier": [ + "punctuation.section.embedded.rust" + ], + "*.mutable": [ + "markup.underline" + ] + } + } + ], + "menus": { + "commandPalette": [ + { + "command": "rust-analyzer.syntaxTree", + "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" + } + ] + } + } +} diff --git a/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json b/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json new file mode 100644 index 00000000..431d414f --- /dev/null +++ b/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json @@ -0,0 +1,31 @@ +{ + "$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/rust-analyzer/editors/code/rollup.config.js b/rust-analyzer/editors/code/rollup.config.js new file mode 100644 index 00000000..27abf75a --- /dev/null +++ b/rust-analyzer/editors/code/rollup.config.js @@ -0,0 +1,21 @@ +// @ts-check + +import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import nodeBuiltins from 'builtin-modules'; + +/** @type { import('rollup').RollupOptions } */ +export default { + input: 'out/src/main.js', + plugins: [ + resolve({ + preferBuiltins: true + }), + commonjs() + ], + external: [...nodeBuiltins, 'vscode'], + output: { + file: './out/src/main.js', + format: 'cjs' + } +}; diff --git a/rust-analyzer/editors/code/rust.tmGrammar.json b/rust-analyzer/editors/code/rust.tmGrammar.json new file mode 100644 index 00000000..0be2583d --- /dev/null +++ b/rust-analyzer/editors/code/rust.tmGrammar.json @@ -0,0 +1,686 @@ +{ + "name": "Rust", + "scopeName": "source.rust", + "patterns": [ + { + "comment": "Implementation", + "begin": "\\b(impl)\\b", + "end": "\\{", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#dyn" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#where" + }, + { + "name": "storage.type.rust", + "match": "\\bfor\\b" + }, + { + "include": "#type" + } + ] + }, + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_doc_comment" + }, + { + "include": "#line_comment" + }, + { + "comment": "Attribute", + "name": "meta.attribute.rust", + "begin": "#\\!?\\[(\\w*)", + "end": "\\]", + "captures": { + "1": { + "name": "entity.name.function.attribute.rust" + } + }, + "patterns": [ + { + "include": "#string_literal" + }, + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_doc_comment" + }, + { + "include": "#line_comment" + } + ] + }, + { + "comment": "Single-quote string literal (character)", + "name": "string.quoted.single.rust", + "match": "b?'([^'\\\\]|\\\\(x[0-9A-Fa-f]{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.))'" + }, + { + "include": "#string_literal" + }, + { + "include": "#raw_string_literal" + }, + { + "comment": "Floating point literal (fraction)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*\\.[0-9][0-9_]*([eE][+-]?[0-9_]+)?(f32|f64)?\\b" + }, + { + "comment": "Floating point literal (exponent)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*(\\.[0-9][0-9_]*)?[eE][+-]?[0-9_]+(f32|f64)?\\b" + }, + { + "comment": "Floating point literal (typed)", + "name": "constant.numeric.float.rust", + "match": "\\b[0-9][0-9_]*(\\.[0-9][0-9_]*)?([eE][+-]?[0-9_]+)?(f32|f64)\\b" + }, + { + "comment": "Integer literal (decimal)", + "name": "constant.numeric.integer.decimal.rust", + "match": "\\b[0-9][0-9_]*([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (hexadecimal)", + "name": "constant.numeric.integer.hexadecimal.rust", + "match": "\\b0x[a-fA-F0-9_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (octal)", + "name": "constant.numeric.integer.octal.rust", + "match": "\\b0o[0-7_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Integer literal (binary)", + "name": "constant.numeric.integer.binary.rust", + "match": "\\b0b[01_]+([ui](8|16|32|64|128|s|size))?\\b" + }, + { + "comment": "Static storage modifier", + "name": "storage.modifier.static.rust", + "match": "\\bstatic\\b" + }, + { + "comment": "Boolean constant", + "name": "constant.language.boolean.rust", + "match": "\\b(true|false)\\b" + }, + { + "comment": "Control keyword", + "name": "keyword.control.rust", + "match": "\\b(async|await|break|continue|else|if|in|for|loop|match|return|try|while)\\b" + }, + { + "comment": "Keyword", + "name": "keyword.other.rust", + "match": "\\b(crate|extern|mod|let|ref|use|super|move|as)\\b" + }, + { + "comment": "Reserved keyword", + "name": "invalid.deprecated.rust", + "match": "\\b(abstract|alignof|become|do|final|macro|offsetof|override|priv|proc|pure|sizeof|typeof|virtual|yield)\\b" + }, + { + "include": "#unsafe" + }, + { + "include": "#sigils" + }, + { + "include": "#self" + }, + { + "include": "#mut" + }, + { + "include": "#dyn" + }, + { + "include": "#impl" + }, + { + "include": "#box" + }, + { + "include": "#lifetime" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#const" + }, + { + "include": "#pub" + }, + { + "comment": "Miscellaneous operator", + "name": "keyword.operator.misc.rust", + "match": "(=>|::|\\?)" + }, + { + "comment": "Comparison operator", + "name": "keyword.operator.comparison.rust", + "match": "(&&|\\|\\||==|!=)" + }, + { + "comment": "Assignment operator", + "name": "keyword.operator.assignment.rust", + "match": "(\\+=|-=|/=|\\*=|%=|\\^=|&=|\\|=|<<=|>>=|=)" + }, + { + "comment": "Arithmetic operator", + "name": "keyword.operator.arithmetic.rust", + "match": "(!|\\+|-|/|\\*|%|\\^|&|\\||<<|>>)" + }, + { + "comment": "Comparison operator (second group because of regex precedence)", + "name": "keyword.operator.comparison.rust", + "match": "(<=|>=|<|>)" + }, + { + "include": "#core_types" + }, + { + "include": "#core_vars" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "comment": "Built-in macro", + "name": "support.function.builtin.rust", + "match": "\\b(macro_rules|compile_error|format_args|env|option_env|concat_idents|concat|line|column|file|stringify|include|include_str|include_bytes|module_path|cfg)!" + }, + { + "comment": "Core macro", + "name": "support.function.core.rust", + "match": "\\b(panic|assert|assert_eq|assert_ne|debug_assert|debug_assert_eq|debug_assert_ne|try|write|writeln|unreachable|unimplemented)!" + }, + { + "comment": "Standard library macro", + "name": "support.function.std.rust", + "match": "\\b(format|print|println|eprint|eprintln|select|vec)!" + }, + { + "comment": "Logging macro", + "name": "support.function.log.rust", + "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!" + }, + { + "comment": "Invocation of a macro", + "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]", + "captures": { + "1": { + "name": "entity.name.function.macro.rust" + } + } + }, + { + "comment": "Function call", + "match": "\\b([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)\\s*\\(", + "captures": { + "1": { + "name": "entity.name.function.rust" + } + } + }, + { + "comment": "Function call with type parameters", + "begin": "\\b([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)\\s*(::)(?=\\s*<.*>\\s*\\()", + "end": "\\(", + "captures": { + "1": { + "name": "entity.name.function.rust" + }, + "2": { + "name": "keyword.operator.misc.rust" + } + }, + "patterns": [ + { + "include": "#type_params" + } + ] + }, + { + "comment": "Function definition", + "begin": "\\b(fn)\\s+([A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+)", + "end": "[\\{;]", + "beginCaptures": { + "1": { + "name": "keyword.other.fn.rust" + }, + "2": { + "name": "entity.name.function.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#self" + }, + { + "include": "#mut" + }, + { + "include": "#dyn" + }, + { + "include": "#impl" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#const" + }, + { + "include": "#where" + }, + { + "include": "#unsafe" + }, + { + "comment": "Function arguments", + "match": "\bfn\b", + "name": "keyword.other.fn.rust" + } + ] + }, + { + "comment": "Type declaration", + "begin": "\\b(enum|struct|trait|union)\\s+([a-zA-Z_][a-zA-Z0-9_]*)", + "end": "[\\{\\(;]", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + }, + "2": { + "name": "entity.name.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + }, + { + "include": "#core_types" + }, + { + "include": "#pub" + }, + { + "include": "#where" + } + ] + }, + { + "comment": "Type alias", + "begin": "\\b(type)\\s+([a-zA-Z_][a-zA-Z0-9_]*)", + "end": ";", + "beginCaptures": { + "1": { + "name": "storage.type.rust" + }, + "2": { + "name": "entity.name.type.rust" + } + }, + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#dyn" + }, + { + "include": "#impl" + }, + { + "include": "#lifetime" + }, + { + "include": "#ref_lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + } + ] + } + ], + "repository": { + "block_doc_comment": { + "comment": "Block documentation comment", + "name": "comment.block.documentation.rust", + "begin": "/\\*[\\*!](?![\\*/])", + "end": "\\*/", + "patterns": [ + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + } + ] + }, + "block_comment": { + "comment": "Block comment", + "name": "comment.block.rust", + "begin": "/\\*", + "end": "\\*/", + "patterns": [ + { + "include": "#block_doc_comment" + }, + { + "include": "#block_comment" + } + ] + }, + "line_doc_comment": { + "comment": "Single-line documentation comment", + "name": "comment.line.documentation.rust", + "begin": "//[!/](?=[^/])", + "end": "$" + }, + "line_comment": { + "comment": "Single-line comment", + "name": "comment.line.double-slash.rust", + "begin": "//", + "end": "$" + }, + "escaped_character": { + "name": "constant.character.escape.rust", + "match": "\\\\(x[0-9A-Fa-f]{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)" + }, + "string_literal": { + "comment": "Double-quote string literal", + "name": "string.quoted.double.rust", + "begin": "b?\"", + "end": "\"", + "patterns": [ + { + "include": "#escaped_character" + } + ] + }, + "raw_string_literal": { + "comment": "Raw double-quote string literal", + "name": "string.quoted.double.raw.rust", + "begin": "b?r(#*)\"", + "end": "\"\\1" + }, + "sigils": { + "comment": "Sigil", + "name": "keyword.operator.sigil.rust", + "match": "[&*](?=[a-zA-Z0-9_\\(\\[\\|\\\"]+)" + }, + "self": { + "comment": "Self variable", + "name": "variable.language.rust", + "match": "\\bself\\b" + }, + "mut": { + "comment": "Mutable storage modifier", + "name": "storage.modifier.mut.rust", + "match": "\\bmut\\b" + }, + "dyn": { + "comment": "Dynamic modifier", + "name": "storage.modifier.dyn.rust", + "match": "\\bdyn\\b" + }, + "impl": { + "comment": "Existential type modifier", + "name": "storage.modifier.impl.rust", + "match": "\\bimpl\\b" + }, + "box": { + "comment": "Box storage modifier", + "name": "storage.modifier.box.rust", + "match": "\\bbox\\b" + }, + "const": { + "comment": "Const storage modifier", + "name": "storage.modifier.const.rust", + "match": "\\bconst\\b" + }, + "pub": { + "comment": "Visibility modifier", + "name": "storage.modifier.visibility.rust", + "match": "\\bpub\\b" + }, + "unsafe": { + "comment": "Unsafe code keyword", + "name": "keyword.other.unsafe.rust", + "match": "\\bunsafe\\b" + }, + "where": { + "comment": "Generic where clause", + "name": "keyword.other.where.rust", + "match": "\\bwhere\\b" + }, + "lifetime": { + "comment": "Named lifetime", + "name": "storage.modifier.lifetime.rust", + "match": "'([a-zA-Z_][a-zA-Z0-9_]*)\\b" + }, + "ref_lifetime": { + "comment": "Reference with named lifetime", + "match": "(&)('[a-zA-Z_][a-zA-Z0-9_]*)\\b", + "captures": { + "1": { + "name": "keyword.operator.sigil.rust" + }, + "2": { + "name": "storage.modifier.lifetime.rust" + } + } + }, + "core_types": { + "comment": "Built-in/core type", + "name": "support.type.primitive.rust", + "match": "\\b(bool|char|usize|isize|u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f32|f64|str|Self)\\b" + }, + "core_vars": { + "comment": "Core type variant", + "name": "support.constant.core.rust", + "match": "\\b(Some|None|Ok|Err)\\b" + }, + "core_marker": { + "comment": "Core trait (marker)", + "name": "entity.name.type.marker.rust", + "match": "\\b(Copy|Send|Sized|Sync)\\b" + }, + "core_traits": { + "comment": "Core trait", + "name": "entity.name.type.core.rust", + "match": "\\b(Drop|Fn|FnMut|FnOnce|Clone|PartialEq|PartialOrd|Eq|Ord|AsRef|AsMut|Into|From|Default|Iterator|Extend|IntoIterator|DoubleEndedIterator|ExactSizeIterator)\\b" + }, + "std_types": { + "comment": "Standard library type", + "name": "entity.name.type.class.std.rust", + "match": "\\b(Box|String|Vec|Path|PathBuf|Option|Result)\\b" + }, + "std_traits": { + "comment": "Standard library trait", + "name": "entity.name.type.std.rust", + "match": "\\b(ToOwned|ToString)\\b" + }, + "type": { + "comment": "A type", + "name": "entity.name.type.rust", + "match": "\\b([A-Za-z][_A-Za-z0-9]*|_[_A-Za-z0-9]+)\\b" + }, + "type_params": { + "comment": "Type parameters", + "name": "meta.type_params.rust", + "begin": "<(?![=<])", + "end": "(?", + "patterns": [ + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#sigils" + }, + { + "include": "#mut" + }, + { + "include": "#dyn" + }, + { + "include": "#impl" + }, + { + "include": "#lifetime" + }, + { + "include": "#core_types" + }, + { + "include": "#core_marker" + }, + { + "include": "#core_traits" + }, + { + "include": "#std_types" + }, + { + "include": "#std_traits" + }, + { + "include": "#type_params" + } + ] + } + } +} diff --git a/rust-analyzer/editors/code/src/ast_inspector.ts b/rust-analyzer/editors/code/src/ast_inspector.ts new file mode 100644 index 00000000..4fdd167b --- /dev/null +++ b/rust-analyzer/editors/code/src/ast_inspector.ts @@ -0,0 +1,185 @@ +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: 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 { + 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 { + 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 { + val: undefined | T; + + constructor(private readonly compute: () => undefined | T) { } + + get() { + return this.val ?? (this.val = this.compute()); + } + + reset() { + this.val = undefined; + } +} diff --git a/rust-analyzer/editors/code/src/client.ts b/rust-analyzer/editors/code/src/client.ts new file mode 100644 index 00000000..41ffac7b --- /dev/null +++ b/rust-analyzer/editors/code/src/client.ts @@ -0,0 +1,179 @@ +import * as lc from 'vscode-languageclient'; +import * as vscode from 'vscode'; +import * as ra from '../src/lsp_ext'; +import * as Is from 'vscode-languageclient/lib/utils/is'; + +import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; +import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; +import { assert } from './util'; + +function renderCommand(cmd: ra.CommandLink) { + return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${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 function createClient(serverPath: string, cwd: string): 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 run: lc.Executable = { + command: serverPath, + options: { cwd }, + }; + const serverOptions: lc.ServerOptions = { + run, + debug: run, + }; + const traceOutputChannel = vscode.window.createOutputChannel( + 'Rust Analyzer Language Server Trace', + ); + + const clientOptions: lc.LanguageClientOptions = { + documentSelector: [{ scheme: 'file', language: 'rust' }], + initializationOptions: vscode.workspace.getConfiguration("rust-analyzer"), + traceOutputChannel, + middleware: { + // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 + async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken, next: DocumentSemanticsTokensSignature) { + const res = await next(document, token); + if (res === undefined) throw new Error('busy'); + return res; + }, + async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) { + return client.sendRequest(lc.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then( + (result) => { + const hover = client.protocol2CodeConverter.asHover(result); + if (hover) { + const actions = (result).actions; + if (actions) { + hover.contents.push(renderHoverActions(actions)); + } + } + return hover; + }, + (error) => { + client.logFailedRequest(lc.HoverRequest.type, error); + return Promise.resolve(null); + }); + }, + // Using custom handling of CodeActions where each code action is resolved lazily + // That's why we are not waiting for any command or edits + 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: client.code2ProtocolConverter.asCodeActionContext(context) + }; + return client.sendRequest(lc.CodeActionRequest.type, params, token).then((values) => { + if (values === null) return undefined; + const result: (vscode.CodeAction | vscode.Command)[] = []; + const groups = new Map(); + 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 = client.protocol2CodeConverter.asCodeAction(item); + 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; + const id = (item as any).id; + const resolveParams: ra.ResolveCodeActionParams = { + id: id, + codeActionParams: params + }; + action.command = { + command: "rust-analyzer.resolveCodeAction", + title: item.title, + arguments: [resolveParams], + }; + 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] }; + })], + }; + result[index] = action; + } + } + return result; + }, + (_error) => undefined + ); + } + + } as any + }; + + const client = new lc.LanguageClient( + 'rust-analyzer', + 'Rust Analyzer Language Server', + serverOptions, + clientOptions, + ); + + // To turn on all proposed features use: client.registerProposedFeatures(); + // Here we want to enable CallHierarchyFeature and SemanticTokensFeature + // since they are available on stable. + // Note that while these features are stable in vscode their LSP protocol + // implementations are still in the "proposed" category for 3.16. + client.registerFeature(new CallHierarchyFeature(client)); + client.registerFeature(new SemanticTokensFeature(client)); + 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.resolveCodeAction = true; + caps.hoverActions = true; + caps.statusNotification = true; + capabilities.experimental = caps; + } + initialize(_capabilities: lc.ServerCapabilities, _documentSelector: lc.DocumentSelector | undefined): 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/rust-analyzer/editors/code/src/commands.ts b/rust-analyzer/editors/code/src/commands.ts new file mode 100644 index 00000000..1f3a7cf7 --- /dev/null +++ b/rust-analyzer/editors/code/src/commands.ts @@ -0,0 +1,483 @@ +import * as vscode from 'vscode'; +import * as lc from 'vscode-languageclient'; +import * as ra from './lsp_ext'; + +import { Ctx, Cmd } from './ctx'; +import { applySnippetWorkspaceEdit, applySnippetTextEdits } from './snippets'; +import { spawnSync } from 'child_process'; +import { RunnableQuickPick, selectRunnable, createTask } from './run'; +import { AstInspector } from './ast_inspector'; +import { isRustDocument, sleep, isRustEditor } from './util'; +import { startDebugSession, makeDebugConfig } from './debug'; + +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(); + + provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { + if (!vscode.window.activeTextEditor) return ''; + + return ctx.client.sendRequest(ra.analyzerStatus, null); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } + }(); + + let poller: NodeJS.Timer | undefined = undefined; + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider( + 'rust-analyzer-status', + tdcp, + ), + ); + + ctx.pushCleanup({ + dispose() { + if (poller !== undefined) { + clearInterval(poller); + } + }, + }); + + return async () => { + if (poller === undefined) { + poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); + } + const document = await vscode.workspace.openTextDocument(tdcp.uri); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, 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(); + + provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { + if (!vscode.window.activeTextEditor) return ''; + + return ctx.client.sendRequest(ra.memoryUsage, null).then((mem) => { + return 'Per-query memory usage:\n' + mem + '\n(note: database has been cleared)'; + }); + } + + get onDidChange(): vscode.Event { + 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 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: { uri: editor.document.uri.toString() }, + 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: { uri: editor.document.uri.toString() }, + }); + editor.edit((builder) => { + client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => { + builder.replace(edit.range, edit.newText); + }); + }); + }; +} + +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: { uri: editor.document.uri.toString() }, + position: client.code2ProtocolConverter.asPosition( + editor.selection.active, + ), + }).catch(_error => { + // client.logFailedRequest(OnEnterRequest.type, error); + return null; + }); + if (!lcEdits) return false; + + const edits = 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 = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const response = await client.sendRequest(ra.parentModule, { + textDocument: { uri: editor.document.uri.toString() }, + position: client.code2ProtocolConverter.asPosition( + editor.selection.active, + ), + }); + const loc = response[0]; + if (!loc) return; + + 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); + }; +} + +export function ssr(ctx: Ctx): Cmd { + return async () => { + const client = ctx.client; + if (!client) return; + + 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 }); + } catch (e) { + return e.toString(); + } + return null; + } + }; + const request = await vscode.window.showInputBox(options); + if (!request) return; + + 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 }); + + await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit)); + }); + }; +} + +export function serverVersion(ctx: Ctx): Cmd { + return async () => { + const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); + const commitHash = stdout.slice(`rust-analyzer `.length).trim(); + const { releaseTag } = ctx.config.package; + + void vscode.window.showInformationMessage( + `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})` + ); + }; +} + +export function toggleInlayHints(ctx: Ctx): Cmd { + return async () => { + await vscode + .workspace + .getConfiguration(`${ctx.config.rootSection}.inlayHints`) + .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace); + }; +} + +// 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://syntaxtree/tree.rast'); + readonly eventEmitter = new vscode.EventEmitter(); + 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 { + 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 { + return this.eventEmitter.event; + } + }; + + void new AstInspector(ctx); + + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', 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 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://expandMacro/[EXPANSION].rs'); + eventEmitter = new vscode.EventEmitter(); + async provideTextDocumentContent(_uri: vscode.Uri): Promise { + 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: { uri: editor.document.uri.toString() }, + position, + }); + + if (expanded == null) return 'Not available'; + + return codeFormat(expanded); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } + }(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider( + 'rust-analyzer', + 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, null); +} + +export function showReferences(ctx: Ctx): Cmd { + return (uri: string, position: lc.Position, locations: lc.Location[]) => { + const client = ctx.client; + if (client) { + vscode.commands.executeCommand( + 'editor.action.showReferences', + vscode.Uri.parse(uri), + client.protocol2CodeConverter.asPosition(position), + locations.map(client.protocol2CodeConverter.asLocation), + ); + } + }; +} + +export function applyActionGroup(_ctx: Ctx): Cmd { + return async (actions: { label: string; arguments: ra.ResolveCodeActionParams }[]) => { + const selectedAction = await vscode.window.showQuickPick(actions); + if (!selectedAction) return; + 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 resolveCodeAction(ctx: Ctx): Cmd { + const client = ctx.client; + return async (params: ra.ResolveCodeActionParams) => { + const item: lc.WorkspaceEdit = await client.sendRequest(ra.resolveCodeAction, params); + if (!item) { + return; + } + const edit = client.protocol2CodeConverter.asWorkspaceEdit(item); + await applySnippetWorkspaceEdit(edit); + }; +} + +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 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 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); + }; +} diff --git a/rust-analyzer/editors/code/src/config.ts b/rust-analyzer/editors/code/src/config.ts new file mode 100644 index 00000000..033b04b6 --- /dev/null +++ b/rust-analyzer/editors/code/src/config.ts @@ -0,0 +1,153 @@ +import * as vscode from 'vscode'; +import { log } from "./util"; + +export type UpdatesChannel = "stable" | "nightly"; + +export const NIGHTLY_TAG = "nightly"; + +export type RunnableEnvCfg = undefined | Record | { mask?: string; env: Record }[]; + +export class Config { + readonly extensionId = "matklad.rust-analyzer"; + + readonly rootSection = "rust-analyzer"; + private readonly requiresReloadOpts = [ + "serverPath", + "cargo", + "procMacro", + "files", + "highlighting", + "updates.channel", + "lens", // works as lens.* + "hoverActions", // works as hoverActions.* + ] + .map(opt => `${this.rootSection}.${opt}`); + + readonly package: { + version: string; + releaseTag: string | null; + enableProposedApi: boolean | undefined; + } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; + + readonly globalStoragePath: string; + + constructor(ctx: vscode.ExtensionContext) { + this.globalStoragePath = ctx.globalStoragePath; + 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 userResponse = await vscode.window.showInformationMessage( + `Changing "${requiresReloadOpt}" requires a reload`, + "Reload now" + ); + + if (userResponse === "Reload now") { + await vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + } + + // 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-analyer") + * .get(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(path: string): T { + return this.cfg.get(path)!; + } + + get serverPath() { return this.get("serverPath"); } + get channel() { return this.get("updates.channel"); } + get askBeforeDownload() { return this.get("updates.askBeforeDownload"); } + get traceExtension() { return this.get("trace.extension"); } + + get inlayHints() { + return { + enable: this.get("inlayHints.enable"), + typeHints: this.get("inlayHints.typeHints"), + parameterHints: this.get("inlayHints.parameterHints"), + chainingHints: this.get("inlayHints.chainingHints"), + maxLength: this.get("inlayHints.maxLength"), + }; + } + + get checkOnSave() { + return { + command: this.get("checkOnSave.command"), + }; + } + + get cargoRunner() { + return this.get("cargoRunner"); + } + + get runnableEnv() { + return this.get("runnableEnv"); + } + + get debug() { + // "/rustc/" used by suggestions only. + const { ["/rustc/"]: _, ...sourceFileMap } = this.get>("debug.sourceFileMap"); + + return { + engine: this.get("debug.engine"), + engineSettings: this.get("debug.engineSettings"), + openDebugPane: this.get("debug.openDebugPane"), + sourceFileMap: sourceFileMap + }; + } + + get lens() { + return { + enable: this.get("lens.enable"), + run: this.get("lens.run"), + debug: this.get("lens.debug"), + implementations: this.get("lens.implementations"), + }; + } + + get hoverActions() { + return { + enable: this.get("hoverActions.enable"), + implementations: this.get("hoverActions.implementations"), + run: this.get("hoverActions.run"), + debug: this.get("hoverActions.debug"), + gotoTypeDef: this.get("hoverActions.gotoTypeDef"), + }; + } +} diff --git a/rust-analyzer/editors/code/src/ctx.ts b/rust-analyzer/editors/code/src/ctx.ts new file mode 100644 index 00000000..6e767bab --- /dev/null +++ b/rust-analyzer/editors/code/src/ctx.ts @@ -0,0 +1,106 @@ +import * as vscode from 'vscode'; +import * as lc from 'vscode-languageclient'; +import * as ra from './lsp_ext'; + +import { Config } from './config'; +import { createClient } from './client'; +import { isRustEditor, RustEditor } from './util'; +import { Status } from './lsp_ext'; + +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, + cwd: string, + ): Promise { + const client = createClient(serverPath, cwd); + + const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + extCtx.subscriptions.push(statusBar); + statusBar.text = "rust-analyzer"; + statusBar.tooltip = "ready"; + statusBar.show(); + + const res = new Ctx(config, extCtx, client, serverPath, statusBar); + + res.pushCleanup(client.start()); + await client.onReady(); + client.onNotification(ra.status, (status) => res.setStatus(status)); + 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 globalState(): vscode.Memento { + return this.extCtx.globalState; + } + + get subscriptions(): Disposable[] { + return this.extCtx.subscriptions; + } + + setStatus(status: Status) { + switch (status) { + case "loading": + this.statusBar.text = "$(sync~spin) rust-analyzer"; + this.statusBar.tooltip = "Loading the project"; + this.statusBar.command = undefined; + this.statusBar.color = undefined; + break; + case "ready": + this.statusBar.text = "rust-analyzer"; + this.statusBar.tooltip = "Ready"; + this.statusBar.command = undefined; + this.statusBar.color = undefined; + break; + case "invalid": + this.statusBar.text = "$(error) rust-analyzer"; + this.statusBar.tooltip = "Failed to load the project"; + this.statusBar.command = undefined; + this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground"); + break; + case "needsReload": + this.statusBar.text = "$(warning) rust-analyzer"; + this.statusBar.tooltip = "Click to reload"; + this.statusBar.command = "rust-analyzer.reloadWorkspace"; + this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground"); + break; + } + } + + pushCleanup(d: Disposable) { + this.extCtx.subscriptions.push(d); + } +} + +export interface Disposable { + dispose(): void; +} +export type Cmd = (...args: any[]) => unknown; diff --git a/rust-analyzer/editors/code/src/debug.ts b/rust-analyzer/editors/code/src/debug.ts new file mode 100644 index 00000000..bd92c5b6 --- /dev/null +++ b/rust-analyzer/editors/code/src/debug.ts @@ -0,0 +1,151 @@ +import * as os from "os"; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as ra from './lsp_ext'; + +import { Cargo } 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, sourceFileMap?: Record) => vscode.DebugConfiguration; + +export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise { + 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("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 { + let debugConfig: vscode.DebugConfiguration | undefined = undefined; + let message = ""; + + const wsLaunchSection = vscode.workspace.getConfiguration("launch"); + const configurations = wsLaunchSection.get("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 { + const editor = ctx.activeRustEditor; + if (!editor) return; + + const knownEngines: Record = { + "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) { + 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); + } + + const wsFolder = path.normalize(vscode.workspace.workspaceFolders![0].uri.fsPath); // folder exists or RA is not active. + function simplifyPath(p: string): string { + return path.normalize(p).replace(wsFolder, '${workspaceRoot}'); + } + + const executable = await getDebugExecutable(runnable); + const env = prepareEnv(runnable, ctx.config.runnableEnv); + const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, debugOptions.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 { + 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, sourceFileMap?: Record): 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, sourceFileMap?: Record): 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/rust-analyzer/editors/code/src/inlay_hints.ts b/rust-analyzer/editors/code/src/inlay_hints.ts new file mode 100644 index 00000000..9e6d6045 --- /dev/null +++ b/rust-analyzer/editors/code/src/inlay_hints.ts @@ -0,0 +1,243 @@ +import * as lc from "vscode-languageclient"; +import * as vscode from 'vscode'; +import * as ra from './lsp_ext'; + +import { Ctx, Disposable } from './ctx'; +import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util'; + + +export function activateInlayHints(ctx: Ctx) { + const maybeUpdater = { + updater: null as null | HintsUpdater, + async onConfigChange() { + const anyEnabled = ctx.config.inlayHints.typeHints + || ctx.config.inlayHints.parameterHints + || ctx.config.inlayHints.chainingHints; + const enabled = ctx.config.inlayHints.enable && anyEnabled; + + if (!enabled) return this.dispose(); + + await sleep(100); + if (this.updater) { + this.updater.syncCacheAndRenderHints(); + } else { + this.updater = new HintsUpdater(ctx); + } + }, + dispose() { + this.updater?.dispose(); + this.updater = null; + } + }; + + ctx.pushCleanup(maybeUpdater); + + vscode.workspace.onDidChangeConfiguration( + maybeUpdater.onConfigChange, maybeUpdater, ctx.subscriptions + ); + + maybeUpdater.onConfigChange(); +} + + +const typeHints = { + decorationType: vscode.window.createTextEditorDecorationType({ + after: { + color: new vscode.ThemeColor('rust_analyzer.inlayHint'), + fontStyle: "normal", + } + }), + + toDecoration(hint: ra.InlayHint.TypeHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { + return { + range: conv.asRange(hint.range), + renderOptions: { after: { contentText: `: ${hint.label}` } } + }; + } +}; + +const paramHints = { + decorationType: vscode.window.createTextEditorDecorationType({ + before: { + color: new vscode.ThemeColor('rust_analyzer.inlayHint'), + fontStyle: "normal", + } + }), + + toDecoration(hint: ra.InlayHint.ParamHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { + return { + range: conv.asRange(hint.range), + renderOptions: { before: { contentText: `${hint.label}: ` } } + }; + } +}; + +const chainingHints = { + decorationType: vscode.window.createTextEditorDecorationType({ + after: { + color: new vscode.ThemeColor('rust_analyzer.inlayHint'), + fontStyle: "normal", + } + }), + + toDecoration(hint: ra.InlayHint.ChainingHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { + return { + range: conv.asRange(hint.range), + renderOptions: { after: { contentText: ` ${hint.label}` } } + }; + } +}; + +class HintsUpdater implements Disposable { + private sourceFiles = new Map(); // map Uri -> RustSourceFile + private readonly disposables: Disposable[] = []; + + constructor(private readonly ctx: Ctx) { + vscode.window.onDidChangeVisibleTextEditors( + this.onDidChangeVisibleTextEditors, + this, + this.disposables + ); + + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + this.disposables + ); + + // Set up initial cache shape + ctx.visibleRustEditors.forEach(editor => this.sourceFiles.set( + editor.document.uri.toString(), + { + document: editor.document, + inlaysRequest: null, + cachedDecorations: null + } + )); + + this.syncCacheAndRenderHints(); + } + + dispose() { + this.sourceFiles.forEach(file => file.inlaysRequest?.cancel()); + this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [], chaining: [] })); + this.disposables.forEach(d => d.dispose()); + } + + onDidChangeTextDocument({ contentChanges, document }: vscode.TextDocumentChangeEvent) { + if (contentChanges.length === 0 || !isRustDocument(document)) return; + this.syncCacheAndRenderHints(); + } + + syncCacheAndRenderHints() { + // FIXME: make inlayHints request pass an array of files? + this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { + if (!hints) return; + + file.cachedDecorations = this.hintsToDecorations(hints); + + for (const editor of this.ctx.visibleRustEditors) { + if (editor.document.uri.toString() === uri) { + this.renderDecorations(editor, file.cachedDecorations); + } + } + })); + } + + onDidChangeVisibleTextEditors() { + const newSourceFiles = new Map(); + + // Rerendering all, even up-to-date editors for simplicity + this.ctx.visibleRustEditors.forEach(async editor => { + const uri = editor.document.uri.toString(); + const file = this.sourceFiles.get(uri) ?? { + document: editor.document, + inlaysRequest: null, + cachedDecorations: null + }; + newSourceFiles.set(uri, file); + + // No text documents changed, so we may try to use the cache + if (!file.cachedDecorations) { + const hints = await this.fetchHints(file); + if (!hints) return; + + file.cachedDecorations = this.hintsToDecorations(hints); + } + + this.renderDecorations(editor, file.cachedDecorations); + }); + + // Cancel requests for no longer visible (disposed) source files + this.sourceFiles.forEach((file, uri) => { + if (!newSourceFiles.has(uri)) file.inlaysRequest?.cancel(); + }); + + this.sourceFiles = newSourceFiles; + } + + private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) { + editor.setDecorations(typeHints.decorationType, decorations.type); + editor.setDecorations(paramHints.decorationType, decorations.param); + editor.setDecorations(chainingHints.decorationType, decorations.chaining); + } + + private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations { + const decorations: InlaysDecorations = { type: [], param: [], chaining: [] }; + const conv = this.ctx.client.protocol2CodeConverter; + + for (const hint of hints) { + switch (hint.kind) { + case ra.InlayHint.Kind.TypeHint: { + decorations.type.push(typeHints.toDecoration(hint, conv)); + continue; + } + case ra.InlayHint.Kind.ParamHint: { + decorations.param.push(paramHints.toDecoration(hint, conv)); + continue; + } + case ra.InlayHint.Kind.ChainingHint: { + decorations.chaining.push(chainingHints.toDecoration(hint, conv)); + continue; + } + } + } + return decorations; + } + + private async fetchHints(file: RustSourceFile): Promise { + file.inlaysRequest?.cancel(); + + const tokenSource = new vscode.CancellationTokenSource(); + file.inlaysRequest = tokenSource; + + const request = { textDocument: { uri: file.document.uri.toString() } }; + + return sendRequestWithRetry(this.ctx.client, ra.inlayHints, request, tokenSource.token) + .catch(_ => null) + .finally(() => { + if (file.inlaysRequest === tokenSource) { + file.inlaysRequest = null; + } + }); + } +} + +interface InlaysDecorations { + type: vscode.DecorationOptions[]; + param: vscode.DecorationOptions[]; + chaining: vscode.DecorationOptions[]; +} + +interface RustSourceFile { + /** + * Source of the token to cancel in-flight inlay hints request if any. + */ + inlaysRequest: null | vscode.CancellationTokenSource; + /** + * Last applied decorations. + */ + cachedDecorations: null | InlaysDecorations; + + document: RustDocument; +} diff --git a/rust-analyzer/editors/code/src/lsp_ext.ts b/rust-analyzer/editors/code/src/lsp_ext.ts new file mode 100644 index 00000000..5f32cb40 --- /dev/null +++ b/rust-analyzer/editors/code/src/lsp_ext.ts @@ -0,0 +1,109 @@ +/** + * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. + */ + +import * as lc from "vscode-languageclient"; + +export const analyzerStatus = new lc.RequestType("rust-analyzer/analyzerStatus"); +export const memoryUsage = new lc.RequestType("rust-analyzer/memoryUsage"); + +export type Status = "loading" | "ready" | "invalid" | "needsReload"; +export const status = new lc.NotificationType("rust-analyzer/status"); + +export const reloadWorkspace = new lc.RequestType("rust-analyzer/reloadWorkspace"); + +export interface SyntaxTreeParams { + textDocument: lc.TextDocumentIdentifier; + range: lc.Range | null; +} +export const syntaxTree = new lc.RequestType("rust-analyzer/syntaxTree"); + + +export interface ExpandMacroParams { + textDocument: lc.TextDocumentIdentifier; + position: lc.Position; +} +export interface ExpandedMacro { + name: string; + expansion: string; +} +export const expandMacro = new lc.RequestType("rust-analyzer/expandMacro"); + +export interface MatchingBraceParams { + textDocument: lc.TextDocumentIdentifier; + positions: lc.Position[]; +} +export const matchingBrace = new lc.RequestType("experimental/matchingBrace"); + +export const parentModule = new lc.RequestType("experimental/parentModule"); + +export interface ResolveCodeActionParams { + id: string; + codeActionParams: lc.CodeActionParams; +} +export const resolveCodeAction = new lc.RequestType('experimental/resolveCodeAction'); + +export interface JoinLinesParams { + textDocument: lc.TextDocumentIdentifier; + ranges: lc.Range[]; +} +export const joinLines = new lc.RequestType("experimental/joinLines"); + +export const onEnter = new lc.RequestType("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[]; + executableArgs: string[]; + expectTest?: boolean; + }; +} +export const runnables = new lc.RequestType("experimental/runnables"); + +export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint; + +export namespace InlayHint { + export const enum Kind { + TypeHint = "TypeHint", + ParamHint = "ParameterHint", + ChainingHint = "ChainingHint", + } + interface Common { + range: lc.Range; + label: string; + } + export type TypeHint = Common & { kind: Kind.TypeHint }; + export type ParamHint = Common & { kind: Kind.ParamHint }; + export type ChainingHint = Common & { kind: Kind.ChainingHint }; +} +export interface InlayHintsParams { + textDocument: lc.TextDocumentIdentifier; +} +export const inlayHints = new lc.RequestType("rust-analyzer/inlayHints"); + +export interface SsrParams { + query: string; + parseOnly: boolean; +} +export const ssr = new lc.RequestType('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[]; +} diff --git a/rust-analyzer/editors/code/src/main.ts b/rust-analyzer/editors/code/src/main.ts new file mode 100644 index 00000000..bd99d696 --- /dev/null +++ b/rust-analyzer/editors/code/src/main.ts @@ -0,0 +1,335 @@ +import * as vscode from 'vscode'; +import * as path from "path"; +import * as os from "os"; +import { promises as fs, PathLike } from "fs"; + +import * as commands from './commands'; +import { activateInlayHints } from './inlay_hints'; +import { Ctx } from './ctx'; +import { Config, NIGHTLY_TAG } from './config'; +import { log, assert, isValidExecutable } from './util'; +import { PersistentState } from './persistent_state'; +import { fetchRelease, download } from './net'; +import { activateTaskProvider } from './tasks'; +import { setContextValue } from './util'; +import { exec } from 'child_process'; + +let ctx: Ctx | undefined; + +const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; + +export async function activate(context: vscode.ExtensionContext) { + // For some reason vscode not always shows pop-up error notifications + // when an extension fails to activate, so we do it explicitly by ourselves. + // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242 + await tryActivate(context).catch(err => { + void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); + throw err; + }); +} + +async function tryActivate(context: vscode.ExtensionContext) { + // 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); + + const config = new Config(context); + const state = new PersistentState(context.globalState); + const serverPath = await bootstrap(config, state).catch(err => { + let message = "bootstrap error. "; + + if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") { + message += "Other vscode windows might be using rust-analyzer, "; + message += "you should close them and reload this window to retry. "; + } + + 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); + }); + + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + if (workspaceFolder === undefined) { + throw new Error("no folder is opened"); + } + + // 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, workspaceFolder.uri.fsPath); + + 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 deactivate(); + 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('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('expandMacro', commands.expandMacro); + ctx.registerCommand('run', commands.run); + ctx.registerCommand('debug', commands.debug); + ctx.registerCommand('newDebugConfig', commands.newDebugConfig); + + 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.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); + + activateInlayHints(ctx); + + vscode.workspace.onDidChangeConfiguration( + _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), + null, + ctx.subscriptions, + ); +} + +export async function deactivate() { + setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined); + await ctx?.client.stop(); + ctx = undefined; +} + +async function bootstrap(config: Config, state: PersistentState): Promise { + await fs.mkdir(config.globalStoragePath, { recursive: true }); + + await bootstrapExtension(config, state); + const path = await bootstrapServer(config, state); + + return path; +} + +async function bootstrapExtension(config: Config, state: PersistentState): Promise { + if (config.package.releaseTag === null) return; + if (config.channel === "stable") { + if (config.package.releaseTag === NIGHTLY_TAG) { + void vscode.window.showWarningMessage( + `You are running a nightly version of rust-analyzer extension. ` + + `To switch to stable, uninstall the extension and re-install it from the marketplace` + ); + } + return; + }; + + const now = Date.now(); + if (config.package.releaseTag === NIGHTLY_TAG) { + // Check if we should poll github api for the new nightly version + // if we haven't done it during the past hour + const lastCheck = state.lastCheck; + + const anHour = 60 * 60 * 1000; + const shouldCheckForNewNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour; + + if (!shouldCheckForNewNightly) return; + } + + const release = await fetchRelease("nightly").catch((e) => { + log.error(e); + if (state.releaseId === undefined) { // Show error only for the initial download + vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly ${e}`); + } + return undefined; + }); + if (release === undefined || release.id === state.releaseId) return; + + const userResponse = await vscode.window.showInformationMessage( + "New version of rust-analyzer (nightly) is available (requires reload).", + "Update" + ); + if (userResponse !== "Update") return; + + const artifact = release.assets.find(artifact => artifact.name === "rust-analyzer.vsix"); + assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); + + const dest = path.join(config.globalStoragePath, "rust-analyzer.vsix"); + await download({ + url: artifact.browser_download_url, + dest, + progressTitle: "Downloading rust-analyzer extension", + }); + + await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest)); + await fs.unlink(dest); + + await state.updateReleaseId(release.id); + await state.updateLastCheck(now); + await vscode.commands.executeCommand("workbench.action.reloadWindow"); +} + +async function bootstrapServer(config: Config, state: PersistentState): Promise { + const path = await getServer(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)) { + throw new Error(`Failed to execute ${path} --version`); + } + + return path; +} + +async function patchelf(dest: PathLike): Promise { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Patching rust-analyzer for NixOS" + }, + async (progress, _) => { + const expression = ` + {src, pkgs ? import {}}: + pkgs.stdenv.mkDerivation { + name = "rust-analyzer"; + inherit src; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = "cp $src $out"; + fixupPhase = '' + chmod 755 $out + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out + ''; + } + `; + const origFile = dest + "-orig"; + await fs.rename(dest, origFile); + progress.report({ message: "Patching executable", increment: 20 }); + await new Promise((resolve, reject) => { + const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`, + (err, stdout, stderr) => { + if (err != null) { + reject(Error(stderr)); + } else { + resolve(stdout); + } + }); + handle.stdin?.write(expression); + handle.stdin?.end(); + }); + await fs.unlink(origFile); + } + ); +} + +async function getServer(config: Config, state: PersistentState): Promise { + const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; + if (explicitPath) { + if (explicitPath.startsWith("~/")) { + return os.homedir() + explicitPath.slice("~".length); + } + return explicitPath; + }; + if (config.package.releaseTag === null) return "rust-analyzer"; + + let platform: string | undefined; + if (process.arch === "x64" || process.arch === "ia32") { + if (process.platform === "linux") platform = "linux"; + if (process.platform === "darwin") platform = "mac"; + if (process.platform === "win32") platform = "windows"; + } + if (platform === undefined) { + vscode.window.showErrorMessage( + "Unfortunately we don't ship binaries for your platform yet. " + + "You need to manually clone 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-analyzer/rust-analyzer/issues) and we " + + "will consider it." + ); + return undefined; + } + const ext = platform === "windows" ? ".exe" : ""; + const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); + const exists = await fs.stat(dest).then(() => true, () => false); + if (!exists) { + await state.updateServerVersion(undefined); + } + + if (state.serverVersion === config.package.version) return dest; + + if (config.askBeforeDownload) { + const userResponse = await vscode.window.showInformationMessage( + `Language server version ${config.package.version} for rust-analyzer is not installed.`, + "Download now" + ); + if (userResponse !== "Download now") return dest; + } + + const release = await fetchRelease(config.package.releaseTag); + const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`); + assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); + + // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error. + await fs.unlink(dest).catch(err => { + if (err.code !== "ENOENT") throw err; + }); + + await download({ + url: artifact.browser_download_url, + dest, + progressTitle: "Downloading rust-analyzer server", + gunzip: true, + mode: 0o755 + }); + + // Patching executable if that's NixOS. + if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) { + await patchelf(dest); + } + + await state.updateServerVersion(config.package.version); + return dest; +} diff --git a/rust-analyzer/editors/code/src/net.ts b/rust-analyzer/editors/code/src/net.ts new file mode 100644 index 00000000..681eaa9c --- /dev/null +++ b/rust-analyzer/editors/code/src/net.ts @@ -0,0 +1,143 @@ +// Replace with `import fetch from "node-fetch"` once this is fixed in rollup: +// https://github.com/rollup/plugins/issues/491 +const fetch = require("node-fetch") as typeof import("node-fetch")["default"]; + +import * as vscode from "vscode"; +import * as stream from "stream"; +import * as crypto from "crypto"; +import * as fs from "fs"; +import * as zlib from "zlib"; +import * as util from "util"; +import * as path from "path"; +import { log, assert } from "./util"; + +const pipeline = util.promisify(stream.pipeline); + +const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; +const OWNER = "rust-analyzer"; +const REPO = "rust-analyzer"; + +export async function fetchRelease( + releaseTag: string +): Promise { + + const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`; + + const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath; + + log.debug("Issuing request for released artifacts metadata to", requestUrl); + + const response = await fetch(requestUrl, { headers: { Accept: "application/vnd.github.v3+json" } }); + + if (!response.ok) { + log.error("Error fetching artifact release info", { + requestUrl, + releaseTag, + response: { + headers: response.headers, + status: response.status, + body: await response.text(), + } + }); + + throw new Error( + `Got response ${response.status} when trying to fetch ` + + `release info for ${releaseTag} release` + ); + } + + // We skip runtime type checks for simplicity (here we cast from `any` to `GithubRelease`) + const release: GithubRelease = await response.json(); + return release; +} + +// We omit declaration of tremendous amount of fields that we are not using here +export interface GithubRelease { + name: string; + id: number; + // eslint-disable-next-line camelcase + published_at: string; + assets: Array<{ + name: string; + // eslint-disable-next-line camelcase + browser_download_url: string; + }>; +} + +interface DownloadOpts { + progressTitle: string; + url: string; + dest: string; + mode?: number; + gunzip?: boolean; +} + +export async function download(opts: DownloadOpts) { + // Put artifact into a temporary file (in the same dir for simplicity) + // to prevent partially downloaded files when user kills vscode + const dest = path.parse(opts.dest); + const randomHex = crypto.randomBytes(5).toString("hex"); + const tempFile = path.join(dest.dir, `${dest.name}${randomHex}`); + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: opts.progressTitle + }, + async (progress, _cancellationToken) => { + let lastPercentage = 0; + await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => { + const newPercentage = (readBytes / totalBytes) * 100; + progress.report({ + message: newPercentage.toFixed(0) + "%", + increment: newPercentage - lastPercentage + }); + + lastPercentage = newPercentage; + }); + } + ); + + await fs.promises.rename(tempFile, opts.dest); +} + +async function downloadFile( + url: string, + destFilePath: fs.PathLike, + mode: number | undefined, + gunzip: boolean, + onProgress: (readBytes: number, totalBytes: number) => void +): Promise { + const res = await fetch(url); + + if (!res.ok) { + log.error("Error", res.status, "while downloading file from", url); + log.error({ body: await res.text(), headers: res.headers }); + + throw new Error(`Got response ${res.status} when trying to download a file.`); + } + + const totalBytes = Number(res.headers.get('content-length')); + assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); + + log.debug("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); + + let readBytes = 0; + res.body.on("data", (chunk: Buffer) => { + readBytes += chunk.length; + onProgress(readBytes, totalBytes); + }); + + const destFileStream = fs.createWriteStream(destFilePath, { mode }); + const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; + + await pipeline(srcStream, destFileStream); + + await new Promise(resolve => { + destFileStream.on("close", resolve); + destFileStream.destroy(); + // This workaround is awaiting to be removed when vscode moves to newer nodejs version: + // https://github.com/rust-analyzer/rust-analyzer/issues/3167 + }); +} diff --git a/rust-analyzer/editors/code/src/persistent_state.ts b/rust-analyzer/editors/code/src/persistent_state.ts new file mode 100644 index 00000000..5705eed8 --- /dev/null +++ b/rust-analyzer/editors/code/src/persistent_state.ts @@ -0,0 +1,41 @@ +import * as vscode from 'vscode'; +import { log } from './util'; + +export class PersistentState { + constructor(private readonly globalState: vscode.Memento) { + const { lastCheck, releaseId, serverVersion } = this; + log.info("PersistentState:", { lastCheck, releaseId, serverVersion }); + } + + /** + * Used to check for *nightly* updates once an hour. + */ + get lastCheck(): number | undefined { + return this.globalState.get("lastCheck"); + } + async updateLastCheck(value: number) { + await this.globalState.update("lastCheck", value); + } + + /** + * Release id of the *nightly* extension. + * Used to check if we should update. + */ + get releaseId(): number | undefined { + return this.globalState.get("releaseId"); + } + async updateReleaseId(value: number) { + await this.globalState.update("releaseId", value); + } + + /** + * Version of the extension that installed the server. + * Used to check if we need to update the server. + */ + get serverVersion(): string | undefined { + return this.globalState.get("serverVersion"); + } + async updateServerVersion(value: string | undefined) { + await this.globalState.update("serverVersion", value); + } +} diff --git a/rust-analyzer/editors/code/src/run.ts b/rust-analyzer/editors/code/src/run.ts new file mode 100644 index 00000000..de68f27a --- /dev/null +++ b/rust-analyzer/editors/code/src/run.ts @@ -0,0 +1,149 @@ +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 configurtation." }]; + +export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise { + 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 + 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(); + 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((_button) => { + (async () => 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 { + const env: Record = { "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 { + 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 = [...runnable.args.cargoArgs]; // should be a copy! + if (runnable.args.executableArgs.length > 0) { + args.push('--', ...runnable.args.executableArgs); + } + + 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), + }; + + 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; + + return cargoTask; +} diff --git a/rust-analyzer/editors/code/src/snippets.ts b/rust-analyzer/editors/code/src/snippets.ts new file mode 100644 index 00000000..bcb3f2cc --- /dev/null +++ b/rust-analyzer/editors/code/src/snippets.ts @@ -0,0 +1,55 @@ +import * as vscode from 'vscode'; + +import { assert } from './util'; + +export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { + assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); + const [uri, edits] = edit.entries()[0]; + + const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); + if (!editor) return; + await applySnippetTextEdits(editor, edits); +} + +export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { + let selection: vscode.Selection | undefined = undefined; + 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; + selection = new vscode.Selection( + new vscode.Position(startLine, startColumn), + new vscode.Position(startLine, endColumn), + ); + builder.replace(indel.range, newText); + } else { + lineDelta = countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); + builder.replace(indel.range, indel.newText); + } + } + }); + if (selection) editor.selection = selection; +} + +function parseSnippet(snip: string): [string, [number, number]] | undefined { + const m = snip.match(/\$(0|\{0:([^}]*)\})/); + if (!m) return undefined; + const placeholder = m[2] ?? ""; + 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/rust-analyzer/editors/code/src/tasks.ts b/rust-analyzer/editors/code/src/tasks.ts new file mode 100644 index 00000000..14abbd5b --- /dev/null +++ b/rust-analyzer/editors/code/src/tasks.ts @@ -0,0 +1,117 @@ +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 }; +} + +class CargoTaskProvider implements vscode.TaskProvider { + private readonly target: vscode.WorkspaceFolder; + private readonly config: Config; + + constructor(target: vscode.WorkspaceFolder, config: Config) { + this.target = target; + this.config = config; + } + + async provideTasks(): Promise { + // 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: 'test', group: vscode.TaskGroup.Test }, + { command: 'clean', group: vscode.TaskGroup.Clean }, + { command: 'run', group: undefined }, + ]; + + const tasks: vscode.Task[] = []; + for (const def of defs) { + const vscodeTask = await buildCargoTask(this.target, { 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 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(this.target, definition, task.name, args, this.config.cargoRunner); + } + + return undefined; + } +} + +export async function buildCargoTask( + target: vscode.WorkspaceFolder, + definition: CargoTaskDefinition, + name: string, + args: string[], + customRunner?: string, + throwOnError: boolean = false +): Promise { + + let exec: 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) { + exec = new vscode.ShellExecution(toolchain.cargoPath(), args, definition); + } + + return new vscode.Task( + definition, + target, + name, + TASK_SOURCE, + exec, + ['$rustc'] + ); +} + +export function activateTaskProvider(target: vscode.WorkspaceFolder, config: Config): vscode.Disposable { + const provider = new CargoTaskProvider(target, config); + return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); +} diff --git a/rust-analyzer/editors/code/src/toolchain.ts b/rust-analyzer/editors/code/src/toolchain.ts new file mode 100644 index 00000000..80a7915e --- /dev/null +++ b/rust-analyzer/editors/code/src/toolchain.ts @@ -0,0 +1,174 @@ +import * as cp from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as readline from 'readline'; +import { OutputChannel } from 'vscode'; +import { log, memoize } 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: 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") { + // 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 { + 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 { + 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 runCargo( + cargoArgs: string[], + onStdoutJson: (obj: any) => void, + onStderrString: (data: string) => void + ): Promise { + return new Promise((resolve, reject) => { + const cargo = cp.spawn(cargoPath(), 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 `ra_toolchain::cargo()` implementation */ +export function cargoPath(): string { + return getPathForExecutable("cargo"); +} + +/** Mirrors `ra_toolchain::get_path_for_executable()` implementation */ +export const getPathForExecutable = memoize( + // We apply caching to decrease file-system interactions + (executableName: "cargo" | "rustc" | "rustup"): string => { + { + const envVar = process.env[executableName.toUpperCase()]; + if (envVar) return envVar; + } + + if (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 = path.join(os.homedir(), ".cargo", "bin", executableName); + + if (isFile(standardPath)) return standardPath; + } catch (err) { + log.error("Failed to read the fs info", err); + } + return executableName; + } +); + +function lookupInPath(exec: string): 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]; + }); + + return candidates.some(isFile); +} + +function isFile(suspectPath: string): boolean { + // It is not mentionned in docs, but `statSync()` throws an error when + // the path doesn't exist + try { + return fs.statSync(suspectPath).isFile(); + } catch { + return false; + } +} diff --git a/rust-analyzer/editors/code/src/util.ts b/rust-analyzer/editors/code/src/util.ts new file mode 100644 index 00000000..970fedb3 --- /dev/null +++ b/rust-analyzer/editors/code/src/util.ts @@ -0,0 +1,145 @@ +import * as lc from "vscode-languageclient"; +import * as vscode from "vscode"; +import { strict as nativeAssert } from "assert"; +import { 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); + log.output.toString(); + } + + 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( + client: lc.LanguageClient, + reqType: lc.RequestType, + param: TParam, + token?: vscode.CancellationToken, +): Promise { + for (const delay of [2, 4, 6, 8, 10, 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.ErrorCodes.RequestCancelled) { + throw error; + } + + if (error.code !== lc.ErrorCodes.ContentModified) { + log.warn("LSP request failed", { method: reqType.method, param, error }); + throw error; + } + + await sleep(10 * (1 << 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 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 { + return vscode.commands.executeCommand('setContext', key, value); +} + +/** + * Returns a higher-order function that caches the results of invoking the + * underlying function. + */ +export function memoize(func: (this: TThis, arg: Param) => Ret) { + const cache = new Map(); + + return function(this: TThis, arg: Param) { + const cached = cache.get(arg); + if (cached) return cached; + + const result = func.call(this, arg); + cache.set(arg, result); + + return result; + }; +} diff --git a/rust-analyzer/editors/code/tests/runTests.ts b/rust-analyzer/editors/code/tests/runTests.ts new file mode 100644 index 00000000..22df80ad --- /dev/null +++ b/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'; + +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"]; + + // 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/rust-analyzer/editors/code/tests/unit/index.ts b/rust-analyzer/editors/code/tests/unit/index.ts new file mode 100644 index 00000000..b7d8d214 --- /dev/null +++ b/rust-analyzer/editors/code/tests/unit/index.ts @@ -0,0 +1,38 @@ +import * as path from 'path'; +import * as Mocha from 'mocha'; +import * as glob from 'glob'; + +export function run(): Promise { + // Create the mocha test + const mocha = new Mocha({ + ui: 'tdd', + color: true + }); + + const testsRoot = __dirname; + + return new Promise((resolve, reject) => { + glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { + if (err) { + return reject(err); + } + + // Add files to the test suite + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.timeout(100000); + mocha.run(failures => { + if (failures > 0) { + reject(new Error(`${failures} tests failed.`)); + } else { + resolve(); + } + }); + } catch (err) { + reject(err); + } + }); + }); +} diff --git a/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/rust-analyzer/editors/code/tests/unit/launch_config.test.ts new file mode 100644 index 00000000..68794d53 --- /dev/null +++ b/rust-analyzer/editors/code/tests/unit/launch_config.test.ts @@ -0,0 +1,52 @@ +import * as assert from 'assert'; +import { Cargo } from '../../src/toolchain'; + +suite('Launch configuration', () => { + + suite('Lens', () => { + test('A binary', async () => { + const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "pkg_name"]); + + assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); + assert.deepEqual(args.filter, undefined); + }); + + test('One of Multiple Binaries', async () => { + const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]); + + assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]); + assert.deepEqual(args.filter, undefined); + }); + + test('A test', async () => { + const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]); + + assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]); + assert.notDeepEqual(args.filter, undefined); + }); + }); + + suite('QuickPick', () => { + test('A binary', async () => { + const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]); + + assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); + assert.deepEqual(args.filter, undefined); + }); + + + test('One of Multiple Binaries', async () => { + const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]); + + assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]); + assert.deepEqual(args.filter, undefined); + }); + + test('A test', async () => { + const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]); + + assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]); + assert.notDeepEqual(args.filter, undefined); + }); + }); +}); diff --git a/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts new file mode 100644 index 00000000..f2f53e91 --- /dev/null +++ b/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts @@ -0,0 +1,118 @@ +import * as assert from 'assert'; +import { prepareEnv } from '../../src/run'; +import { RunnableEnvCfg } from '../../src/config'; +import * as ra from '../../src/lsp_ext'; + +function makeRunnable(label: string): ra.Runnable { + return { + label, + kind: "cargo", + args: { + cargoArgs: [], + executableArgs: [] + } + }; +} + +function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record { + const runnable = makeRunnable(runnableName); + return prepareEnv(runnable, config); +} + +suite('Runnable env', () => { + test('Global config works', () => { + const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" }); + assert.equal(binEnv["GLOBAL"], "g"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" }); + assert.equal(testEnv["GLOBAL"], "g"); + }); + + test('null mask works', () => { + const config = [ + { + env: { DATA: "data" } + } + ]; + const binEnv = fakePrepareEnv("run project_name", config); + assert.equal(binEnv["DATA"], "data"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "data"); + }); + + test('order works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + env: { DATA: "newdata" } + } + ]; + const binEnv = fakePrepareEnv("run project_name", config); + assert.equal(binEnv["DATA"], "newdata"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "newdata"); + }); + + test('mask works', () => { + 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.equal(binEnv["DATA"], "rundata"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "data"); + + const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); + assert.equal(specialTestEnv["DATA"], "special_test"); + }); + + test('exact test name works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + mask: "some::mod::test_name", + env: { DATA: "test special" } + } + ]; + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "test special"); + + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(specialTestEnv["DATA"], "data"); + }); + + test('test mod name works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + mask: "some::mod", + env: { DATA: "mod special" } + } + ]; + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "mod special"); + + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(specialTestEnv["DATA"], "mod special"); + }); + +}); diff --git a/rust-analyzer/editors/code/tsconfig.json b/rust-analyzer/editors/code/tsconfig.json new file mode 100644 index 00000000..c9f34824 --- /dev/null +++ b/rust-analyzer/editors/code/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2019", + "outDir": "out", + "lib": [ + "es2019" + ], + "sourceMap": true, + "rootDir": ".", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "newLine": "LF" + }, + "exclude": [ + "node_modules", + ".vscode-test" + ], + "include": [ + "src", + "tests" + ] +}