diff --git a/extensions/terminal-suggest/.vscode/launch.json b/extensions/terminal-suggest/.vscode/launch.json new file mode 100644 index 00000000000..017c8762415 --- /dev/null +++ b/extensions/terminal-suggest/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/client/out/**/*.js"], + "preLaunchTask": "npm" + } + ] +} \ No newline at end of file diff --git a/extensions/terminal-suggest/.vscode/tasks.json b/extensions/terminal-suggest/.vscode/tasks.json new file mode 100644 index 00000000000..b7c8a281635 --- /dev/null +++ b/extensions/terminal-suggest/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "command": "npm", + "type": "shell", + "presentation": { + "reveal": "silent", + }, + "args": ["run", "compile"], + "isBackground": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/extensions/terminal-suggest/.vscodeignore b/extensions/terminal-suggest/.vscodeignore new file mode 100644 index 00000000000..f05a79416be --- /dev/null +++ b/extensions/terminal-suggest/.vscodeignore @@ -0,0 +1,7 @@ +src/** +out/** +tsconfig.json +.vscode/** +extension.webpack.config.js +extension-browser.webpack.config.js +package-lock.json diff --git a/extensions/terminal-suggest/README.md b/extensions/terminal-suggest/README.md new file mode 100644 index 00000000000..215ca927ff4 --- /dev/null +++ b/extensions/terminal-suggest/README.md @@ -0,0 +1,42 @@ +# Node npm + +**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. + +## Features + +### Task Running + +This extension supports running npm scripts defined in the `package.json` as [tasks](https://code.visualstudio.com/docs/editor/tasks). Scripts with the name 'build', 'compile', or 'watch' +are treated as build tasks. + +To run scripts as tasks, use the **Tasks** menu. + +For more information about auto detection of Tasks, see the [documentation](https://code.visualstudio.com/Docs/editor/tasks#_task-autodetection). + +### Script Explorer + +The Npm Script Explorer shows the npm scripts found in your workspace. The explorer view is enabled by the setting `npm.enableScriptExplorer`. A script can be opened, run, or debug from the explorer. + +### Run Scripts from the Editor + +The extension supports to run the selected script as a task when editing the `package.json`file. You can either run a script from +the hover shown on a script or using the command `Run Selected Npm Script`. + +### Run Scripts from a Folder in the Explorer + +The extension supports running a script as a task from a folder in the Explorer. The command `Run NPM Script in Folder...` shown in the Explorer context menu finds all scripts in `package.json` files that are contained in this folder. You can then select the script to be executed as a task from the resulting list. You enable this support with the `npm.runScriptFromFolder` which is `false` by default. + +### Others + +The extension fetches data from and to provide auto-completion and information on hover features on npm dependencies. + +## Settings + +- `npm.autoDetect` - Enable detecting scripts as tasks, the default is `on`. +- `npm.runSilent` - Run npm script with the `--silent` option, the default is `false`. +- `npm.packageManager` - The package manager used to run the scripts: `auto`, `npm`, `yarn`, `pnpm` or `bun`. The default is `auto`, which detects your package manager based on files in your workspace. +- `npm.exclude` - Glob patterns for folders that should be excluded from automatic script detection. The pattern is matched against the **absolute path** of the package.json. For example, to exclude all test folders use '**/test/**'. +- `npm.enableScriptExplorer` - Enable an explorer view for npm scripts. +- `npm.scriptExplorerAction` - The default click action: `open` or `run`, the default is `open`. +- `npm.enableRunFromFolder` - Enable running npm scripts from the context menu of folders in Explorer, the default is `false`. +- `npm.scriptCodeLens.enable` - Enable/disable the code lenses to run a script, the default is `false`. diff --git a/extensions/terminal-suggest/extension-browser.webpack.config.js b/extensions/terminal-suggest/extension-browser.webpack.config.js new file mode 100644 index 00000000000..ec1313ebf26 --- /dev/null +++ b/extensions/terminal-suggest/extension-browser.webpack.config.js @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withBrowserDefaults = require('../shared.webpack.config').browser; + +const config = withBrowserDefaults({ + context: __dirname, + entry: { + extension: './src/npmBrowserMain.ts' + }, + output: { + filename: 'npmBrowserMain.js' + }, + resolve: { + fallback: { + 'child_process': false + } + } +}); + +module.exports = config; diff --git a/extensions/terminal-suggest/extension.webpack.config.js b/extensions/terminal-suggest/extension.webpack.config.js new file mode 100644 index 00000000000..320956abe3d --- /dev/null +++ b/extensions/terminal-suggest/extension.webpack.config.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); + +module.exports = withDefaults({ + context: __dirname, + entry: { + extension: './src/npmMain.ts', + }, + output: { + filename: 'npmMain.js', + }, + resolve: { + mainFields: ['module', 'main'], + extensions: ['.ts', '.js'] // support ts-files and js-files + } +}); diff --git a/extensions/terminal-suggest/package-lock.json b/extensions/terminal-suggest/package-lock.json new file mode 100644 index 00000000000..4ee7ee7a0e3 --- /dev/null +++ b/extensions/terminal-suggest/package-lock.json @@ -0,0 +1,353 @@ +{ + "name": "npm", + "version": "1.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "npm", + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root": "^2.0.0", + "jsonc-parser": "^3.2.0", + "minimatch": "^5.1.6", + "request-light": "^0.7.0", + "vscode-uri": "^3.0.8", + "which": "^4.0.0", + "which-pm": "^2.1.1" + }, + "devDependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "20.x", + "@types/which": "^3.0.0" + }, + "engines": { + "vscode": "0.10.x" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.0.tgz", + "integrity": "sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY= sha512-iK7YPKV+GsvihPUTKcM3hh2gq47zSFCpVDv/Ay2O9mzuD7dfvLV4vhms4XcjZvv4VRgXuGLMEts51IlTjS11/A==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c= sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/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==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, + "node_modules/load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/request-light": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", + "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" + }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/which-pm": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.1.1.tgz", + "integrity": "sha512-xzzxNw2wMaoCWXiGE8IJ9wuPMU+EYhFksjHxrRT8kMT5SnocBPRg69YAMtyV4D12fP582RA+k3P8H9J5EMdIxQ==", + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/extensions/terminal-suggest/package.json b/extensions/terminal-suggest/package.json new file mode 100644 index 00000000000..e9569f2917a --- /dev/null +++ b/extensions/terminal-suggest/package.json @@ -0,0 +1,362 @@ +{ + "name": "npm", + "publisher": "vscode", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.1", + "private": true, + "license": "MIT", + "engines": { + "vscode": "0.10.x" + }, + "icon": "images/npm_icon.png", + "categories": [ + "Other" + ], + "enabledApiProposals": [ + "terminalQuickFixProvider", + "terminalCompletionsProvider" + ], + "scripts": { + "compile": "npx gulp compile-extension:npm", + "watch": "npx gulp watch-extension:npm" + }, + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root": "^2.0.0", + "jsonc-parser": "^3.2.0", + "minimatch": "^5.1.6", + "request-light": "^0.7.0", + "which": "^4.0.0", + "which-pm": "^2.1.1", + "vscode-uri": "^3.0.8" + }, + "devDependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "20.x", + "@types/which": "^3.0.0" + }, + "main": "./out/npmMain", + "browser": "./dist/browser/npmBrowserMain", + "activationEvents": [ + "onTaskType:npm", + "onLanguage:json", + "workspaceContains:package.json" + ], + "capabilities": { + "virtualWorkspaces": { + "supported": "limited", + "description": "%virtualWorkspaces%" + }, + "untrustedWorkspaces": { + "supported": "limited", + "description": "%workspaceTrust%" + } + }, + "contributes": { + "languages": [ + { + "id": "ignore", + "extensions": [ + ".npmignore" + ] + }, + { + "id": "properties", + "extensions": [ + ".npmrc" + ] + } + ], + "views": { + "explorer": [ + { + "id": "npm", + "name": "%view.name%", + "when": "npm:showScriptExplorer", + "icon": "$(json)", + "visibility": "hidden", + "contextualTitle": "%view.name%" + } + ] + }, + "commands": [ + { + "command": "npm.runScript", + "title": "%command.run%", + "icon": "$(run)" + }, + { + "command": "npm.debugScript", + "title": "%command.debug%", + "icon": "$(debug)" + }, + { + "command": "npm.openScript", + "title": "%command.openScript%" + }, + { + "command": "npm.runInstall", + "title": "%command.runInstall%" + }, + { + "command": "npm.refresh", + "title": "%command.refresh%", + "icon": "$(refresh)" + }, + { + "command": "npm.runSelectedScript", + "title": "%command.runSelectedScript%" + }, + { + "command": "npm.runScriptFromFolder", + "title": "%command.runScriptFromFolder%" + }, + { + "command": "npm.packageManager", + "title": "%command.packageManager%" + } + ], + "menus": { + "commandPalette": [ + { + "command": "npm.refresh", + "when": "false" + }, + { + "command": "npm.runScript", + "when": "false" + }, + { + "command": "npm.debugScript", + "when": "false" + }, + { + "command": "npm.openScript", + "when": "false" + }, + { + "command": "npm.runInstall", + "when": "false" + }, + { + "command": "npm.runSelectedScript", + "when": "false" + }, + { + "command": "npm.runScriptFromFolder", + "when": "false" + }, + { + "command": "npm.packageManager", + "when": "false" + } + ], + "editor/context": [ + { + "command": "npm.runSelectedScript", + "when": "resourceFilename == 'package.json' && resourceScheme == file", + "group": "navigation@+1" + } + ], + "view/title": [ + { + "command": "npm.refresh", + "when": "view == npm", + "group": "navigation" + } + ], + "view/item/context": [ + { + "command": "npm.openScript", + "when": "view == npm && viewItem == packageJSON", + "group": "navigation@1" + }, + { + "command": "npm.runInstall", + "when": "view == npm && viewItem == packageJSON", + "group": "navigation@2" + }, + { + "command": "npm.openScript", + "when": "view == npm && viewItem == script", + "group": "navigation@1" + }, + { + "command": "npm.runScript", + "when": "view == npm && viewItem == script", + "group": "navigation@2" + }, + { + "command": "npm.runScript", + "when": "view == npm && viewItem == script", + "group": "inline" + }, + { + "command": "npm.debugScript", + "when": "view == npm && viewItem == script", + "group": "inline" + }, + { + "command": "npm.debugScript", + "when": "view == npm && viewItem == script", + "group": "navigation@3" + } + ], + "explorer/context": [ + { + "when": "config.npm.enableRunFromFolder && explorerViewletVisible && explorerResourceIsFolder && resourceScheme == file", + "command": "npm.runScriptFromFolder", + "group": "2_workspace" + } + ] + }, + "configuration": { + "id": "npm", + "type": "object", + "title": "Npm", + "properties": { + "npm.autoDetect": { + "type": "string", + "enum": [ + "off", + "on" + ], + "default": "on", + "scope": "resource", + "description": "%config.npm.autoDetect%" + }, + "npm.runSilent": { + "type": "boolean", + "default": false, + "scope": "resource", + "markdownDescription": "%config.npm.runSilent%" + }, + "npm.packageManager": { + "scope": "resource", + "type": "string", + "enum": [ + "auto", + "npm", + "yarn", + "pnpm", + "bun" + ], + "enumDescriptions": [ + "%config.npm.packageManager.auto%", + "%config.npm.packageManager.npm%", + "%config.npm.packageManager.yarn%", + "%config.npm.packageManager.pnpm%", + "%config.npm.packageManager.bun%" + ], + "default": "auto", + "description": "%config.npm.packageManager%" + }, + "npm.exclude": { + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + }, + "description": "%config.npm.exclude%", + "scope": "resource" + }, + "npm.enableScriptExplorer": { + "type": "boolean", + "default": false, + "scope": "resource", + "deprecationMessage": "The NPM Script Explorer is now available in 'Views' menu in the Explorer in all folders.", + "description": "%config.npm.enableScriptExplorer%" + }, + "npm.enableRunFromFolder": { + "type": "boolean", + "default": false, + "scope": "resource", + "description": "%config.npm.enableRunFromFolder%" + }, + "npm.scriptExplorerAction": { + "type": "string", + "enum": [ + "open", + "run" + ], + "markdownDescription": "%config.npm.scriptExplorerAction%", + "scope": "window", + "default": "open" + }, + "npm.scriptExplorerExclude": { + "type": "array", + "items": { + "type": "string" + }, + "markdownDescription": "%config.npm.scriptExplorerExclude%", + "scope": "resource", + "default": [] + }, + "npm.fetchOnlinePackageInfo": { + "type": "boolean", + "description": "%config.npm.fetchOnlinePackageInfo%", + "default": true, + "scope": "window", + "tags": [ + "usesOnlineServices" + ] + }, + "npm.scriptHover": { + "type": "boolean", + "description": "%config.npm.scriptHover%", + "default": true, + "scope": "window" + } + } + }, + "jsonValidation": [ + { + "fileMatch": "package.json", + "url": "https://json.schemastore.org/package" + }, + { + "fileMatch": "bower.json", + "url": "https://json.schemastore.org/bower" + } + ], + "taskDefinitions": [ + { + "type": "npm", + "required": [ + "script" + ], + "properties": { + "script": { + "type": "string", + "description": "%taskdef.script%" + }, + "path": { + "type": "string", + "description": "%taskdef.path%" + } + }, + "when": "shellExecutionSupported" + } + ], + "terminalQuickFixes": [ + { + "id": "ms-vscode.npm-command", + "commandLineMatcher": "npm", + "commandExitResult": "error", + "outputMatcher": { + "anchor": "bottom", + "length": 8, + "lineMatcher": "Did you mean (?:this|one of these)\\?((?:\\n.+?npm .+ #.+)+)", + "offset": 2 + } + } + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/vscode.git" + } +} diff --git a/extensions/terminal-suggest/package.nls.json b/extensions/terminal-suggest/package.nls.json new file mode 100644 index 00000000000..ff8581bde17 --- /dev/null +++ b/extensions/terminal-suggest/package.nls.json @@ -0,0 +1,33 @@ +{ + "description": "Extension to add task support for npm scripts.", + "displayName": "NPM support for VS Code", + "workspaceTrust": "This extension executes tasks, which require trust to run.", + "virtualWorkspaces": "Functionality that requires running the 'npm' command is not available in virtual workspaces.", + "config.npm.autoDetect": "Controls whether npm scripts should be automatically detected.", + "config.npm.runSilent": "Run npm commands with the `--silent` option.", + "config.npm.packageManager": "The package manager used to run scripts.", + "config.npm.packageManager.npm": "Use npm as the package manager for running scripts.", + "config.npm.packageManager.yarn": "Use yarn as the package manager for running scripts.", + "config.npm.packageManager.pnpm": "Use pnpm as the package manager for running scripts.", + "config.npm.packageManager.bun": "Use bun as the package manager for running scripts.", + "config.npm.packageManager.auto": "Auto-detect which package manager to use for running scripts based on lock files and installed package managers.", + "config.npm.exclude": "Configure glob patterns for folders that should be excluded from automatic script detection.", + "config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts when there is no top-level 'package.json' file.", + "config.npm.scriptExplorerAction": "The default click action used in the NPM Scripts Explorer: `open` or `run`, the default is `open`.", + "config.npm.scriptExplorerExclude": "An array of regular expressions that indicate which scripts should be excluded from the NPM Scripts view.", + "config.npm.enableRunFromFolder": "Enable running npm scripts contained in a folder from the Explorer context menu.", + "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", + "config.npm.scriptHover": "Display hover with 'Run' and 'Debug' commands for scripts.", + "npm.parseError": "Npm task detection: failed to parse the file {0}", + "taskdef.script": "The npm script to customize.", + "taskdef.path": "The path to the folder of the package.json file that provides the script. Can be omitted.", + "view.name": "NPM Scripts", + "command.refresh": "Refresh", + "command.run": "Run", + "command.debug": "Debug", + "command.openScript": "Open", + "command.runInstall": "Run Install", + "command.runSelectedScript": "Run Script", + "command.runScriptFromFolder": "Run NPM Script in Folder...", + "command.packageManager": "Get Configured Package Manager" +} diff --git a/extensions/terminal-suggest/src/npmMain.ts b/extensions/terminal-suggest/src/npmMain.ts new file mode 100644 index 00000000000..a8e7a6ed98e --- /dev/null +++ b/extensions/terminal-suggest/src/npmMain.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +// import * as which from 'which'; + +export async function activate(context: vscode.ExtensionContext): Promise { + + (vscode as any).registerTerminalCompletionProvider({ + async provideTerminalCompletions(terminal: vscode.Terminal, context: any, token: vscode.CancellationToken) { + if (token.isCancellationRequested) { + return; + } + if (context.shellType === 'pwsh') { + return; + } + const commandLine = context.commandLine; + if (commandLine.startsWith('cd')) { + return [ + { + label: 'foo', + kind: (vscode as any).TerminalCompletionItemKind.Flag, + description: 'bar' + }, + ]; + } + return; + }, + }); + +} diff --git a/extensions/terminal-suggest/tsconfig.json b/extensions/terminal-suggest/tsconfig.json new file mode 100644 index 00000000000..ec12eb547b3 --- /dev/null +++ b/extensions/terminal-suggest/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*", + "../../src/vscode-dts/vscode.d.ts", + "../../src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts", + ] +} diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 362b4298cdd..1a79a37d504 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -347,6 +347,9 @@ const _allApiProposals = { telemetry: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.telemetry.d.ts', }, + terminalCompletionProvider: { + proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts', + }, terminalDataWriteEvent: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDataWriteEvent.d.ts', }, diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 4baa14ed812..16c42d3dfaf 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -835,6 +835,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerTerminalProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable { return extHostTerminalService.registerProfileProvider(extension, id, provider); }, + registerTerminalCompletionProvider(provider: vscode.TerminalCompletionProvider): vscode.Disposable { + // check proposed api + checkProposedApiEnabled(extension, 'terminalCompletionProvider'); + return extHostTerminalService.registerTerminalCompletionProvider(extension, provider); + }, registerTerminalQuickFixProvider(id: string, provider: vscode.TerminalQuickFixProvider): vscode.Disposable { checkProposedApiEnabled(extension, 'terminalQuickFixProvider'); return extHostTerminalService.registerTerminalQuickFixProvider(id, extension.identifier.value, provider); @@ -1655,6 +1660,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I TerminalProfile: extHostTypes.TerminalProfile, TerminalExitReason: extHostTypes.TerminalExitReason, TerminalShellExecutionCommandLineConfidence: extHostTypes.TerminalShellExecutionCommandLineConfidence, + TerminalCompletionItem: extHostTypes.TerminalCompletionItem, + TerminalCompletionContext: extHostTypes.TerminalCompletionContext, + TerminalCompletionItemKind: extHostTypes.TerminalCompletionItemKind, + TerminalCompletion: extHostTypes.TerminalCompletion, TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason, TextEdit: extHostTypes.TextEdit, SnippetTextEdit: extHostTypes.SnippetTextEdit, diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 39ce969617b..76ce2cdda00 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -56,6 +56,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID getEnvironmentVariableCollection(extension: IExtensionDescription): IEnvironmentVariableCollection; getTerminalById(id: number): ExtHostTerminal | null; getTerminalIdByApiObject(apiTerminal: vscode.Terminal): number | null; + registerTerminalCompletionProvider(extension: IExtensionDescription, provider: vscode.TerminalCompletionProvider): vscode.Disposable; } interface IEnvironmentVariableCollection extends vscode.EnvironmentVariableCollection { @@ -397,6 +398,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I private readonly _bufferer: TerminalDataBufferer; private readonly _linkProviders: Set = new Set(); + private readonly _completionProviders: Map> = new Map(); private readonly _profileProviders: Map = new Map(); private readonly _quickFixProviders: Map = new Map(); private readonly _terminalLinkCache: Map> = new Map(); @@ -732,6 +734,18 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I }); } + public registerTerminalCompletionProvider(extension: IExtensionDescription, provider: vscode.TerminalCompletionProvider): vscode.Disposable { + if (this._completionProviders.has(provider.id)) { + throw new Error(`Terminal completion provider "${provider.id}" already registered`); + } + this._completionProviders.set(provider.id, provider); + this._proxy.$registerProfileProvider(provider.id, extension.identifier.value); + return new VSCodeDisposable(() => { + this._completionProviders.delete(provider.id); + this._proxy.$unregisterProfileProvider(provider.id); + }); + } + public registerProfileProvider(extension: IExtensionDescription, id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable { if (this._profileProviders.has(id)) { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index ada4e5e5156..14624ceee6d 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2108,6 +2108,44 @@ export class TerminalProfile implements vscode.TerminalProfile { } } +export class TerminalCompletion { + + /** + * The label of this completion item. By default + * this is also the text that is inserted when selecting + * this completion. + */ + label: string | CompletionItemLabel; + + /** + * The kind of this completion item. Based on the kind, + * an icon is chosen. + */ + kind?: TerminalCompletionItemKind; + + /** + * A human-readable string with additional information + * about this item. + */ + detail?: string; + + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string | MarkdownString; +} + +export enum TerminalCompletionItemKind { + File = 0, + Folder = 1, + Flag = 2, +} + +export interface TerminalCompletionContext { + shellType: string; + commandLine: string; +} + export enum TaskRevealKind { Always = 1, diff --git a/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts b/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts new file mode 100644 index 00000000000..61847dd6973 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/226562 + + export interface TerminalCompletionProvider { + id: string; + /** + * Provide completions for the given position and document. + * @param terminal The terminal for which completions are being provided. + * @param context Information about the terminal's current state. + * @param token A cancellation token. + * @return A list of completions. + */ + provideTerminalCompletions(terminal: Terminal, context: TerminalCompletionContext, token: CancellationToken): ProviderResult>; + } + + export class TerminalCompletion { + + /** + * The label of this completion item. By default + * this is also the text that is inserted when selecting + * this completion. + */ + label: string | CompletionItemLabel; + + /** + * The kind of this completion item. Based on the kind, + * an icon is chosen. + */ + kind?: TerminalCompletionItemKind; + + /** + * A human-readable string with additional information + * about this item. + */ + detail?: string; + + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string | MarkdownString; + } + + export enum TerminalCompletionItemKind { + File = 0, + Folder = 1, + Flag = 2, + } + + export interface TerminalCompletionContext { + shellType: string; + commandLine: string; + } + export namespace window { + export function registerTerminalCompletionProvider(provider: TerminalCompletionProvider): Disposable; + } +}