diff --git a/.gitignore b/.gitignore index 80a99a4952..f44cadebe5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ out-vscode-reh-web-min/ out-vscode-reh-web-pkg/ out-vscode-web/ out-vscode-web-min/ +out-vscode-web-pkg/ src/vs/server resources/server build/node_modules diff --git a/.vscode/launch.json b/.vscode/launch.json index 04efa7aa70..45000d4bcb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -90,10 +90,10 @@ "port": 9222, "timeout": 20000, "env": { - "VSCODE_EXTHOST_WILL_SEND_SOCKET": null + "VSCODE_EXTHOST_WILL_SEND_SOCKET": null, + "VSCODE_SKIP_PRELAUNCH": "1" }, "cleanUp": "wholeBrowser", - "breakOnLoad": false, "urlFilter": "*workbench.html*", "runtimeArgs": [ "--inspect=5875", @@ -106,7 +106,8 @@ "outFiles": [ "${workspaceFolder}/out/**/*.js" ], - "browserLaunchLocation": "workspace" + "browserLaunchLocation": "workspace", + "preLaunchTask": "Ensure Prelaunch Dependencies", }, { "type": "chrome", diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index 8931e7b0b3..979da52c04 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -8,8 +8,17 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item ", - "editable": true + "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item " + }, + { + "kind": 1, + "language": "markdown", + "value": "## Inbox tracking and Issue triage" + }, + { + "kind": 1, + "language": "markdown", + "value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/master/.github/classifier.json). \n\nšŸ’” The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/Microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions." }, { "kind": 1, @@ -32,7 +41,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox", - "editable": false + "value": "$inbox -label:emmet", + "editable": true } ] \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 21c38ac822..8e1235f8d8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -200,6 +200,14 @@ "source": "eslint", "base": "$eslint-stylish" } - } + }, + { + "type": "shell", + "command": "node build/lib/prelaunch.js", + "label": "Ensure Prelaunch Dependencies", + "presentation": { + "reveal": "silent" + } + }, ] } diff --git a/.yarnrc b/.yarnrc index 5119ded102..135e10442a 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "9.1.0" +target "7.3.2" runtime "electron" diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index d6f61a7aec..e758389603 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version inputs: diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index ae6dae321b..9c5b047ceb 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index f26d5db267..a286bf7ef8 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -11,7 +11,7 @@ pr: steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' diff --git a/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml index 0b825b7438..ff2b7065cb 100644 --- a/build/azure-pipelines/exploration-build.yml +++ b/build/azure-pipelines/exploration-build.yml @@ -11,7 +11,7 @@ pr: steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Get Secrets' diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 2f6482bd76..cb871f65bd 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -10,7 +10,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 inputs: diff --git a/build/azure-pipelines/linux/product-build-linux-multiarch.yml b/build/azure-pipelines/linux/product-build-linux-multiarch.yml index 258f87ea3d..485f8dcfba 100644 --- a/build/azure-pipelines/linux/product-build-linux-multiarch.yml +++ b/build/azure-pipelines/linux/product-build-linux-multiarch.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index dbd0621a27..5d7bccf467 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 39c39e86c9..a530499b31 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index ab0dbb932c..db6524be03 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -16,7 +16,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index 10b6aa4e16..b73cd04a96 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -9,7 +9,7 @@ pr: none steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts index 7c0ca80ecc..598d75050f 100644 --- a/build/azure-pipelines/publish-types/update-types.ts +++ b/build/azure-pipelines/publish-types/update-types.ts @@ -36,6 +36,18 @@ function updateDTSFile(outPath: string, tag: string) { fs.writeFileSync(outPath, newContent); } +function repeat(str: string, times: number): string { + const result = new Array(times); + for (let i = 0; i < times; i++) { + result[i] = str; + } + return result.join(''); +} + +function convertTabsToSpaces(str: string): string { + return str.replace(/^\t+/gm, value => repeat(' ', value.length)); +} + function getNewFileContent(content: string, tag: string) { const oldheader = [ `/*---------------------------------------------------------------------------------------------`, @@ -44,7 +56,7 @@ function getNewFileContent(content: string, tag: string) { ` *--------------------------------------------------------------------------------------------*/` ].join('\n'); - return getNewFileHeader(tag) + content.slice(oldheader.length); + return convertTabsToSpaces(getNewFileHeader(tag) + content.slice(oldheader.length)); } function getNewFileHeader(tag: string) { diff --git a/build/azure-pipelines/sync-mooncake.yml b/build/azure-pipelines/sync-mooncake.yml index 49dfc9ced8..2641830a41 100644 --- a/build/azure-pipelines/sync-mooncake.yml +++ b/build/azure-pipelines/sync-mooncake.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index 7f4907aa2d..0c338203b4 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index 5470b8e0de..0e4045639e 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version inputs: diff --git a/build/azure-pipelines/win32/product-build-win32-arm64.yml b/build/azure-pipelines/win32/product-build-win32-arm64.yml index ecb50ad678..01be34aa9a 100644 --- a/build/azure-pipelines/win32/product-build-win32-arm64.yml +++ b/build/azure-pipelines/win32/product-build-win32-arm64.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index c233d5c6d2..fb4f305257 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -21,7 +21,7 @@ steps: - task: NodeTool@0 inputs: - versionSpec: "12.14.1" + versionSpec: "12.13.0" - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 74f95d1015..0eed5bebe4 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -171,8 +171,8 @@ gulp.task(compileExtensionsBuildLegacyTask); const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( cleanExtensionsBuildTask, - task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))), - task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))) + task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))), + task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))), )); gulp.task(compileExtensionsBuildTask); diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 295123418b..d4eb9fed61 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -42,8 +42,8 @@ const indentationFilter = [ '**', // except specific files - '!ThirdPartyNotices.txt', - '!LICENSE.{txt,rtf}', + '!**/ThirdPartyNotices.txt', + '!**/LICENSE.{txt,rtf}', '!LICENSES.chromium.html', '!**/LICENSE', '!src/vs/nls.js', diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index 708bbf38fc..d2a1f7553b 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -100,7 +100,7 @@ function writeControlFile(control) { fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2)); } -function main() { +exports.getBuiltInExtensions = function getBuiltInExtensions() { log('Syncronizing built-in extensions...'); log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`); @@ -116,14 +116,16 @@ function main() { writeControlFile(control); - es.merge(streams) - .on('error', err => { - console.error(err); - process.exit(1); - }) - .on('end', () => { - process.exit(0); - }); -} + return new Promise((resolve, reject) => { + es.merge(streams) + .on('error', reject) + .on('end', resolve); + }); +}; -main(); +if (require.main === module) { + exports.getBuiltInExtensions().then(() => process.exit(0)).catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 05d2b2fb2a..22423ab4b7 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -4,7 +4,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.translatePackageJSON = exports.packageRebuildExtensionsStream = exports.cleanRebuildExtensions = exports.packageExternalExtensionsStream = exports.scanBuiltinExtensions = exports.packageMarketplaceWebExtensionsStream = exports.packageMarketplaceExtensionsStream = exports.packageLocalWebExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; +exports.translatePackageJSON = exports.packageRebuildExtensionsStream = exports.cleanRebuildExtensions = exports.packageExternalExtensionsStream = exports.scanBuiltinExtensions = exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; const es = require("event-stream"); const fs = require("fs"); const glob = require("glob"); @@ -22,22 +22,28 @@ const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const buffer = require('gulp-buffer'); const json = require("gulp-json-editor"); +const jsoncParser = require("jsonc-parser"); const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); const util = require('./util'); const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`; -function minimizeLanguageJSON(input) { - const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); +function minifyExtensionResources(input) { + const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); return input - .pipe(tmLanguageJsonFilter) + .pipe(jsonFilter) .pipe(buffer()) .pipe(es.mapSync((f) => { - f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8')))); + const errors = []; + const value = jsoncParser.parse(f.contents.toString('utf8'), errors); + if (errors.length === 0) { + // file parsed OK => just stringify to drop whitespace and comments + f.contents = Buffer.from(JSON.stringify(value)); + } return f; })) - .pipe(tmLanguageJsonFilter.restore); + .pipe(jsonFilter.restore); } function updateExtensionPackageJSON(input, update) { const packageJsonFilter = filter('extensions/*/package.json', { restore: true }); @@ -57,24 +63,18 @@ function fromLocal(extensionPath, forWeb) { let input = isWebPacked ? fromLocalWebpack(extensionPath, webpackConfigFileName) : fromLocalNormal(extensionPath); - if (forWeb) { - input = updateExtensionPackageJSON(input, (data) => { - if (data.browser) { - data.main = data.browser; - } - data.extensionKind = ['web']; - return data; - }); - } - else if (isWebPacked) { + if (isWebPacked) { input = updateExtensionPackageJSON(input, (data) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); } return data; }); } - return minimizeLanguageJSON(input); + return input; } function fromLocalWebpack(extensionPath, webpackConfigFileName) { const result = es.through(); @@ -194,7 +194,6 @@ function fromMarketplace(extensionName, version, metadata) { exports.fromMarketplace = fromMarketplace; const excludedExtensions = [ 'vscode-api-tests', - 'vscode-web-playground', 'vscode-colorize-tests', 'vscode-test-resolver', 'ms-vscode.node-debug', @@ -230,98 +229,105 @@ const rebuildExtensions = [ 'big-data-cluster', 'mssql' ]; -const builtInExtensions = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; -function packageLocalExtensionsStream() { - const localExtensionDescriptions = glob.sync('extensions/*/package.json') +const marketplaceWebExtensions = [ + 'ms-vscode.references-view' +]; +const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); +const builtInExtensions = productJson.builtInExtensions || []; +const webBuiltInExtensions = productJson.webBuiltInExtensions || []; +/** + * Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts` + */ +function isWebExtension(manifest) { + if (typeof manifest.extensionKind !== 'undefined') { + const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind]; + return (extensionKind.indexOf('web') >= 0); + } + return (!Boolean(manifest.main) || Boolean(manifest.browser)); +} +function packageLocalExtensionsStream(forWeb) { + const localExtensionsDescriptions = (glob.sync('extensions/*/package.json') .map(manifestPath => { + const absoluteManifestPath = path.join(root, manifestPath); const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; + return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath }; }) + .filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web .filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) - .filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package - const localExtensions = localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, false) + .filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package + ); + const localExtensionsStream = minifyExtensionResources(es.merge(...localExtensionsDescriptions.map(extension => { + return fromLocal(extension.path, forWeb) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); - return es.merge(nodeModules, ...localExtensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); + }))); + let result; + if (forWeb) { + result = localExtensionsStream; + } + else { + // also include shared node modules + result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' })); + } + return (result + .pipe(util2.setExecutableBit(['**/*.sh']))); } exports.packageLocalExtensionsStream = packageLocalExtensionsStream; -function packageLocalWebExtensionsStream() { - const localExtensionDescriptions = glob.sync('extensions/*/package.json') - .filter(manifestPath => { - const packageJsonConfig = require(path.join(root, manifestPath)); - return !packageJsonConfig.main || packageJsonConfig.browser; - }) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }); - return es.merge(...localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, true) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })); -} -exports.packageLocalWebExtensionsStream = packageLocalWebExtensionsStream; -function packageMarketplaceExtensionsStream() { - const extensions = builtInExtensions.map(extension => { - return fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - return es.merge(extensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); -} -exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; -function packageMarketplaceWebExtensionsStream(builtInExtensions) { - const extensions = builtInExtensions +function packageMarketplaceExtensionsStream(forWeb) { + const marketplaceExtensionsDescriptions = [ + ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)), + ...(forWeb ? webBuiltInExtensions : []) + ]; + const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions .map(extension => { const input = fromMarketplace(extension.name, extension.version, extension.metadata) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); return updateExtensionPackageJSON(input, (data) => { - if (data.main) { - data.browser = data.main; - } - data.extensionKind = ['web']; + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; return data; }); - }); - return es.merge(extensions); + }))); + return (marketplaceExtensionsStream + .pipe(util2.setExecutableBit(['**/*.sh']))); } -exports.packageMarketplaceWebExtensionsStream = packageMarketplaceWebExtensionsStream; -function scanBuiltinExtensions(extensionsRoot, forWeb) { +exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; +function scanBuiltinExtensions(extensionsRoot, exclude = []) { const scannedExtensions = []; - const extensionsFolders = fs.readdirSync(extensionsRoot); - for (const extensionFolder of extensionsFolders) { - const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); - if (!fs.existsSync(packageJSONPath)) { - continue; + try { + const extensionsFolders = fs.readdirSync(extensionsRoot); + for (const extensionFolder of extensionsFolders) { + if (exclude.indexOf(extensionFolder) >= 0) { + continue; + } + const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); + if (!fs.existsSync(packageJSONPath)) { + continue; + } + let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + if (!isWebExtension(packageJSON)) { + continue; + } + const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); + const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; + const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; + scannedExtensions.push({ + extensionPath: extensionFolder, + packageJSON, + packageNLS, + readmePath: readme ? path.join(extensionFolder, readme) : undefined, + changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, + }); } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); - const extensionKind = packageJSON['extensionKind'] || []; - if (forWeb && extensionKind.indexOf('web') === -1) { - continue; - } - const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); - const packageNLS = children.filter(child => child === 'package.nls.json')[0]; - const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; - const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; - if (packageNLS) { - // temporary - packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS)); - } - scannedExtensions.push({ - extensionPath: extensionFolder, - packageJSON, - packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined, - readmePath: readme ? path.join(extensionFolder, readme) : undefined, - changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, - }); + return scannedExtensions; + } + catch (ex) { + return scannedExtensions; } - return scannedExtensions; } exports.scanBuiltinExtensions = scanBuiltinExtensions; function packageExternalExtensionsStream() { diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 6a55bec013..e338b0b10e 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -21,6 +21,7 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; const buffer = require('gulp-buffer'); import json = require('gulp-json-editor'); +import * as jsoncParser from 'jsonc-parser'; const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); const util = require('./util'); @@ -28,16 +29,21 @@ const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`; -function minimizeLanguageJSON(input: Stream): Stream { - const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); +function minifyExtensionResources(input: Stream): Stream { + const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true }); return input - .pipe(tmLanguageJsonFilter) + .pipe(jsonFilter) .pipe(buffer()) .pipe(es.mapSync((f: File) => { - f.contents = Buffer.from(JSON.stringify(JSON.parse(f.contents.toString('utf8')))); + const errors: jsoncParser.ParseError[] = []; + const value = jsoncParser.parse(f.contents.toString('utf8'), errors); + if (errors.length === 0) { + // file parsed OK => just stringify to drop whitespace and comments + f.contents = Buffer.from(JSON.stringify(value)); + } return f; })) - .pipe(tmLanguageJsonFilter.restore); + .pipe(jsonFilter.restore); } function updateExtensionPackageJSON(input: Stream, update: (data: any) => any): Stream { @@ -61,16 +67,11 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { ? fromLocalWebpack(extensionPath, webpackConfigFileName) : fromLocalNormal(extensionPath); - if (forWeb) { - input = updateExtensionPackageJSON(input, (data: any) => { - if (data.browser) { - data.main = data.browser; - } - data.extensionKind = ['web']; - return data; - }); - } else if (isWebPacked) { + if (isWebPacked) { input = updateExtensionPackageJSON(input, (data: any) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); } @@ -78,7 +79,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { }); } - return minimizeLanguageJSON(input); + return input; } @@ -224,10 +225,8 @@ export function fromMarketplace(extensionName: string, version: string, metadata .pipe(json({ __metadata: metadata })) .pipe(packageJsonFilter.restore); } - const excludedExtensions = [ 'vscode-api-tests', - 'vscode-web-playground', 'vscode-colorize-tests', 'vscode-test-resolver', 'ms-vscode.node-debug', @@ -266,6 +265,10 @@ const rebuildExtensions = [ 'mssql' ]; +const marketplaceWebExtensions = [ + 'ms-vscode.references-view' +]; + interface IBuiltInExtension { name: string; version: string; @@ -273,113 +276,134 @@ interface IBuiltInExtension { metadata: any; } -const builtInExtensions: IBuiltInExtension[] = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; +const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); +const builtInExtensions: IBuiltInExtension[] = productJson.builtInExtensions || []; +const webBuiltInExtensions: IBuiltInExtension[] = productJson.webBuiltInExtensions || []; -export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream { - const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }) - .filter(({ name }) => excludedExtensions.indexOf(name) === -1) - .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) - .filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package - - - const localExtensions = localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, false) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); - - const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); - return es.merge(nodeModules, ...localExtensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); +type ExtensionKind = 'ui' | 'workspace' | 'web'; +interface IExtensionManifest { + main: string; + browser: string; + extensionKind?: ExtensionKind | ExtensionKind[]; +} +/** + * Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts` + */ +function isWebExtension(manifest: IExtensionManifest): boolean { + if (typeof manifest.extensionKind !== 'undefined') { + const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind]; + return (extensionKind.indexOf('web') >= 0); + } + return (!Boolean(manifest.main) || Boolean(manifest.browser)); } -export function packageLocalWebExtensionsStream(): NodeJS.ReadWriteStream { - const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) - .filter(manifestPath => { - const packageJsonConfig = require(path.join(root, manifestPath)); - return !packageJsonConfig.main || packageJsonConfig.browser; - }) - .map(manifestPath => { - const extensionPath = path.dirname(path.join(root, manifestPath)); - const extensionName = path.basename(extensionPath); - return { name: extensionName, path: extensionPath }; - }); +export function packageLocalExtensionsStream(forWeb: boolean): Stream { + const localExtensionsDescriptions = ( + (glob.sync('extensions/*/package.json')) + .map(manifestPath => { + const absoluteManifestPath = path.join(root, manifestPath); + const extensionPath = path.dirname(path.join(root, manifestPath)); + const extensionName = path.basename(extensionPath); + return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath }; + }) + .filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web + .filter(({ name }) => excludedExtensions.indexOf(name) === -1) + .filter(({ name }) => builtInExtensions.every(b => b.name !== name)) + .filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package + ); + const localExtensionsStream = minifyExtensionResources( + es.merge( + ...localExtensionsDescriptions.map(extension => { + return fromLocal(extension.path, forWeb) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + }) + ) + ); - return es.merge(...localExtensionDescriptions.map(extension => { - return fromLocal(extension.path, true) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })); + let result: Stream; + if (forWeb) { + result = localExtensionsStream; + } else { + // also include shared node modules + result = es.merge(localExtensionsStream, gulp.src('extensions/node_modules/**', { base: '.' })); + } + + return ( + result + .pipe(util2.setExecutableBit(['**/*.sh'])) + ); } -export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream { - const extensions = builtInExtensions.map(extension => { - return fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }); +export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream { + const marketplaceExtensionsDescriptions = [ + ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)), + ...(forWeb ? webBuiltInExtensions : []) + ]; + const marketplaceExtensionsStream = minifyExtensionResources( + es.merge( + ...marketplaceExtensionsDescriptions + .map(extension => { + const input = fromMarketplace(extension.name, extension.version, extension.metadata) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + return updateExtensionPackageJSON(input, (data: any) => { + delete data.scripts; + delete data.dependencies; + delete data.devDependencies; + return data; + }); + }) + ) + ); - return es.merge(extensions) - .pipe(util2.setExecutableBit(['**/*.sh'])); -} - -export function packageMarketplaceWebExtensionsStream(builtInExtensions: IBuiltInExtension[]): NodeJS.ReadWriteStream { - const extensions = builtInExtensions - .map(extension => { - const input = fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - return updateExtensionPackageJSON(input, (data: any) => { - if (data.main) { - data.browser = data.main; - } - data.extensionKind = ['web']; - return data; - }); - }); - return es.merge(extensions); + return ( + marketplaceExtensionsStream + .pipe(util2.setExecutableBit(['**/*.sh'])) + ); } export interface IScannedBuiltinExtension { - extensionPath: string, - packageJSON: any, - packageNLSPath?: string, - readmePath?: string, - changelogPath?: string, + extensionPath: string; + packageJSON: any; + packageNLS?: any; + readmePath?: string; + changelogPath?: string; } -export function scanBuiltinExtensions(extensionsRoot: string, forWeb: boolean): IScannedBuiltinExtension[] { +export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] = []): IScannedBuiltinExtension[] { const scannedExtensions: IScannedBuiltinExtension[] = []; - const extensionsFolders = fs.readdirSync(extensionsRoot); - for (const extensionFolder of extensionsFolders) { - const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); - if (!fs.existsSync(packageJSONPath)) { - continue; - } - let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); - const extensionKind: string[] = packageJSON['extensionKind'] || []; - if (forWeb && extensionKind.indexOf('web') === -1) { - continue; - } - const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); - const packageNLS = children.filter(child => child === 'package.nls.json')[0]; - const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; - const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; - if (packageNLS) { - // temporary - packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS)); + try { + const extensionsFolders = fs.readdirSync(extensionsRoot); + for (const extensionFolder of extensionsFolders) { + if (exclude.indexOf(extensionFolder) >= 0) { + continue; + } + const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); + if (!fs.existsSync(packageJSONPath)) { + continue; + } + let packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString('utf8')); + if (!isWebExtension(packageJSON)) { + continue; + } + const children = fs.readdirSync(path.join(extensionsRoot, extensionFolder)); + const packageNLSPath = children.filter(child => child === 'package.nls.json')[0]; + const packageNLS = packageNLSPath ? JSON.parse(fs.readFileSync(path.join(extensionsRoot, extensionFolder, packageNLSPath)).toString()) : undefined; + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; + + scannedExtensions.push({ + extensionPath: extensionFolder, + packageJSON, + packageNLS, + readmePath: readme ? path.join(extensionFolder, readme) : undefined, + changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, + }); } - scannedExtensions.push({ - extensionPath: extensionFolder, - packageJSON, - packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined, - readmePath: readme ? path.join(extensionFolder, readme) : undefined, - changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined, - }); + return scannedExtensions; + } catch (ex) { + return scannedExtensions; } - return scannedExtensions; } export function packageExternalExtensionsStream(): NodeJS.ReadWriteStream { diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index ceef664b85..9bba404c24 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -246,6 +246,10 @@ "name": "vs/workbench/services/configurationResolver", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/crashReporter", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/dialogs", "project": "vscode-workbench" diff --git a/build/lib/optimize.js b/build/lib/optimize.js index df7097a9fe..240cdc6fca 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -72,7 +72,7 @@ function loader(src, bundledFileHeader, bundleLoader) { })) .pipe(concat('vs/loader.js'))); } -function toConcatStream(src, bundledFileHeader, sources, dest) { +function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper) { const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); // If a bundle ends up including in any of the sources our copyright, then // insert a fake source at the beginning of each bundle with our copyright @@ -93,10 +93,12 @@ function toConcatStream(src, bundledFileHeader, sources, dest) { const treatedSources = sources.map(function (source) { const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; const base = source.path ? root + `/${src}` : ''; + const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake'; + const contents = source.path ? fileContentMapper(source.contents, path) : source.contents; return new VinylFile({ - path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', + path: path, base: base, - contents: Buffer.from(source.contents) + contents: Buffer.from(contents) }); }); return es.readArray(treatedSources) @@ -104,9 +106,9 @@ function toConcatStream(src, bundledFileHeader, sources, dest) { .pipe(concat(dest)) .pipe(stats_1.createStatsStream(dest)); } -function toBundleStream(src, bundledFileHeader, bundles) { +function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) { return es.merge(bundles.map(function (bundle) { - return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest); + return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); })); } const DEFAULT_FILE_HEADER = [ @@ -122,6 +124,7 @@ function optimizeTask(opts) { const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; + const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents); return function () { const bundlesStream = es.through(); // this stream will contain the bundled files const resourcesStream = es.through(); // this stream will contain the resources @@ -130,7 +133,7 @@ function optimizeTask(opts) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } - toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); result.cssInlinedResources.forEach(function (resource) { diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 828fbca507..313ef17295 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -18,7 +18,6 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as path from 'path'; import * as pump from 'pump'; -import * as sm from 'source-map'; import * as terser from 'terser'; import * as VinylFile from 'vinyl'; import * as bundle from './bundle'; @@ -50,10 +49,6 @@ export function loaderConfig() { const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; -declare class FileSourceMap extends VinylFile { - public sourceMap: sm.RawSourceMap; -} - function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream { let sources = [ `${src}/vs/loader.js` @@ -86,7 +81,7 @@ function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): ); } -function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string): NodeJS.ReadWriteStream { +function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string, fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream { const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); // If a bundle ends up including in any of the sources our copyright, then @@ -110,11 +105,13 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle. const treatedSources = sources.map(function (source) { const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; const base = source.path ? root + `/${src}` : ''; + const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake'; + const contents = source.path ? fileContentMapper(source.contents, path) : source.contents; return new VinylFile({ - path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', + path: path, base: base, - contents: Buffer.from(source.contents) + contents: Buffer.from(contents) }); }); @@ -124,9 +121,9 @@ function toConcatStream(src: string, bundledFileHeader: string, sources: bundle. .pipe(createStatsStream(dest)); } -function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[]): NodeJS.ReadWriteStream { +function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[], fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream { return es.merge(bundles.map(function (bundle) { - return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest); + return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper); })); } @@ -164,6 +161,12 @@ export interface IOptimizeTaskOpts { * (out folder name) */ languages?: Language[]; + /** + * File contents interceptor + * @param contents The contens of the file + * @param path The absolute file path, always using `/`, even on Windows + */ + fileContentMapper?: (contents: string, path: string) => string; } const DEFAULT_FILE_HEADER = [ @@ -180,6 +183,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; + const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents); return function () { const bundlesStream = es.through(); // this stream will contain the bundled files @@ -189,7 +193,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr bundle.bundle(entryPoints, loaderConfig, function (err, result) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } - toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); + toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); diff --git a/build/lib/preLaunch.js b/build/lib/preLaunch.js new file mode 100644 index 0000000000..e7b38cac36 --- /dev/null +++ b/build/lib/preLaunch.js @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); +// @ts-check +const path = require("path"); +const child_process_1 = require("child_process"); +const fs_1 = require("fs"); +const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; +const rootDir = path.resolve(__dirname, '..', '..'); +function runProcess(command, args = []) { + return new Promise((resolve, reject) => { + const child = child_process_1.spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); + child.on('exit', err => !err ? resolve() : process.exit(err !== null && err !== void 0 ? err : 1)); + child.on('error', reject); + }); +} +async function exists(subdir) { + try { + await fs_1.promises.stat(path.join(rootDir, subdir)); + return true; + } + catch (_a) { + return false; + } +} +async function ensureNodeModules() { + if (!(await exists('node_modules'))) { + await runProcess(yarn); + } +} +async function getElectron() { + await runProcess(yarn, ['electron']); +} +async function ensureCompiled() { + if (!(await exists('out'))) { + await runProcess(yarn, ['compile']); + } +} +async function main() { + await ensureNodeModules(); + await getElectron(); + await ensureCompiled(); + // Can't require this until after dependencies are installed + const { getBuiltInExtensions } = require('./builtInExtensions'); + await getBuiltInExtensions(); +} +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/lib/preLaunch.ts b/build/lib/preLaunch.ts new file mode 100644 index 0000000000..9df6882f4d --- /dev/null +++ b/build/lib/preLaunch.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +// @ts-check + +import * as path from 'path'; +import { spawn } from 'child_process'; +import { promises as fs } from 'fs'; + +const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; +const rootDir = path.resolve(__dirname, '..', '..'); + +function runProcess(command: string, args: ReadonlyArray = []) { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); + child.on('exit', err => !err ? resolve() : process.exit(err ?? 1)); + child.on('error', reject); + }); +} + +async function exists(subdir: string) { + try { + await fs.stat(path.join(rootDir, subdir)); + return true; + } catch { + return false; + } +} + +async function ensureNodeModules() { + if (!(await exists('node_modules'))) { + await runProcess(yarn); + } +} + +async function getElectron() { + await runProcess(yarn, ['electron']); +} + +async function ensureCompiled() { + if (!(await exists('out'))) { + await runProcess(yarn, ['compile']); + } +} + +async function main() { + await ensureNodeModules(); + await getElectron(); + await ensureCompiled(); + + // Can't require this until after dependencies are installed + const { getBuiltInExtensions } = require('./builtInExtensions'); + await getBuiltInExtensions(); +} + +if (require.main === module) { + main().catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/package.json b/build/package.json index 7e813a381b..0a10bf0dda 100644 --- a/build/package.json +++ b/build/package.json @@ -41,6 +41,7 @@ "gulp-sourcemaps": "^1.11.0", "gulp-uglify": "^3.0.0", "iconv-lite-umd": "0.6.8", + "jsonc-parser": "^2.3.0", "mime": "^1.3.4", "minimatch": "3.0.4", "minimist": "^1.2.3", @@ -49,7 +50,7 @@ "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", "terser": "4.3.8", - "typescript": "^4.0.0-dev.20200722", + "typescript": "^4.0.0-dev.20200803", "vsce": "1.48.0", "vscode-telemetry-extractor": "^1.6.0", "xml2js": "^0.4.17" diff --git a/build/tsconfig.json b/build/tsconfig.json index 4bcde65375..9ffce5e262 100644 --- a/build/tsconfig.json +++ b/build/tsconfig.json @@ -14,7 +14,8 @@ "checkJs": true, "strict": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "newLine": "lf" }, "include": [ "**/*.ts" diff --git a/build/yarn.lock b/build/yarn.lock index c1d6b399dd..85a07fa52d 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2123,6 +2123,11 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +jsonc-parser@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.0.tgz#7c7fc988ee1486d35734faaaa866fadb00fa91ee" + integrity sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3539,10 +3544,10 @@ typescript@^3.0.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== -typescript@^4.0.0-dev.20200722: - version "4.0.0-dev.20200722" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200722.tgz#b59dd5a3cd84a98d5aae0e4f3a3c58f0c81a3b9b" - integrity sha512-MmJ1YyPNK3JYeKLiTg5sQXdeZaMgt99Fg4BMRZhJmhoq1/x2V1cpXMYvE1rtIYl9K7NvmTDdU3WDW7ZOD6ybaw== +typescript@^4.0.0-dev.20200803: + version "4.0.0-dev.20200803" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200803.tgz#ea8b0e9fb2ee3085598ff200c8568f04f4cbb2ba" + integrity sha512-f/jDkFqCs0gbUd5MCUijO9u3AOMx1x1HdRDDHSidlc6uPVEkRduxjeTFhIXbGutO7ivzv+aC2sxH+1FQwsyBcg== typical@^4.0.0: version "4.0.0" diff --git a/cglicenses.json b/cglicenses.json index f2d5a39a2b..0da22bd9f5 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -330,5 +330,34 @@ "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "SOFTWARE." ] + }, + { + // Reason: The license at https://github.com/colorjs/color-name/blob/master/LICENSE + // cannot be found by the OSS tool automatically. + "name": "color-name", + "fullLicenseText": [ + "The MIT License (MIT)", + "Copyright (c) 2015 Dmitry Ivanov", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] + }, + { + // Reason: The license cannot be found by the tool due to access controls on the repository + "name": "tas-client", + "fullLicenseText": [ + "MIT License", + "Copyright (c) 2020 - present Microsoft Corporation", + "", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", + "", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ] } ] diff --git a/cgmanifest.json b/cgmanifest.json index 29afebf6b0..cb9954628d 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "894fb9eb56c6cbda65e3c3ae9ada6d4cb5850cc9" + "commitHash": "e4745133a1d3745f066e068b8033c6a269b59caf" } }, "licenseDetail": [ @@ -40,7 +40,7 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "83.0.4103.122" + "version": "78.0.3904.130" }, { "component": { @@ -48,11 +48,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "9622fed3fb2cffcea9efff6c8cb4cc2def99d75d" + "commitHash": "787378879acfb212ed4ff824bf9f767a24a5cb43a" } }, "isOnlyProductionDependency": true, - "version": "12.14.1" + "version": "12.8.1" }, { "component": { @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "a822d2639a9c9c2c670e91d73f78e921865ce38e" + "commitHash": "5f93e889020d279d5a9cd1ecab080ab467312447" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "9.1.0" + "version": "7.3.2" }, { "component": { diff --git a/extensions/configuration-editing/schemas/attachContainer.schema.json b/extensions/configuration-editing/schemas/attachContainer.schema.json index da06cb1c9f..fc53bb896f 100644 --- a/extensions/configuration-editing/schemas/attachContainer.schema.json +++ b/extensions/configuration-editing/schemas/attachContainer.schema.json @@ -46,6 +46,15 @@ "errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." } }, + "userEnvProbe": { + "type": "string", + "enum": [ + "none", + "loginInteractiveShell", + "interactiveShell" + ], + "description": "User environment probe to run. The default is none." + }, "postAttachCommand": { "type": [ "string", diff --git a/extensions/configuration-editing/schemas/devContainer.schema.json b/extensions/configuration-editing/schemas/devContainer.schema.json index 596672dede..999a50e778 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.json @@ -92,6 +92,15 @@ "type": "integer", "description": "The port VS Code can use to connect to its backend." }, + "userEnvProbe": { + "type": "string", + "enum": [ + "none", + "loginInteractiveShell", + "interactiveShell" + ], + "description": "User environment probe to run. The default is none." + }, "codespaces": { "type": "object", "description": "Codespaces-specific configuration." diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index 16c9c8f4a0..a39a0136af 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -42,11 +42,11 @@ export class SettingsDocument { }); } - // sync.ignoredExtensions - if (location.path[0] === 'sync.ignoredExtensions') { + // settingsSync.ignoredExtensions + if (location.path[0] === 'settingsSync.ignoredExtensions') { let ignoredExtensions = []; try { - ignoredExtensions = parse(this.document.getText())['sync.ignoredExtensions']; + ignoredExtensions = parse(this.document.getText())['settingsSync.ignoredExtensions']; } catch (e) {/* ignore error */ } return provideInstalledExtensionProposals(ignoredExtensions, range, true); } @@ -223,7 +223,7 @@ export class SettingsDocument { if (location.path.length === 1 && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) { // Suggestion model word matching includes closed sqaure bracket and ending quote // Hence include them in the proposal to replace - let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position); + const range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position); return this.provideLanguageCompletionItemsForLanguageOverrides(location, range, language => `"[${language}]"`); } return Promise.resolve([]); diff --git a/extensions/docker/package.json b/extensions/docker/package.json index c1b91dc283..3af7727a6b 100644 --- a/extensions/docker/package.json +++ b/extensions/docker/package.json @@ -14,6 +14,7 @@ "id": "dockerfile", "extensions": [ ".dockerfile", ".containerfile" ], "filenames": [ "Dockerfile", "Containerfile" ], + "filenamePatterns": [ "Dockerfile.*", "Containerfile.*" ], "aliases": [ "Dockerfile", "Containerfile" ], "configuration": "./language-configuration.json" }], diff --git a/extensions/extension-editing/.vscodeignore b/extensions/extension-editing/.vscodeignore index 9d384dd906..de8e6dc591 100644 --- a/extensions/extension-editing/.vscodeignore +++ b/extensions/extension-editing/.vscodeignore @@ -3,4 +3,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +extension-browser.webpack.config.js +yarn.lock diff --git a/extensions/git/package.json b/extensions/git/package.json index d9df45a10b..748868778d 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -753,149 +753,49 @@ "group": "navigation", "when": "scmProvider == git" }, - { - "command": "git.sync", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.syncRebase", - "group": "1_sync", - "when": "scmProvider == git && gitState == idle" - }, - { - "command": "git.pull", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pullRebase", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pullFrom", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.push", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pushForce", - "group": "1_sync", - "when": "scmProvider == git && config.git.allowForcePush" - }, - { - "command": "git.pushTo", - "group": "1_sync", - "when": "scmProvider == git" - }, - { - "command": "git.pushToForce", - "group": "1_sync", - "when": "scmProvider == git && config.git.allowForcePush" - }, { "command": "git.checkout", - "group": "2_branch", + "group": "1_header", "when": "scmProvider == git" }, { - "command": "git.publish", - "group": "2_branch", + "command": "git.clone", + "group": "1_header", "when": "scmProvider == git" }, { - "command": "git.commitStaged", - "group": "4_commit", + "submenu": "git.commit", + "group": "2_main@1", "when": "scmProvider == git" }, { - "command": "git.commitStagedSigned", - "group": "4_commit", + "submenu": "git.changes", + "group": "2_main@2", "when": "scmProvider == git" }, { - "command": "git.commitStagedAmend", - "group": "4_commit", + "submenu": "git.pullpush", + "group": "2_main@3", "when": "scmProvider == git" }, { - "command": "git.commitAll", - "group": "4_commit", + "submenu": "git.branch", + "group": "2_main@4", "when": "scmProvider == git" }, { - "command": "git.commitAllSigned", - "group": "4_commit", + "submenu": "git.remotes", + "group": "2_main@5", "when": "scmProvider == git" }, { - "command": "git.commitAllAmend", - "group": "4_commit", - "when": "scmProvider == git" - }, - { - "command": "git.undoCommit", - "group": "4_commit", - "when": "scmProvider == git" - }, - { - "command": "git.stageAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.unstageAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.cleanAll", - "group": "5_stage", - "when": "scmProvider == git" - }, - { - "command": "git.stashIncludeUntracked", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stash", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashPop", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashPopLatest", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashApply", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashApplyLatest", - "group": "6_stash", - "when": "scmProvider == git" - }, - { - "command": "git.stashDrop", - "group": "6_stash", + "submenu": "git.stash", + "group": "2_main@6", "when": "scmProvider == git" }, { "command": "git.showOutput", - "group": "7_repository", + "group": "3_footer", "when": "scmProvider == git" } ], @@ -1307,8 +1207,184 @@ "group": "5_copy@2", "when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/" } + ], + "git.commit": [ + { + "command": "git.commit", + "group": "1_commit@1" + }, + { + "command": "git.commitStaged", + "group": "1_commit@2" + }, + { + "command": "git.commitAll", + "group": "1_commit@3" + }, + { + "command": "git.undoCommit", + "group": "1_commit@4" + }, + { + "command": "git.rebaseAbort", + "group": "1_commit@5" + }, + { + "command": "git.commitStagedAmend", + "group": "2_amend@1" + }, + { + "command": "git.commitAllAmend", + "group": "2_amend@1" + }, + { + "command": "git.commitStagedSigned", + "group": "3_signoff@1" + }, + { + "command": "git.commitAllSigned", + "group": "3_signoff@2" + } + ], + "git.changes": [ + { + "command": "git.stageAll" + }, + { + "command": "git.unstageAll" + }, + { + "command": "git.cleanAll" + } + ], + "git.pullpush": [ + { + "command": "git.sync", + "group": "1_sync" + }, + { + "command": "git.syncRebase", + "when": "gitState == idle", + "group": "1_sync" + }, + { + "command": "git.pull", + "group": "2_pull" + }, + { + "command": "git.pullRebase", + "group": "2_pull" + }, + { + "command": "git.pullFrom", + "group": "2_pull" + }, + { + "command": "git.push", + "group": "3_push" + }, + { + "command": "git.pushForce", + "when": "config.git.allowForcePush", + "group": "3_push" + }, + { + "command": "git.pushTo", + "group": "3_push" + }, + { + "command": "git.pushToForce", + "when": "config.git.allowForcePush", + "group": "3_push" + }, + { + "command": "git.fetch", + "group": "4_fetch" + }, + { + "command": "git.fetchPrune", + "group": "4_fetch" + }, + { + "command": "git.fetchAll", + "group": "4_fetch" + } + ], + "git.branch": [ + { + "command": "git.merge" + }, + { + "command": "git.branch" + }, + { + "command": "git.branchFrom" + }, + { + "command": "git.renameBranch" + }, + { + "command": "git.publish" + } + ], + "git.remotes": [ + { + "command": "git.addRemote" + }, + { + "command": "git.removeRemote" + } + ], + "git.stash": [ + { + "command": "git.stash" + }, + { + "command": "git.stashIncludeUntracked" + }, + { + "command": "git.stashApplyLatest" + }, + { + "command": "git.stashApply" + }, + { + "command": "git.stashPopLatest" + }, + { + "command": "git.stashPop" + }, + { + "command": "git.stashDrop" + } ] }, + "submenus": [ + { + "id": "git.commit", + "label": "%submenu.commit%" + }, + { + "id": "git.changes", + "label": "%submenu.changes%" + }, + { + "id": "git.pullpush", + "label": "%submenu.pullpush%" + }, + { + "id": "git.branch", + "label": "%submenu.branch%" + }, + { + "id": "git.remotes", + "label": "%submenu.remotes%" + }, + { + "id": "git.stash", + "label": "%submenu.stash%" + } + ], "configuration": { "title": "Git", "properties": { @@ -1425,6 +1501,11 @@ "description": "%config.ignoreMissingGitWarning%", "default": false }, + "git.ignoreWindowsGit27Warning": { + "type": "boolean", + "description": "%config.ignoreWindowsGit27Warning%", + "default": false + }, "git.ignoreLimitWarning": { "type": "boolean", "description": "%config.ignoreLimitWarning%", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 98d4ce4019..21364140df 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -99,6 +99,7 @@ "config.branchWhitespaceChar": "The character to replace whitespace in new branch names.", "config.ignoreLegacyWarning": "Ignores the legacy Git warning.", "config.ignoreMissingGitWarning": "Ignores the warning when Git is missing.", + "config.ignoreWindowsGit27Warning": "Ignores the warning when Git 2.25 - 2.26 is installed on Windows.", "config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository.", "config.defaultCloneDirectory": "The default location to clone a git repository.", "config.enableSmartCommit": "Commit all changes when there are no staged changes.", @@ -147,6 +148,14 @@ "config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.", "config.showCommitInput": "Controls whether to show the commit input in the Git source control panel.", "config.terminalAuthentication": "Controls whether to enable VS Code to be the authentication handler for git processes spawned in the integrated terminal. Note: terminals need to be restarted to pick up a change in this setting.", + "submenu.commit": "Commit", + "submenu.commit.amend": "Amend", + "submenu.commit.signoff": "Sign Off", + "submenu.changes": "Changes", + "submenu.pullpush": "Pull, Push", + "submenu.branch": "Branch", + "submenu.remotes": "Remote", + "submenu.stash": "Stash", "colors.added": "Color for added resources.", "colors.modified": "Color for modified resources.", "colors.deleted": "Color for deleted resources.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index ce80a053fc..8343bb9b38 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -543,11 +543,11 @@ export class CommandCenter { const uri = Uri.file(repositoryPath); if (openFolder) { - commands.executeCommand('vscode.openFolder', uri); + commands.executeCommand('vscode.openFolder', uri, { forceReuseWindow: true }); } else if (result === addToWorkspace) { workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri }); } else if (result === openNewWindow) { - commands.executeCommand('vscode.openFolder', uri, true); + commands.executeCommand('vscode.openFolder', uri, { forceNewWindow: true }); } } catch (err) { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 16ac8a51cc..4804ba3c81 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -209,14 +209,25 @@ async function checkGitWindows(info: IGit): Promise { return; } + const config = workspace.getConfiguration('git'); + const shouldIgnore = config.get('ignoreWindowsGit27Warning') === true; + + if (shouldIgnore) { + return; + } + const update = localize('updateGit', "Update Git"); + const neverShowAgain = localize('neverShowAgain', "Don't Show Again"); const choice = await window.showWarningMessage( localize('git2526', "There are known issues with the installed Git {0}. Please update to Git >= 2.27 for the git features to work correctly.", info.version), - update + update, + neverShowAgain ); if (choice === update) { commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/')); + } else if (choice === neverShowAgain) { + await config.update('ignoreWindowsGit27Warning', true, true); } } diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index 43bf093160..7b49689eb4 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -61,6 +61,15 @@ class SyncStatusBar { } constructor(private repository: Repository, private remoteSourceProviderRegistry: IRemoteSourceProviderRegistry) { + this._state = { + enabled: true, + isSyncRunning: false, + hasRemotes: false, + HEAD: undefined, + remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders() + .filter(p => !!p.publishRepository) + }; + repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables); repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables); @@ -70,15 +79,6 @@ class SyncStatusBar { const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync')); onEnablementChange(this.updateEnablement, this, this.disposables); this.updateEnablement(); - - this._state = { - enabled: true, - isSyncRunning: false, - hasRemotes: false, - HEAD: undefined, - remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders() - .filter(p => !!p.publishRepository) - }; } private updateEnablement(): void { diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index ad000b86a7..4c7b80e071 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -65,27 +65,32 @@ export class GitTimelineProvider implements TimelineProvider { readonly id = 'git-history'; readonly label = localize('git.timeline.source', 'Git History'); - private disposable: Disposable; + private readonly disposable: Disposable; + private providerDisposable: Disposable | undefined; private repo: Repository | undefined; private repoDisposable: Disposable | undefined; private repoStatusDate: Date | undefined; - constructor(private readonly _model: Model) { + constructor(private readonly model: Model) { this.disposable = Disposable.from( - _model.onDidOpenRepository(this.onRepositoriesChanged, this), - workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this), + model.onDidOpenRepository(this.onRepositoriesChanged, this), ); + + if (model.repositories.length) { + this.ensureProviderRegistration(); + } } dispose() { + this.providerDisposable?.dispose(); this.disposable.dispose(); } async provideTimeline(uri: Uri, options: TimelineOptions, _token: CancellationToken): Promise { // console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`); - const repo = this._model.getRepository(uri); + const repo = this.model.getRepository(uri); if (!repo) { this.repoDisposable?.dispose(); this.repoStatusDate = undefined; @@ -110,7 +115,7 @@ export class GitTimelineProvider implements TimelineProvider { let limit: number | undefined; if (options.limit !== undefined && typeof options.limit !== 'number') { try { - const result = await this._model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]); + const result = await this.model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.id}..`, '--', uri.fsPath]); if (!result.exitCode) { // Ask for 2 more (1 for the limit commit and 1 for the next commit) than so we can determine if there are more commits limit = Number(result.stdout) + 2; @@ -203,9 +208,17 @@ export class GitTimelineProvider implements TimelineProvider { }; } + private ensureProviderRegistration() { + if (this.providerDisposable === undefined) { + this.providerDisposable = workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this); + } + } + private onRepositoriesChanged(_repo: Repository) { // console.log(`GitTimelineProvider.onRepositoriesChanged`); + this.ensureProviderRegistration(); + // TODO@eamodio: Being naive for now and just always refreshing each time there is a new repository this.fireChanged(); } diff --git a/extensions/github-authentication/.vscodeignore b/extensions/github-authentication/.vscodeignore index ee85b88450..5f3350adfb 100644 --- a/extensions/github-authentication/.vscodeignore +++ b/extensions/github-authentication/.vscodeignore @@ -1,8 +1,10 @@ +.gitignore src/** !src/common/config.json out/** build/** extension.webpack.config.js +extension-browser.webpack.config.js tsconfig.json yarn.lock README.md diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 838c1de0b8..c64aa9b804 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -9,7 +9,7 @@ import { keychain } from './common/keychain'; import { GitHubServer, NETWORK_ERROR } from './githubServer'; import Logger from './common/logger'; -export const onDidChangeSessions = new vscode.EventEmitter(); +export const onDidChangeSessions = new vscode.EventEmitter(); interface SessionData { id: string; diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index 5e61d996f1..33cbd5c28e 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -79,7 +79,7 @@ export class GitHubServer { const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); if (this.isTestEnvironment(callbackUri)) { - const token = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true }); + const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); if (!token) { throw new Error('Sign in failed: No token provided'); } this.updateStatusBarItem(false); return token; diff --git a/extensions/github-browser/.gitignore b/extensions/github-browser/.gitignore deleted file mode 100644 index c19bd94aaa..0000000000 --- a/extensions/github-browser/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -out -node_modules diff --git a/extensions/github-browser/README.md b/extensions/github-browser/README.md deleted file mode 100644 index ef4d6f58e8..0000000000 --- a/extensions/github-browser/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# GitHub FileSystem for Visual Studio Code - -**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. - -## Features - -This extension provides remote GitHub repository features for VS Code. diff --git a/extensions/github-browser/extension.webpack.config.js b/extensions/github-browser/extension.webpack.config.js deleted file mode 100644 index 35b95ccffc..0000000000 --- a/extensions/github-browser/extension.webpack.config.js +++ /dev/null @@ -1,17 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. 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/extension.ts' - } -}); diff --git a/extensions/github-browser/package.json b/extensions/github-browser/package.json deleted file mode 100644 index 9938e25ed5..0000000000 --- a/extensions/github-browser/package.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "name": "github-browser", - "displayName": "%displayName%", - "description": "%description%", - "publisher": "vscode", - "version": "0.0.1", - "engines": { - "vscode": "^1.45.0" - }, - "enableProposedApi": true, - "private": true, - "categories": [ - "Other" - ], - "activationEvents": [ - "onFileSystem:codespace", - "onFileSystem:github", - "onCommand:githubBrowser.openRepository" - ], - "browser": "./dist/browser/extension.js", - "main": "./out/extension.js", - "contributes": { - "commands": [ - { - "command": "githubBrowser.openRepository", - "title": "Open GitHub Repository...", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.commit", - "title": "Commit", - "icon": "$(check)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.discardChanges", - "title": "Discard Changes", - "icon": "$(discard)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.openChanges", - "title": "Open Changes", - "icon": "$(git-compare)", - "category": "GitHub Browser" - }, - { - "command": "githubBrowser.openFile", - "title": "Open File", - "icon": "$(go-to-file)", - "category": "GitHub Browser" - } - ], - "menus": { - "commandPalette": [ - { - "command": "githubBrowser.openRepository", - "when": "config.githubBrowser.openRepository" - }, - { - "command": "githubBrowser.commit", - "when": "false" - }, - { - "command": "githubBrowser.discardChanges", - "when": "false" - }, - { - "command": "githubBrowser.openChanges", - "when": "false" - }, - { - "command": "githubBrowser.openFile", - "when": "false" - } - ], - "scm/title": [ - { - "command": "githubBrowser.commit", - "group": "navigation", - "when": "scmProvider == github" - } - ], - "scm/resourceState/context": [ - { - "command": "githubBrowser.openFile", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "inline@0" - }, - { - "command": "githubBrowser.discardChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "inline@1" - }, - { - "command": "githubBrowser.openChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "navigation@0" - }, - { - "command": "githubBrowser.openFile", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "navigation@1" - }, - { - "command": "githubBrowser.discardChanges", - "when": "scmProvider == github && scmResourceGroup == github.changes", - "group": "1_modification@0" - } - ] - }, - "resourceLabelFormatters": [ - { - "scheme": "github", - "authority": "HEAD", - "formatting": { - "label": "github.com${path}", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "github", - "authority": "*", - "formatting": { - "label": "github.com${path} (${authority})", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "codespace", - "authority": "HEAD", - "formatting": { - "label": "github.com${path}", - "separator": "/", - "workspaceSuffix": "GitHub" - } - }, - { - "scheme": "codespace", - "authority": "*", - "formatting": { - "label": "github.com${path} (${authority})", - "separator": "/", - "workspaceSuffix": "GitHub" - } - } - ] - }, - "scripts": { - "compile": "gulp compile-extension:github-browser", - "compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none", - "watch": "gulp watch-extension:github-browser", - "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose", - "vscode:prepublish": "npm run compile" - }, - "dependencies": { - "@octokit/graphql": "4.5.1", - "@octokit/rest": "18.0.0", - "fuzzysort": "1.1.4", - "node-fetch": "2.6.0", - "vscode-nls": "4.1.2" - }, - "devDependencies": { - "@types/node-fetch": "2.5.7" - } -} diff --git a/extensions/github-browser/package.nls.json b/extensions/github-browser/package.nls.json deleted file mode 100644 index 69f0f91177..0000000000 --- a/extensions/github-browser/package.nls.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "displayName": "GitHub Browser", - "description": "Remotely browse a GitHub repository" -} diff --git a/extensions/github-browser/src/changeStore.ts b/extensions/github-browser/src/changeStore.ts deleted file mode 100644 index 516eee7c38..0000000000 --- a/extensions/github-browser/src/changeStore.ts +++ /dev/null @@ -1,380 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { commands, Event, EventEmitter, FileStat, FileType, Memento, TextDocumentShowOptions, Uri, ViewColumn } from 'vscode'; -import { getRootUri, getRelativePath, isChild } from './extension'; -import { sha1 } from './sha1'; - -const textDecoder = new TextDecoder(); - -interface CreateOperation { - type: 'created'; - size: number; - timestamp: number; - uri: T; - hash: string; - originalHash: string; -} - -interface ChangeOperation { - type: 'changed'; - size: number; - timestamp: number; - uri: T; - hash: string; - originalHash: string; -} - -interface DeleteOperation { - type: 'deleted'; - size: undefined; - timestamp: number; - uri: T; - hash: undefined; - originalHash: undefined; -} - -export type Operation = CreateOperation | ChangeOperation | DeleteOperation; -type StoredOperation = CreateOperation | ChangeOperation | DeleteOperation; - -const workingOperationsKeyPrefix = 'github.working.changes|'; -const workingFileKeyPrefix = 'github.working|'; - -function fromSerialized(operations: StoredOperation): Operation { - return { ...operations, uri: Uri.parse(operations.uri) }; -} - -export interface ChangeStoreEvent { - type: 'created' | 'changed' | 'deleted'; - rootUri: Uri; - uri: Uri; -} - -function toChangeStoreEvent(operation: Operation | StoredOperation, rootUri: Uri, uri?: Uri): ChangeStoreEvent { - return { - type: operation.type, - rootUri: rootUri, - uri: uri ?? (typeof operation.uri === 'string' ? Uri.parse(operation.uri) : operation.uri), - }; -} - -export interface IChangeStore { - onDidChange: Event; - - acceptAll(rootUri: Uri): Promise; - discard(uri: Uri): Promise; - discardAll(rootUri: Uri): Promise; - - hasChanges(rootUri: Uri): boolean; - - getChanges(rootUri: Uri): Operation[]; - getContent(uri: Uri): string | undefined; - - openChanges(uri: Uri, original: Uri): void; - openFile(uri: Uri): void; -} - -export interface IWritableChangeStore { - onDidChange: Event; - - hasChanges(rootUri: Uri): boolean; - - getContent(uri: Uri): string | undefined; - getStat(uri: Uri): FileStat | undefined; - updateDirectoryEntries(uri: Uri, entries: [string, FileType][]): [string, FileType][]; - - onFileChanged(uri: Uri, content: Uint8Array, originalContent: () => Uint8Array | Thenable): Promise; - onFileCreated(uri: Uri, content: Uint8Array): Promise; - onFileDeleted(uri: Uri): Promise; -} - -export class ChangeStore implements IChangeStore, IWritableChangeStore { - private _onDidChange = new EventEmitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - constructor(private readonly memento: Memento) { } - - async acceptAll(rootUri: Uri): Promise { - const operations = this.getChanges(rootUri); - - await this.saveWorkingOperations(rootUri, undefined); - - const events: ChangeStoreEvent[] = []; - - for (const operation of operations) { - await this.discardWorkingContent(operation.uri); - events.push(toChangeStoreEvent(operation, rootUri)); - } - - for (const e of events) { - this._onDidChange.fire(e); - } - } - - async discard(uri: Uri): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - const index = operations.findIndex(c => c.uri === key); - if (index === -1) { - return; - } - - const [operation] = operations.splice(index, 1); - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - - this._onDidChange.fire({ - type: operation.type === 'created' ? 'deleted' : operation.type === 'deleted' ? 'created' : 'changed', - rootUri: rootUri, - uri: uri, - }); - } - - async discardAll(rootUri: Uri): Promise { - const operations = this.getChanges(rootUri); - - await this.saveWorkingOperations(rootUri, undefined); - - const events: ChangeStoreEvent[] = []; - - for (const operation of operations) { - await this.discardWorkingContent(operation.uri); - events.push(toChangeStoreEvent(operation, rootUri)); - } - - for (const e of events) { - this._onDidChange.fire(e); - } - } - - getChanges(rootUri: Uri) { - return this.getWorkingOperations(rootUri).map(c => fromSerialized(c)); - } - - getContent(uri: Uri): string | undefined { - return this.memento.get(`${workingFileKeyPrefix}${uri.toString()}`); - } - - getStat(uri: Uri): FileStat | undefined { - const key = uri.toString(); - const operation = this.getChanges(getRootUri(uri)!).find(c => c.uri.toString() === key); - if (operation === undefined) { - return undefined; - } - - return { - type: FileType.File, - size: operation.size ?? 0, - ctime: 0, - mtime: operation.timestamp - }; - } - - hasChanges(rootUri: Uri): boolean { - return this.getWorkingOperations(rootUri).length !== 0; - } - - updateDirectoryEntries(uri: Uri, entries: [string, FileType][]): [string, FileType][] { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return entries; - } - - const folderPath = getRelativePath(rootUri, uri); - - const operations = this.getChanges(rootUri); - for (const operation of operations) { - switch (operation.type) { - case 'changed': - continue; - - case 'created': { - const filePath = getRelativePath(rootUri, operation.uri); - if (isChild(folderPath, filePath)) { - entries.push([filePath, FileType.File]); - } - break; - } - - case 'deleted': { - const filePath = getRelativePath(rootUri, operation.uri); - if (isChild(folderPath, filePath)) { - const index = entries.findIndex(([path]) => path === filePath); - if (index !== -1) { - entries.splice(index, 1); - } - } - break; - } - } - } - - return entries; - } - - async onFileChanged(uri: Uri, content: Uint8Array, originalContent: () => Uint8Array | Thenable): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - const hash = await sha1(content); - - let operation = operations.find(c => c.uri === key); - if (operation === undefined) { - const originalHash = await sha1(await originalContent!()); - if (hash === originalHash) { - return; - } - - operation = { - type: 'changed', - size: content.byteLength, - timestamp: Date.now(), - uri: key, - hash: hash!, - originalHash: originalHash - } as ChangeOperation; - operations.push(operation); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } else if (hash! === operation.originalHash) { - operations.splice(operations.indexOf(operation), 1); - - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - } else if (operation.hash !== hash) { - operation.hash = hash!; - operation.timestamp = Date.now(); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async onFileCreated(uri: Uri, content: Uint8Array): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - const hash = await sha1(content); - - let operation = operations.find(c => c.uri === key); - if (operation === undefined) { - operation = { - type: 'created', - size: content.byteLength, - timestamp: Date.now(), - uri: key, - hash: hash!, - originalHash: hash! - } as CreateOperation; - operations.push(operation); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } else { - // Shouldn't happen, but if it does just update the contents - operation.hash = hash!; - operation.timestamp = Date.now(); - - await this.saveWorkingOperations(rootUri, operations); - await this.saveWorkingContent(uri, textDecoder.decode(content)); - } - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async onFileDeleted(uri: Uri): Promise { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return; - } - - const key = uri.toString(); - - const operations = this.getWorkingOperations(rootUri); - - let operation = operations.find(c => c.uri === key); - if (operation !== undefined) { - operations.splice(operations.indexOf(operation), 1); - } - - const wasCreated = operation?.type === 'created'; - - operation = { - type: 'deleted', - timestamp: Date.now(), - uri: key, - } as DeleteOperation; - - // Only track the delete, if we weren't tracking the create - if (!wasCreated) { - operations.push(operation); - } - - await this.saveWorkingOperations(rootUri, operations); - await this.discardWorkingContent(uri); - - this._onDidChange.fire(toChangeStoreEvent(operation, rootUri, uri)); - } - - async openChanges(uri: Uri, original: Uri) { - const opts: TextDocumentShowOptions = { - preserveFocus: false, - preview: true, - viewColumn: ViewColumn.Active - }; - - await commands.executeCommand('vscode.diff', original, uri, `${uri.fsPath} (Working Tree)`, opts); - } - - async openFile(uri: Uri) { - const opts: TextDocumentShowOptions = { - preserveFocus: false, - preview: false, - viewColumn: ViewColumn.Active - }; - - await commands.executeCommand('vscode.open', uri, opts); - } - - private getWorkingOperations(rootUri: Uri): StoredOperation[] { - return this.memento.get(`${workingOperationsKeyPrefix}${rootUri.toString()}`, []); - } - - private async saveWorkingOperations(rootUri: Uri, operations: StoredOperation[] | undefined): Promise { - await this.memento.update(`${workingOperationsKeyPrefix}${rootUri.toString()}`, operations); - } - - private async saveWorkingContent(uri: Uri, content: string): Promise { - await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, content); - } - - private async discardWorkingContent(uri: Uri): Promise { - await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, undefined); - } -} diff --git a/extensions/github-browser/src/contextStore.ts b/extensions/github-browser/src/contextStore.ts deleted file mode 100644 index f53d635dd2..0000000000 --- a/extensions/github-browser/src/contextStore.ts +++ /dev/null @@ -1,53 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { Event, EventEmitter, Memento, Uri, workspace } from 'vscode'; - -export interface WorkspaceFolderContext { - context: T; - name: string; - folderUri: Uri; -} - -export class ContextStore { - private _onDidChange = new EventEmitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - constructor( - private readonly scheme: string, - private readonly originalScheme: string, - private readonly memento: Memento, - ) { } - - delete(uri: Uri) { - return this.set(uri, undefined); - } - - get(uri: Uri): T | undefined { - return this.memento.get(`${this.originalScheme}.context|${this.getOriginalResource(uri).toString()}`); - } - - getForWorkspace(): WorkspaceFolderContext[] { - const folders = workspace.workspaceFolders?.filter(f => f.uri.scheme === this.scheme || f.uri.scheme === this.originalScheme) ?? []; - return folders.map(f => ({ context: this.get(f.uri)!, name: f.name, folderUri: f.uri })).filter(c => c.context !== undefined); - } - - async set(uri: Uri, context: T | undefined) { - uri = this.getOriginalResource(uri); - await this.memento.update(`${this.originalScheme}.context|${uri.toString()}`, context); - this._onDidChange.fire(uri); - } - - getOriginalResource(uri: Uri): Uri { - return uri.with({ scheme: this.originalScheme }); - } - - getWorkspaceResource(uri: Uri): Uri { - return uri.with({ scheme: this.scheme }); - } -} diff --git a/extensions/github-browser/src/extension.ts b/extensions/github-browser/src/extension.ts deleted file mode 100644 index d0f551b0c7..0000000000 --- a/extensions/github-browser/src/extension.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { commands, ExtensionContext, Uri, window, workspace } from 'vscode'; -import { ChangeStore } from './changeStore'; -import { ContextStore } from './contextStore'; -import { VirtualFS } from './fs'; -import { GitHubApiContext, GitHubApi } from './github/api'; -import { GitHubFS } from './github/fs'; -import { VirtualSCM } from './scm'; -import { StatusBar } from './statusbar'; - -const repositoryRegex = /^(?:(?:https:\/\/)?github.com\/)?([^\/]+)\/([^\/]+?)(?:\/|.git|$)/i; - -export async function activate(context: ExtensionContext) { - const contextStore = new ContextStore('codespace', GitHubFS.scheme, context.workspaceState); - const changeStore = new ChangeStore(context.workspaceState); - - const githubApi = new GitHubApi(contextStore); - const gitHubFS = new GitHubFS(githubApi); - const virtualFS = new VirtualFS('codespace', contextStore, changeStore, gitHubFS); - - context.subscriptions.push( - githubApi, - gitHubFS, - virtualFS, - new VirtualSCM(GitHubFS.scheme, githubApi, changeStore), - new StatusBar(contextStore, changeStore), - ); - - commands.registerCommand('githubBrowser.openRepository', async () => { - const value = await window.showInputBox({ - placeHolder: 'e.g. https://github.com/microsoft/vscode', - prompt: 'Enter a GitHub repository url', - validateInput: value => repositoryRegex.test(value) ? undefined : 'Invalid repository url' - }); - - if (value) { - const match = repositoryRegex.exec(value); - if (match) { - const [, owner, repo] = match; - - const uri = Uri.parse(`codespace://HEAD/${owner}/${repo}`); - openWorkspace(uri, repo, 'currentWindow'); - } - } - }); -} - -export function getRelativePath(rootUri: Uri, uri: Uri) { - return uri.path.substr(rootUri.path.length + 1); -} - -export function getRootUri(uri: Uri) { - return workspace.getWorkspaceFolder(uri)?.uri; -} - -export function isChild(folderPath: string, filePath: string) { - return isDescendent(folderPath, filePath) && filePath.substr(folderPath.length + (folderPath.endsWith('/') ? 0 : 1)).split('/').length === 1; -} - -export function isDescendent(folderPath: string, filePath: string) { - return folderPath.length === 0 || filePath.startsWith(folderPath.endsWith('/') ? folderPath : `${folderPath}/`); -} - -const shaRegex = /^[0-9a-f]{40}$/; -export function isSha(ref: string) { - return shaRegex.test(ref); -} - -function openWorkspace(uri: Uri, name: string, location: 'currentWindow' | 'newWindow' | 'addToCurrentWorkspace') { - if (location === 'addToCurrentWorkspace') { - const count = (workspace.workspaceFolders && workspace.workspaceFolders.length) || 0; - return workspace.updateWorkspaceFolders(count, 0, { uri: uri, name: name }); - } - - return commands.executeCommand('vscode.openFolder', uri, location === 'newWindow'); -} diff --git a/extensions/github-browser/src/fs.ts b/extensions/github-browser/src/fs.ts deleted file mode 100644 index 0a0ca250ee..0000000000 --- a/extensions/github-browser/src/fs.ts +++ /dev/null @@ -1,216 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { - CancellationToken, - Disposable, - Event, - EventEmitter, - FileChangeEvent, - FileChangeType, - FileSearchOptions, - FileSearchProvider, - FileSearchQuery, - FileStat, - FileSystemError, - FileSystemProvider, - FileType, - Progress, - TextSearchOptions, - TextSearchProvider, - TextSearchQuery, - TextSearchResult, - Uri, - workspace, -} from 'vscode'; -import { IWritableChangeStore } from './changeStore'; -import { ContextStore } from './contextStore'; -import { GitHubApiContext } from './github/api'; - -const emptyDisposable = { dispose: () => { /* noop */ } }; -const textEncoder = new TextEncoder(); - -export class VirtualFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable { - private _onDidChangeFile = new EventEmitter(); - get onDidChangeFile(): Event { - return this._onDidChangeFile.event; - } - - private readonly disposable: Disposable; - - constructor( - readonly scheme: string, - private readonly contextStore: ContextStore, - private readonly changeStore: IWritableChangeStore, - private readonly fs: FileSystemProvider & FileSearchProvider & TextSearchProvider - ) { - // TODO@eamodio listen for workspace folder changes - for (const context of contextStore.getForWorkspace()) { - // If we have a saved context, but no longer have any changes, reset the context - // We only do this on startup/reload to keep things consistent - if (!changeStore.hasChanges(context.folderUri)) { - console.log('Clear context', context.folderUri.toString()); - contextStore.delete(context.folderUri); - } - } - - this.disposable = Disposable.from( - workspace.registerFileSystemProvider(scheme, this, { isCaseSensitive: true }), - workspace.registerFileSearchProvider(scheme, this), - workspace.registerTextSearchProvider(scheme, this), - changeStore.onDidChange(e => { - switch (e.type) { - case 'created': - this._onDidChangeFile.fire([{ type: FileChangeType.Created, uri: e.uri }]); - break; - case 'changed': - this._onDidChangeFile.fire([{ type: FileChangeType.Changed, uri: e.uri }]); - break; - case 'deleted': - this._onDidChangeFile.fire([{ type: FileChangeType.Deleted, uri: e.uri }]); - break; - } - }), - ); - } - - dispose() { - this.disposable?.dispose(); - } - - private getOriginalResource(uri: Uri): Uri { - return this.contextStore.getOriginalResource(uri); - } - - private getWorkspaceResource(uri: Uri): Uri { - return this.contextStore.getWorkspaceResource(uri); - } - - //#region FileSystemProvider - - watch(): Disposable { - return emptyDisposable; - } - - async stat(uri: Uri): Promise { - let stat = this.changeStore.getStat(uri); - if (stat !== undefined) { - return stat; - } - - stat = await this.fs.stat(this.getOriginalResource(uri)); - return stat; - } - - async readDirectory(uri: Uri): Promise<[string, FileType][]> { - let entries = await this.fs.readDirectory(this.getOriginalResource(uri)); - entries = this.changeStore.updateDirectoryEntries(uri, entries); - return entries; - } - - createDirectory(_uri: Uri): void | Thenable { - // TODO@eamodio only support files for now - throw FileSystemError.NoPermissions(); - } - - async readFile(uri: Uri): Promise { - const content = this.changeStore.getContent(uri); - if (content !== undefined) { - return textEncoder.encode(content); - } - - const data = await this.fs.readFile(this.getOriginalResource(uri)); - return data; - } - - async writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): Promise { - let stat; - try { - stat = await this.stat(uri); - if (!options.overwrite) { - throw FileSystemError.FileExists(); - } - } catch (ex) { - if (ex instanceof FileSystemError && ex.code === 'FileNotFound') { - if (!options.create) { - throw FileSystemError.FileNotFound(); - } - } else { - throw ex; - } - } - - if (stat === undefined) { - await this.changeStore.onFileCreated(uri, content); - } else { - await this.changeStore.onFileChanged(uri, content, () => this.fs.readFile(this.getOriginalResource(uri))); - } - } - - async delete(uri: Uri, _options: { recursive: boolean }): Promise { - const stat = await this.stat(uri); - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - await this.changeStore.onFileDeleted(uri); - } - - async rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): Promise { - const stat = await this.stat(oldUri); - // TODO@eamodio only support files for now - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - const content = await this.readFile(oldUri); - await this.writeFile(newUri, content, { create: true, overwrite: options.overwrite }); - await this.delete(oldUri, { recursive: false }); - } - - async copy(source: Uri, destination: Uri, options: { overwrite: boolean }): Promise { - const stat = await this.stat(source); - // TODO@eamodio only support files for now - if (stat.type !== FileType.File) { - throw FileSystemError.NoPermissions(); - } - - const content = await this.readFile(source); - await this.writeFile(destination, content, { create: true, overwrite: options.overwrite }); - } - - //#endregion - - //#region FileSearchProvider - - provideFileSearchResults( - query: FileSearchQuery, - options: FileSearchOptions, - token: CancellationToken, - ) { - return this.fs.provideFileSearchResults(query, { ...options, folder: this.getOriginalResource(options.folder) }, token); - } - - //#endregion - - //#region TextSearchProvider - - provideTextSearchResults( - query: TextSearchQuery, - options: TextSearchOptions, - progress: Progress, - token: CancellationToken, - ) { - return this.fs.provideTextSearchResults( - query, - { ...options, folder: this.getOriginalResource(options.folder) }, - { report: (result: TextSearchResult) => progress.report({ ...result, uri: this.getWorkspaceResource(result.uri) }) }, - token - ); - } - - //#endregion -} diff --git a/extensions/github-browser/src/gate.ts b/extensions/github-browser/src/gate.ts deleted file mode 100644 index 86f8c6dd52..0000000000 --- a/extensions/github-browser/src/gate.ts +++ /dev/null @@ -1,87 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -const emptyStr = ''; - -function defaultResolver(...args: any[]): string { - if (args.length === 1) { - const arg0 = args[0]; - if (arg0 === undefined || arg0 === null) { - return emptyStr; - } - if (typeof arg0 === 'string') { - return arg0; - } - if (typeof arg0 === 'number' || typeof arg0 === 'boolean') { - return String(arg0); - } - - return JSON.stringify(arg0); - } - - return JSON.stringify(args); -} - -function iPromise(obj: T | Promise): obj is Promise { - return typeof (obj as Promise)?.then === 'function'; -} - -export function gate any>(resolver?: (...args: Parameters) => string) { - return (_target: any, key: string, descriptor: PropertyDescriptor) => { - let fn: Function | undefined; - if (typeof descriptor.value === 'function') { - fn = descriptor.value; - } else if (typeof descriptor.get === 'function') { - fn = descriptor.get; - } - if (fn === undefined || fn === null) { - throw new Error('Not supported'); - } - - const gateKey = `$gate$${key}`; - - descriptor.value = function (this: any, ...args: any[]) { - const prop = - args.length === 0 ? gateKey : `${gateKey}$${(resolver ?? defaultResolver)(...(args as Parameters))}`; - - if (!Object.prototype.hasOwnProperty.call(this, prop)) { - Object.defineProperty(this, prop, { - configurable: false, - enumerable: false, - writable: true, - value: undefined, - }); - } - - let promise = this[prop]; - if (promise === undefined) { - let result; - try { - result = fn!.apply(this, args); - if (result === undefined || fn === null || !iPromise(result)) { - return result; - } - - this[prop] = promise = result - .then((r: any) => { - this[prop] = undefined; - return r; - }) - .catch(ex => { - this[prop] = undefined; - throw ex; - }); - } catch (ex) { - this[prop] = undefined; - throw ex; - } - } - - return promise; - }; - }; -} diff --git a/extensions/github-browser/src/github/api.ts b/extensions/github-browser/src/github/api.ts deleted file mode 100644 index 186eb1a223..0000000000 --- a/extensions/github-browser/src/github/api.ts +++ /dev/null @@ -1,504 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { authentication, AuthenticationSession, Disposable, Event, EventEmitter, Range, Uri } from 'vscode'; -import { graphql } from '@octokit/graphql'; -import { Octokit } from '@octokit/rest'; -import { ContextStore } from '../contextStore'; -import { fromGitHubUri } from './fs'; -import { isSha } from '../extension'; -import { Iterables } from '../iterables'; - -export interface GitHubApiContext { - requestRef: string; - - branch: string; - sha: string | undefined; - timestamp: number; -} - -interface CreateCommitOperation { - type: 'created'; - path: string; - content: string -} - -interface ChangeCommitOperation { - type: 'changed'; - path: string; - content: string -} - -interface DeleteCommitOperation { - type: 'deleted'; - path: string; - content: undefined -} - -export type CommitOperation = CreateCommitOperation | ChangeCommitOperation | DeleteCommitOperation; - -type ArrayElement> = T extends (infer U)[] ? U : never; -type GitCreateTreeParamsTree = ArrayElement[0]>['tree']>; - -function getGitHubRootUri(uri: Uri) { - const rootIndex = uri.path.indexOf('/', uri.path.indexOf('/', 1) + 1); - return uri.with({ - path: uri.path.substring(0, rootIndex === -1 ? undefined : rootIndex), - query: '' - }); -} - -export class GitHubApi implements Disposable { - private _onDidChangeContext = new EventEmitter(); - get onDidChangeContext(): Event { - return this._onDidChangeContext.event; - } - - private readonly disposable: Disposable; - - constructor(private readonly context: ContextStore) { - this.disposable = Disposable.from( - context.onDidChange(e => this._onDidChangeContext.fire(e)) - ); - } - - dispose() { - this.disposable.dispose(); - } - - private _session: AuthenticationSession | undefined; - async ensureAuthenticated() { - if (this._session === undefined) { - const providers = await authentication.getProviderIds(); - if (!providers.includes('github')) { - await new Promise(resolve => { - authentication.onDidChangeAuthenticationProviders(e => { - if (e.added.find(provider => provider.id === 'github')) { - resolve(); - } - }); - }); - } - - this._session = await authentication.getSession('github', ['repo'], { createIfNone: true }); - } - - return this._session; - } - - private _graphql: typeof graphql | undefined; - private async graphql() { - if (this._graphql === undefined) { - const session = await this.ensureAuthenticated(); - this._graphql = graphql.defaults({ - headers: { - Authorization: `Bearer ${session.accessToken}`, - } - }); - } - - return this._graphql; - } - - private _octokit: typeof Octokit | undefined; - private async octokit(options?: ConstructorParameters[0]) { - if (this._octokit === undefined) { - const session = await this.ensureAuthenticated(); - this._octokit = Octokit.defaults({ auth: `token ${session.accessToken}` }); - } - return new this._octokit(options); - } - - async commit(rootUri: Uri, message: string, operations: CommitOperation[]): Promise { - const { owner, repo } = fromGitHubUri(rootUri); - - try { - const context = await this.getContext(rootUri); - if (context.sha === undefined) { - throw new Error(`Cannot commit to Uri(${rootUri.toString(true)}); Invalid context sha`); - } - - const hasDeletes = operations.some(op => op.type === 'deleted'); - - const github = await this.octokit(); - const treeResp = await github.git.getTree({ - owner: owner, - repo: repo, - tree_sha: context.sha, - recursive: hasDeletes ? 'true' : undefined, - }); - - // 0100000000000000 (040000): Directory - // 1000000110100100 (100644): Regular non-executable file - // 1000000110110100 (100664): Regular non-executable group-writeable file - // 1000000111101101 (100755): Regular executable file - // 1010000000000000 (120000): Symbolic link - // 1110000000000000 (160000): Gitlink - let updatedTree: GitCreateTreeParamsTree[]; - - if (hasDeletes) { - updatedTree = treeResp.data.tree as GitCreateTreeParamsTree[]; - - for (const operation of operations) { - switch (operation.type) { - case 'created': - updatedTree.push({ path: operation.path, mode: '100644', type: 'blob', content: operation.content }); - break; - - case 'changed': { - const index = updatedTree.findIndex(item => item.path === operation.path); - if (index !== -1) { - const { path, mode, type } = updatedTree[index]; - updatedTree.splice(index, 1, { path: path, mode: mode, type: type, content: operation.content }); - } - break; - } - case 'deleted': { - const index = updatedTree.findIndex(item => item.path === operation.path); - if (index !== -1) { - updatedTree.splice(index, 1); - } - break; - } - } - } - } else { - updatedTree = []; - - for (const operation of operations) { - switch (operation.type) { - case 'created': - updatedTree.push({ path: operation.path, mode: '100644', type: 'blob', content: operation.content }); - break; - - case 'changed': - const item = treeResp.data.tree.find(item => item.path === operation.path) as GitCreateTreeParamsTree; - if (item !== undefined) { - const { path, mode, type } = item; - updatedTree.push({ path: path, mode: mode, type: type, content: operation.content }); - } - break; - } - } - } - - const updatedTreeResp = await github.git.createTree({ - owner: owner, - repo: repo, - base_tree: hasDeletes ? undefined : treeResp.data.sha, - tree: updatedTree - }); - - const resp = await github.git.createCommit({ - owner: owner, - repo: repo, - message: message, - tree: updatedTreeResp.data.sha, - parents: [context.sha] - }); - - this.updateContext(rootUri, { ...context, sha: resp.data.sha, timestamp: Date.now() }); - - // TODO@eamodio need to send a file change for any open files - - await github.git.updateRef({ - owner: owner, - repo: repo, - ref: `heads/${context.branch}`, - sha: resp.data.sha - }); - - return resp.data.sha; - } catch (ex) { - console.log(ex); - throw ex; - } - } - - async defaultBranchQuery(uri: Uri) { - const { owner, repo } = fromGitHubUri(uri); - - try { - const query = `query defaultBranch($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - defaultBranchRef { - name - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { defaultBranchRef: { name: string; target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - }); - return rsp?.repository?.defaultBranchRef?.name ?? undefined; - } catch (ex) { - return undefined; - } - } - - async filesQuery(uri: Uri) { - const { owner, repo, ref } = fromGitHubUri(uri); - - try { - const context = await this.getContext(uri); - - const resp = await (await this.octokit()).git.getTree({ - owner: owner, - repo: repo, - recursive: '1', - tree_sha: context?.sha ?? ref, - }); - return Iterables.filterMap(resp.data.tree, p => p.type === 'blob' ? p.path : undefined); - } catch (ex) { - return []; - } - } - - async fsQuery(uri: Uri, innerQuery: string): Promise { - const { owner, repo, path, ref } = fromGitHubUri(uri); - - try { - const context = await this.getContext(uri); - - const query = `query fs($owner: String!, $repo: String!, $path: String) { - repository(owner: $owner, name: $repo) { - object(expression: $path) { - ${innerQuery} - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { object: T | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - path: `${context.sha ?? ref}:${path}`, - }); - return rsp?.repository?.object ?? undefined; - } catch (ex) { - return undefined; - } - } - - async latestCommitQuery(uri: Uri) { - const { owner, repo, ref } = fromGitHubUri(uri); - - try { - if (ref === 'HEAD') { - const query = `query latest($owner: String!, $repo: String!) { - repository(owner: $owner, name: $repo) { - defaultBranchRef { - target { - oid - } - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { defaultBranchRef: { name: string; target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - }); - return rsp?.repository?.defaultBranchRef?.target.oid ?? undefined; - } - - const query = `query latest($owner: String!, $repo: String!, $ref: String!) { - repository(owner: $owner, name: $repo) { - ref(qualifiedName: $ref) { - target { - oid - } - } - } -}`; - - const rsp = await this.gqlQuery<{ - repository: { ref: { target: { oid: string } } | null | undefined }; - }>(query, { - owner: owner, - repo: repo, - ref: ref ?? 'HEAD', - }); - return rsp?.repository?.ref?.target.oid ?? undefined; - } catch (ex) { - return undefined; - } - } - - async searchQuery( - query: string, - uri: Uri, - options: { maxResults?: number; context?: { before?: number; after?: number } }, - ): Promise { - const { owner, repo, ref } = fromGitHubUri(uri); - - // If we have a specific ref, don't try to search, because GitHub search only works against the default branch - if (ref !== 'HEAD') { - return { matches: [], limitHit: true }; - } - - try { - const resp = await (await this.octokit({ - request: { - headers: { - accept: 'application/vnd.github.v3.text-match+json', - }, - } - })).search.code({ - q: `${query} repo:${owner}/${repo}`, - }); - - // Since GitHub doesn't return ANY line numbers just fake it at the top of the file 😢 - const range = new Range(0, 0, 0, 0); - - const matches: SearchQueryMatch[] = []; - - let counter = 0; - let match: SearchQueryMatch; - for (const item of resp.data.items) { - for (const m of (item as typeof item & { text_matches: GitHubSearchTextMatch[] }).text_matches) { - counter++; - if (options.maxResults !== undefined && counter > options.maxResults) { - return { matches: matches, limitHit: true }; - } - - match = { - path: item.path, - ranges: [], - preview: m.fragment, - matches: [], - }; - - for (const lm of m.matches) { - let line = 0; - let shartChar = 0; - let endChar = 0; - for (let i = 0; i < lm.indices[1]; i++) { - if (i === lm.indices[0]) { - shartChar = endChar; - } - - if (m.fragment[i] === '\n') { - line++; - endChar = 0; - } else { - endChar++; - } - } - - match.ranges.push(range); - match.matches.push(new Range(line, shartChar, line, endChar)); - } - - matches.push(match); - } - } - - return { matches: matches, limitHit: false }; - } catch (ex) { - return { matches: [], limitHit: true }; - } - } - - private async gqlQuery(query: string, variables: { [key: string]: string | number }): Promise { - return (await this.graphql())(query, variables); - } - - private readonly pendingContextRequests = new Map>(); - async getContext(uri: Uri): Promise { - const rootUri = getGitHubRootUri(uri); - - let pending = this.pendingContextRequests.get(rootUri.toString()); - if (pending === undefined) { - pending = this.getContextCore(rootUri); - this.pendingContextRequests.set(rootUri.toString(), pending); - } - - try { - return await pending; - } finally { - this.pendingContextRequests.delete(rootUri.toString()); - } - } - - private readonly rootUriToContextMap = new Map(); - - private async getContextCore(rootUri: Uri): Promise { - const key = rootUri.toString(); - let context = this.rootUriToContextMap.get(key); - - // Check if we have a cached a context - if (context?.sha !== undefined) { - return context; - } - - // Check if we have a saved context - context = this.context.get(rootUri); - if (context?.sha !== undefined) { - this.rootUriToContextMap.set(key, context); - - return context; - } - - const { ref } = fromGitHubUri(rootUri); - - // If the requested ref looks like a sha, then use it - if (isSha(ref)) { - context = { requestRef: ref, branch: ref, sha: ref, timestamp: Date.now() }; - } else { - let branch; - if (ref === 'HEAD') { - branch = await this.defaultBranchQuery(rootUri); - if (branch === undefined) { - throw new Error(`Cannot get context for Uri(${rootUri.toString(true)}); unable to get default branch`); - } - } else { - branch = ref; - } - - // Query for the latest sha for the give ref - const sha = await this.latestCommitQuery(rootUri); - context = { requestRef: ref, branch: branch, sha: sha, timestamp: Date.now() }; - } - - this.updateContext(rootUri, context); - - return context; - } - - private updateContext(rootUri: Uri, context: GitHubApiContext) { - this.rootUriToContextMap.set(rootUri.toString(), context); - this.context.set(rootUri, context); - } -} - -interface GitHubSearchTextMatch { - object_url: string; - object_type: string; - property: string; - fragment: string; - matches: { - text: string; - indices: number[]; - }[]; -} - -interface SearchQueryMatch { - path: string; - ranges: Range[]; - preview: string; - matches: Range[]; -} - -interface SearchQueryResults { - matches: SearchQueryMatch[]; - limitHit: boolean; -} diff --git a/extensions/github-browser/src/github/fs.ts b/extensions/github-browser/src/github/fs.ts deleted file mode 100644 index 389f3cc00e..0000000000 --- a/extensions/github-browser/src/github/fs.ts +++ /dev/null @@ -1,332 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { - CancellationToken, - Disposable, - Event, - EventEmitter, - FileChangeEvent, - FileSearchOptions, - FileSearchProvider, - FileSearchQuery, - FileStat, - FileSystemError, - FileSystemProvider, - FileType, - Progress, - TextSearchComplete, - TextSearchOptions, - TextSearchProvider, - TextSearchQuery, - TextSearchResult, - Uri, - workspace, -} from 'vscode'; -import * as fuzzySort from 'fuzzysort'; -import fetch from 'node-fetch'; -import { GitHubApi } from './api'; -import { Iterables } from '../iterables'; -import { getRootUri } from '../extension'; - -const emptyDisposable = { dispose: () => { /* noop */ } }; -const replaceBackslashRegex = /(\/|\\)/g; -const textEncoder = new TextEncoder(); - -interface Fuzzysort extends Fuzzysort.Fuzzysort { - prepareSlow(target: string): Fuzzysort.Prepared; - cleanup(): void; -} - -export class GitHubFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable { - static scheme = 'github'; - - private _onDidChangeFile = new EventEmitter(); - get onDidChangeFile(): Event { - return this._onDidChangeFile.event; - } - - private readonly disposable: Disposable; - private fsCache = new Map>(); - - constructor(private readonly github: GitHubApi) { - this.disposable = Disposable.from( - workspace.registerFileSystemProvider(GitHubFS.scheme, this, { - isCaseSensitive: true, - isReadonly: true - }), - workspace.registerFileSearchProvider(GitHubFS.scheme, this), - workspace.registerTextSearchProvider(GitHubFS.scheme, this), - github.onDidChangeContext(e => this.fsCache.delete(e.toString())) - ); - } - - dispose() { - this.disposable?.dispose(); - } - - private getCache(uri: Uri) { - const rootUri = getRootUri(uri); - if (rootUri === undefined) { - return undefined; - } - - let cache = this.fsCache.get(rootUri.toString()); - if (cache === undefined) { - cache = new Map(); - this.fsCache.set(rootUri.toString(), cache); - } - return cache; - } - - //#region FileSystemProvider - - watch(): Disposable { - return emptyDisposable; - } - - async stat(uri: Uri): Promise { - if (uri.path === '' || uri.path.lastIndexOf('/') === 0) { - const context = await this.github.getContext(uri); - return { type: FileType.Directory, size: 0, ctime: 0, mtime: context?.timestamp }; - } - - const data = await this.fsQuery<{ - __typename: string; - byteSize: number | undefined; - }>( - uri, - `__typename - ...on Blob { - byteSize - }`, - this.getCache(uri), - ); - - if (data === undefined) { - throw FileSystemError.FileNotFound(); - } - - const context = await this.github.getContext(uri); - - return { - type: typenameToFileType(data.__typename), - size: data.byteSize ?? 0, - ctime: 0, - mtime: context?.timestamp, - }; - } - - async readDirectory(uri: Uri): Promise<[string, FileType][]> { - const data = await this.fsQuery<{ - entries: { name: string; type: string }[]; - }>( - uri, - `... on Tree { - entries { - name - type - } - }`, - this.getCache(uri), - ); - - return (data?.entries ?? []).map<[string, FileType]>(e => [ - e.name, - typenameToFileType(e.type), - ]); - } - - createDirectory(_uri: Uri): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - async readFile(uri: Uri): Promise { - const data = await this.fsQuery<{ - oid: string; - isBinary: boolean; - text: string; - }>( - uri, - `... on Blob { - oid, - isBinary, - text - }`, - ); - - if (data?.isBinary) { - const { owner, repo, path } = fromGitHubUri(uri); - // e.g. https://raw.githubusercontent.com/eamodio/vscode-gitlens/HEAD/images/gitlens-icon.png - const downloadUri = uri.with({ - scheme: 'https', - authority: 'raw.githubusercontent.com', - path: `/${owner}/${repo}/HEAD/${path}`, - }); - - return downloadBinary(downloadUri); - } - - return textEncoder.encode(data?.text ?? ''); - } - - async writeFile(_uri: Uri, _content: Uint8Array, _options: { create: boolean, overwrite: boolean }): Promise { - throw FileSystemError.NoPermissions(); - } - - delete(_uri: Uri, _options: { recursive: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - rename(_oldUri: Uri, _newUri: Uri, _options: { overwrite: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - copy(_source: Uri, _destination: Uri, _options: { overwrite: boolean }): void | Thenable { - throw FileSystemError.NoPermissions(); - } - - //#endregion - - //#region FileSearchProvider - - private fileSearchCache = new Map(); - - async provideFileSearchResults( - query: FileSearchQuery, - options: FileSearchOptions, - token: CancellationToken, - ): Promise { - let searchable = this.fileSearchCache.get(options.folder.toString(true)); - if (searchable === undefined) { - const matches = await this.github.filesQuery(options.folder); - if (matches === undefined || token.isCancellationRequested) { - return []; - } - - searchable = [...Iterables.map(matches, m => (fuzzySort as Fuzzysort).prepareSlow(m))]; - this.fileSearchCache.set(options.folder.toString(true), searchable); - } - - if (options.maxResults === undefined || options.maxResults === 0 || options.maxResults >= searchable.length) { - const results = searchable.map(m => Uri.joinPath(options.folder, m.target)); - return results; - } - - const results = fuzzySort - .go(query.pattern.replace(replaceBackslashRegex, '/'), searchable, { - allowTypo: true, - limit: options.maxResults, - }) - .map(m => Uri.joinPath(options.folder, m.target)); - - (fuzzySort as Fuzzysort).cleanup(); - - return results; - } - - //#endregion - - //#region TextSearchProvider - - async provideTextSearchResults( - query: TextSearchQuery, - options: TextSearchOptions, - progress: Progress, - _token: CancellationToken, - ): Promise { - const results = await this.github.searchQuery( - query.pattern, - options.folder, - { maxResults: options.maxResults, context: { before: options.beforeContext, after: options.afterContext } }, - ); - if (results === undefined) { return { limitHit: true }; } - - let uri; - for (const m of results.matches) { - uri = Uri.joinPath(options.folder, m.path); - - progress.report({ - uri: uri, - ranges: m.ranges, - preview: { - text: m.preview, - matches: m.matches, - }, - }); - } - - return { limitHit: false }; - } - - //#endregion - - private async fsQuery(uri: Uri, query: string, cache?: Map): Promise { - const key = `${uri.toString()}:${getHashCode(query)}`; - - let data = cache?.get(key); - if (data !== undefined) { - return data as T; - } - - data = await this.github.fsQuery(uri, query); - cache?.set(key, data); - return data; - } -} - -async function downloadBinary(uri: Uri) { - const resp = await fetch(uri.toString()); - const array = new Uint8Array(await resp.arrayBuffer()); - return array; -} - -function typenameToFileType(typename: string | undefined | null) { - if (typename) { - typename = typename.toLocaleLowerCase(); - } - - switch (typename) { - case 'blob': - return FileType.File; - case 'tree': - return FileType.Directory; - default: - return FileType.Unknown; - } -} - -type RepoInfo = { owner: string; repo: string; path: string | undefined; ref: string }; -export function fromGitHubUri(uri: Uri): RepoInfo { - const [, owner, repo, ...rest] = uri.path.split('/'); - - let ref; - if (uri.authority) { - ref = uri.authority; - // The casing of HEAD is important for the GitHub api to work - if (/HEAD/i.test(ref)) { - ref = 'HEAD'; - } - } - return { owner: owner, repo: repo, path: rest.join('/'), ref: ref ?? 'HEAD' }; -} - -function getHashCode(s: string): number { - let hash = 0; - - if (s.length === 0) { - return hash; - } - - let char; - const len = s.length; - for (let i = 0; i < len; i++) { - char = s.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash |= 0; // Convert to 32bit integer - } - return hash; -} diff --git a/extensions/github-browser/src/iterables.ts b/extensions/github-browser/src/iterables.ts deleted file mode 100644 index 502750caf9..0000000000 --- a/extensions/github-browser/src/iterables.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -export namespace Iterables { - export function* filterMap( - source: Iterable | IterableIterator, - predicateMapper: (item: T) => TMapped | undefined | null, - ): Iterable { - for (const item of source) { - const mapped = predicateMapper(item); - if (mapped !== undefined && mapped !== null) { - yield mapped; - } - } - } - - export function* map( - source: Iterable | IterableIterator, - mapper: (item: T) => TMapped, - ): Iterable { - for (const item of source) { - yield mapper(item); - } - } -} diff --git a/extensions/github-browser/src/scm.ts b/extensions/github-browser/src/scm.ts deleted file mode 100644 index ce0519d935..0000000000 --- a/extensions/github-browser/src/scm.ts +++ /dev/null @@ -1,177 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { CancellationToken, commands, Disposable, scm, SourceControl, SourceControlResourceGroup, SourceControlResourceState, Uri, window, workspace } from 'vscode'; -import * as nls from 'vscode-nls'; -import { IChangeStore } from './changeStore'; -import { GitHubApi, CommitOperation } from './github/api'; -import { getRelativePath } from './extension'; - -const localize = nls.loadMessageBundle(); - -interface ScmProvider { - sourceControl: SourceControl, - groups: SourceControlResourceGroup[] -} - -export class VirtualSCM implements Disposable { - private readonly providers: ScmProvider[] = []; - - private disposable: Disposable; - - constructor( - private readonly originalScheme: string, - private readonly github: GitHubApi, - private readonly changeStore: IChangeStore, - ) { - this.registerCommands(); - - // TODO@eamodio listen for workspace folder changes - for (const folder of workspace.workspaceFolders ?? []) { - this.createScmProvider(folder.uri, folder.name); - - for (const operation of changeStore.getChanges(folder.uri)) { - this.update(folder.uri, operation.uri); - } - } - - this.disposable = Disposable.from( - changeStore.onDidChange(e => this.update(e.rootUri, e.uri)), - ); - } - - dispose() { - this.disposable.dispose(); - } - - private registerCommands() { - commands.registerCommand('githubBrowser.commit', (sourceControl: SourceControl | undefined) => { - // TODO@eamodio remove this hack once I figure out why the args are missing - if (sourceControl === undefined && this.providers.length === 1) { - sourceControl = this.providers[0].sourceControl; - } - - if (sourceControl === undefined) { - return; - } - - this.commitChanges(sourceControl); - }); - - commands.registerCommand('githubBrowser.discardChanges', (resourceState: SourceControlResourceState) => - this.discardChanges(resourceState.resourceUri) - ); - - commands.registerCommand('githubBrowser.openChanges', (resourceState: SourceControlResourceState) => - this.openChanges(resourceState.resourceUri) - ); - - commands.registerCommand('githubBrowser.openFile', (resourceState: SourceControlResourceState) => - this.openFile(resourceState.resourceUri) - ); - } - - async commitChanges(sourceControl: SourceControl): Promise { - const operations = this.changeStore - .getChanges(sourceControl.rootUri!) - .map(operation => { - const path = getRelativePath(sourceControl.rootUri!, operation.uri); - switch (operation.type) { - case 'created': - return { type: operation.type, path: path, content: this.changeStore.getContent(operation.uri)! }; - case 'changed': - return { type: operation.type, path: path, content: this.changeStore.getContent(operation.uri)! }; - case 'deleted': - return { type: operation.type, path: path }; - } - }); - if (!operations.length) { - window.showInformationMessage(localize('no changes', "There are no changes to commit.")); - - return; - } - - const message = sourceControl.inputBox.value; - if (message) { - const sha = await this.github.commit(this.getOriginalResource(sourceControl.rootUri!), message, operations); - if (sha !== undefined) { - this.changeStore.acceptAll(sourceControl.rootUri!); - sourceControl.inputBox.value = ''; - } - } - } - - discardChanges(uri: Uri): Promise { - return this.changeStore.discard(uri); - } - - openChanges(uri: Uri) { - return this.changeStore.openChanges(uri, this.getOriginalResource(uri)); - } - - openFile(uri: Uri) { - return this.changeStore.openFile(uri); - } - - private update(rootUri: Uri, uri: Uri) { - const folder = workspace.getWorkspaceFolder(uri); - if (folder === undefined) { - return; - } - - const provider = this.createScmProvider(rootUri, folder.name); - const group = this.createChangesGroup(provider); - group.resourceStates = this.changeStore.getChanges(rootUri).map(op => { - const rs: SourceControlResourceState = { - decorations: { - strikeThrough: op.type === 'deleted' - }, - resourceUri: op.uri, - command: { - command: 'githubBrowser.openChanges', - title: 'Open Changes', - } - }; - rs.command!.arguments = [rs]; - return rs; - }); - } - - private createScmProvider(rootUri: Uri, name: string) { - let provider = this.providers.find(sc => sc.sourceControl.rootUri?.toString() === rootUri.toString()); - if (provider === undefined) { - const sourceControl = scm.createSourceControl('github', name, rootUri); - sourceControl.quickDiffProvider = { provideOriginalResource: uri => this.getOriginalResource(uri) }; - sourceControl.acceptInputCommand = { - command: 'githubBrowser.commit', - title: 'Commit', - arguments: [sourceControl] - }; - sourceControl.inputBox.placeholder = `Message (Ctrl+Enter to commit '${name}')`; - // sourceControl.inputBox.validateInput = value => value ? undefined : 'Invalid commit message'; - - provider = { sourceControl: sourceControl, groups: [] }; - this.createChangesGroup(provider); - this.providers.push(provider); - } - - return provider; - } - - private createChangesGroup(provider: ScmProvider) { - let group = provider.groups.find(g => g.id === 'github.changes'); - if (group === undefined) { - group = provider.sourceControl.createResourceGroup('github.changes', 'Changes'); - provider.groups.push(group); - } - - return group; - } - - private getOriginalResource(uri: Uri, _token?: CancellationToken): Uri { - return uri.with({ scheme: this.originalScheme }); - } -} diff --git a/extensions/github-browser/src/sha1.ts b/extensions/github-browser/src/sha1.ts deleted file mode 100644 index a786fcf24d..0000000000 --- a/extensions/github-browser/src/sha1.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -const textDecoder = new TextDecoder(); -const textEncoder = new TextEncoder(); - -declare let WEBWORKER: boolean; - -export async function sha1(s: string | Uint8Array): Promise { - while (true) { - try { - if (WEBWORKER) { - const hash = await globalThis.crypto.subtle.digest({ name: 'sha-1' }, typeof s === 'string' ? textEncoder.encode(s) : s); - // Use encodeURIComponent to avoid issues with btoa and Latin-1 characters - return globalThis.btoa(encodeURIComponent(textDecoder.decode(hash))); - } else { - return (await import('crypto')).createHash('sha1').update(s).digest('base64'); - } - } catch (ex) { - if (ex instanceof ReferenceError) { - (global as any).WEBWORKER = false; - } - } - } -} diff --git a/extensions/github-browser/src/statusbar.ts b/extensions/github-browser/src/statusbar.ts deleted file mode 100644 index d949a95f7c..0000000000 --- a/extensions/github-browser/src/statusbar.ts +++ /dev/null @@ -1,99 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; -import { Disposable, StatusBarAlignment, StatusBarItem, Uri, window, workspace } from 'vscode'; -import { ChangeStoreEvent, IChangeStore } from './changeStore'; -import { GitHubApiContext } from './github/api'; -import { isSha } from './extension'; -import { ContextStore, WorkspaceFolderContext } from './contextStore'; - -export class StatusBar implements Disposable { - private readonly disposable: Disposable; - - private readonly items = new Map(); - - constructor( - private readonly contextStore: ContextStore, - private readonly changeStore: IChangeStore - ) { - this.disposable = Disposable.from( - contextStore.onDidChange(this.onContextsChanged, this), - changeStore.onDidChange(this.onChanged, this) - ); - - for (const context of this.contextStore.getForWorkspace()) { - this.createOrUpdateStatusBarItem(context); - } - } - - dispose() { - this.disposable?.dispose(); - this.items.forEach(i => i.dispose()); - } - - private createOrUpdateStatusBarItem(wc: WorkspaceFolderContext) { - let item = this.items.get(wc.folderUri.toString()); - if (item === undefined) { - item = window.createStatusBarItem({ - id: `githubBrowser.branch:${wc.folderUri.toString()}`, - name: `GitHub Browser: ${wc.name}`, - alignment: StatusBarAlignment.Left, - priority: 1000 - }); - } - - if (isSha(wc.context.branch)) { - item.text = `$(git-commit) ${wc.context.branch.substr(0, 8)}`; - item.tooltip = `${wc.name} \u2022 ${wc.context.branch.substr(0, 8)}`; - } else { - item.text = `$(git-branch) ${wc.context.branch}`; - item.tooltip = `${wc.name} \u2022 ${wc.context.branch}${wc.context.sha ? ` @ ${wc.context.sha?.substr(0, 8)}` : ''}`; - } - - const hasChanges = this.changeStore.hasChanges(wc.folderUri); - if (hasChanges) { - item.text += '*'; - } - - item.show(); - - this.items.set(wc.folderUri.toString(), item); - } - - private onContextsChanged(uri: Uri) { - const folder = workspace.getWorkspaceFolder(this.contextStore.getWorkspaceResource(uri)); - if (folder === undefined) { - return; - } - - const context = this.contextStore.get(uri); - if (context === undefined) { - return; - } - - this.createOrUpdateStatusBarItem({ - context: context, - name: folder.name, - folderUri: folder.uri, - }); - } - - private onChanged(e: ChangeStoreEvent) { - const item = this.items.get(e.rootUri.toString()); - if (item !== undefined) { - const hasChanges = this.changeStore.hasChanges(e.rootUri); - if (hasChanges) { - if (!item.text.endsWith('*')) { - item.text += '*'; - } - } else { - if (item.text.endsWith('*')) { - item.text = item.text.substr(0, item.text.length - 1); - } - } - } - } -} diff --git a/extensions/github-browser/src/typings/ref.d.ts b/extensions/github-browser/src/typings/ref.d.ts deleted file mode 100644 index ffe0c6c693..0000000000 --- a/extensions/github-browser/src/typings/ref.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// -/// -/// diff --git a/extensions/github-browser/tsconfig.json b/extensions/github-browser/tsconfig.json deleted file mode 100644 index eb413a1260..0000000000 --- a/extensions/github-browser/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../shared.tsconfig.json", - "compilerOptions": { - "experimentalDecorators": true, - "lib": [ - "es2018", - "dom" - ], - "outDir": "./out" - }, - "include": [ - "src/**/*" - ] -} diff --git a/extensions/github-browser/yarn.lock b/extensions/github-browser/yarn.lock deleted file mode 100644 index 2c8f1ad965..0000000000 --- a/extensions/github-browser/yarn.lock +++ /dev/null @@ -1,332 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@octokit/auth-token@^2.4.0": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a" - integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ== - dependencies: - "@octokit/types" "^5.0.0" - -"@octokit/core@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.1.0.tgz#9c3c9b23f7504668cfa057f143ccbf0c645a0ac9" - integrity sha512-yPyQSmxIXLieEIRikk2w8AEtWkFdfG/LXcw1KvEtK3iP0ENZLW/WYQmdzOKqfSaLhooz4CJ9D+WY79C8ZliACw== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/graphql" "^4.3.1" - "@octokit/request" "^5.4.0" - "@octokit/types" "^5.0.0" - before-after-hook "^2.1.0" - universal-user-agent "^5.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487" - integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg== - dependencies: - "@octokit/types" "^5.0.0" - is-plain-object "^3.0.0" - universal-user-agent "^5.0.0" - -"@octokit/graphql@4.5.1", "@octokit/graphql@^4.3.1": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.5.1.tgz#162aed1490320b88ce34775b3f6b8de945529fa9" - integrity sha512-qgMsROG9K2KxDs12CO3bySJaYoUu2aic90qpFrv7A8sEBzZ7UFGvdgPKiLw5gOPYEYbS0Xf8Tvf84tJutHPulQ== - dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^5.0.0" - universal-user-agent "^5.0.0" - -"@octokit/plugin-paginate-rest@^2.2.0": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.3.tgz#a6ad4377e7e7832fb4bdd9d421e600cb7640ac27" - integrity sha512-eKTs91wXnJH8Yicwa30jz6DF50kAh7vkcqCQ9D7/tvBAP5KKkg6I2nNof8Mp/65G0Arjsb4QcOJcIEQY+rK1Rg== - dependencies: - "@octokit/types" "^5.0.0" - -"@octokit/plugin-request-log@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" - integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw== - -"@octokit/plugin-rest-endpoint-methods@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.0.0.tgz#b02a2006dda8e908c3f8ab381dd5475ef5a810a8" - integrity sha512-emS6gysz4E9BNi9IrCl7Pm4kR+Az3MmVB0/DoDCmF4U48NbYG3weKyDlgkrz6Jbl4Mu4nDx8YWZwC4HjoTdcCA== - dependencies: - "@octokit/types" "^5.0.0" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0" - integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw== - dependencies: - "@octokit/types" "^5.0.1" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.3.0", "@octokit/request@^5.4.0": - version "5.4.5" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.5.tgz#8df65bd812047521f7e9db6ff118c06ba84ac10b" - integrity sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^5.0.0" - deprecation "^2.0.0" - is-plain-object "^3.0.0" - node-fetch "^2.3.0" - once "^1.4.0" - universal-user-agent "^5.0.0" - -"@octokit/rest@18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.0.0.tgz#7f401d9ce13530ad743dfd519ae62ce49bcc0358" - integrity sha512-4G/a42lry9NFGuuECnua1R1eoKkdBYJap97jYbWDNYBOUboWcM75GJ1VIcfvwDV/pW0lMPs7CEmhHoVrSV5shg== - dependencies: - "@octokit/core" "^3.0.0" - "@octokit/plugin-paginate-rest" "^2.2.0" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "4.0.0" - -"@octokit/types@^5.0.0", "@octokit/types@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.0.1.tgz#5459e9a5e9df8565dcc62c17a34491904d71971e" - integrity sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA== - dependencies: - "@types/node" ">= 8" - -"@types/node-fetch@2.5.7": - version "2.5.7" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" - integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*", "@types/node@>= 8": - version "14.0.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce" - integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -before-after-hook@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" - integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fuzzysort@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-1.1.4.tgz#a0510206ed44532cbb52cf797bf5a3cb12acd4ba" - integrity sha512-JzK/lHjVZ6joAg3OnCjylwYXYVjRiwTY6Yb25LvfpJHK8bjisfnZJ5bY8aVWwTwCXgxPNgLAtmHL+Hs5q1ddLQ== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -is-plain-object@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" - integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -macos-release@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" - integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== - -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@^2.1.12: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-fetch@2.6.0, node-fetch@^2.3.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -os-name@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" - integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== - dependencies: - macos-release "^2.2.0" - windows-release "^3.1.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -universal-user-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9" - integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q== - dependencies: - os-name "^3.1.0" - -vscode-nls@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" - integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -windows-release@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.1.tgz#cb4e80385f8550f709727287bf71035e209c4ace" - integrity sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A== - dependencies: - execa "^1.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/extensions/github/src/publish.ts b/extensions/github/src/publish.ts index d062a031e9..7c0bd46db3 100644 --- a/extensions/github/src/publish.ts +++ b/extensions/github/src/publish.ts @@ -140,6 +140,10 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository) const ignored = new Set(children); result.forEach(c => ignored.delete(c.label)); + if (ignored.size === 0) { + return; + } + const raw = [...ignored].map(i => `/${i}`).join('\n'); const encoder = new TextEncoder(); await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw)); diff --git a/extensions/image-preview/.vscodeignore b/extensions/image-preview/.vscodeignore index 30d948fbc6..bcb886a094 100644 --- a/extensions/image-preview/.vscodeignore +++ b/extensions/image-preview/.vscodeignore @@ -4,6 +4,7 @@ tsconfig.json out/test/** out/** extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json yarn.lock preview-src/** diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index dd04cc7777..064ada9485 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -4,7 +4,8 @@ "description": "%description%", "extensionKind": [ "ui", - "workspace" + "workspace", + "web" ], "version": "1.0.0", "publisher": "vscode", diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index eb2b984af0..e3e507c7b6 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,7 +14,7 @@ "dependencies": { "jsonc-parser": "^2.2.1", "request-light": "^0.3.0", - "vscode-json-languageservice": "^3.7.0", + "vscode-json-languageservice": "^3.8.0", "vscode-languageserver": "7.0.0-next.3", "vscode-uri": "^2.1.2" }, diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index e7dffe1d70..281f8276eb 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -80,10 +80,10 @@ request-light@^0.3.0: https-proxy-agent "^2.2.4" vscode-nls "^4.1.1" -vscode-json-languageservice@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.7.0.tgz#0174417f139cf41dd60c84538fd052385bfb46f6" - integrity sha512-nGLqcBhTjdfkl8Dz9sYGK/ZCTjscYFoIjYw+qqkWB+vyNfM0k/AyIoT73DQvB/PArteCKjEVfQUF72GRZEDSbQ== +vscode-json-languageservice@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.8.0.tgz#c7e7283f993e3db39fa5501407b023ada6fd3ae3" + integrity sha512-sYz5JElJMIlPoqhrRfG3VKnDjnPinLdblIiEVsJgTz1kj2hWD2q5BSbo+evH/5/jKDXDLfA8kb0lHC4vd5g5zg== dependencies: jsonc-parser "^2.2.1" vscode-languageserver-textdocument "^1.0.1" diff --git a/extensions/markdown-language-features/.vscodeignore b/extensions/markdown-language-features/.vscodeignore index bcb886a094..9f1e062077 100644 --- a/extensions/markdown-language-features/.vscodeignore +++ b/extensions/markdown-language-features/.vscodeignore @@ -1,4 +1,5 @@ test/** +test-workspace/** src/** tsconfig.json out/test/** diff --git a/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css index b43eb8e720..b9c72c97d5 100644 --- a/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -128,21 +128,12 @@ textarea:focus { } p { - margin-bottom: 1.5em; -} - -li > p { - margin-bottom: 0; -} - -/* don't space 2 paragraphs too far apart */ -p + p { - margin-top: -0.8em; + margin-bottom: 0.7em; } ul, ol { - margin-bottom: 1.5em; + margin-bottom: 0.7em; } hr { diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index c88e476c8e..fbf3051a54 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -129,7 +129,6 @@ export class MarkdownEngine { } this.currentDocument = document.uri; - this._slugCount = new Map(); const tokens = this.tokenizeString(document.getText(), engine); this._tokenCache.update(document, config, tokens); @@ -144,6 +143,8 @@ export class MarkdownEngine { } private tokenizeString(text: string, engine: MarkdownIt) { + this._slugCount = new Map(); + return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {}); } @@ -362,4 +363,3 @@ function normalizeHighlightLang(lang: string | undefined) { return lang; } } - diff --git a/extensions/merge-conflict/.vscodeignore b/extensions/merge-conflict/.vscodeignore index 36e8b0714f..f071cfb7c7 100644 --- a/extensions/merge-conflict/.vscodeignore +++ b/extensions/merge-conflict/.vscodeignore @@ -2,4 +2,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +extension-browser.webpack.config.js +yarn.lock diff --git a/extensions/microsoft-authentication/.vscodeignore b/extensions/microsoft-authentication/.vscodeignore index ed3f9d37c1..46f23a20db 100644 --- a/extensions/microsoft-authentication/.vscodeignore +++ b/extensions/microsoft-authentication/.vscodeignore @@ -1,10 +1,14 @@ .vscode/** .vscode-test/** out/test/** +out/** +extension.webpack.config.js +extension-browser.webpack.config.js +yarn.lock src/** .gitignore vsc-extension-quickstart.md **/tsconfig.json **/tslint.json **/*.map -**/*.ts \ No newline at end of file +**/*.ts diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index 9db55f18ae..81ed5c32e4 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -17,7 +17,8 @@ ], "extensionKind": [ "ui", - "workspace" + "workspace", + "web" ], "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "main": "./out/extension.js", diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index bead06efbd..7e67df7dd4 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -73,7 +73,7 @@ function parseQuery(uri: vscode.Uri) { }, {}); } -export const onDidChangeSessions = new vscode.EventEmitter(); +export const onDidChangeSessions = new vscode.EventEmitter(); export const REFRESH_NETWORK_FAILURE = 'Network failure'; @@ -339,7 +339,7 @@ export class AzureActiveDirectoryService { } private getCallbackEnvironment(callbackUri: vscode.Uri): string { - if (callbackUri.authority.endsWith('.workspaces.github.com')) { + if (callbackUri.authority.endsWith('.workspaces.github.com') || callbackUri.authority.endsWith('.github.dev')) { return `${callbackUri.authority},`; } @@ -471,7 +471,10 @@ export class AzureActiveDirectoryService { redirect_uri: redirectUrl }); - const result = await fetch(`${loginEndpointUrl}${tenant}/oauth2/v2.0/token`, { + const proxyEndpoints: { [providerId: string]: string } | undefined = await vscode.commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); + const endpoint = proxyEndpoints && proxyEndpoints['microsoft'] || `${loginEndpointUrl}${tenant}/oauth2/v2.0/token`; + + const result = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', diff --git a/extensions/package.json b/extensions/package.json index 69f5ea275b..665553eeea 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -7,8 +7,5 @@ }, "scripts": { "postinstall": "node ./postinstall" - }, - "devDependencies": { - "rimraf": "^3.0.2" } } diff --git a/extensions/python/.vscodeignore b/extensions/python/.vscodeignore index 4d5a14fc91..b5c95d0fb6 100644 --- a/extensions/python/.vscodeignore +++ b/extensions/python/.vscodeignore @@ -1,6 +1,8 @@ test/** src/** +out/** tsconfig.json extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json -.vscode \ No newline at end of file +.vscode diff --git a/extensions/python/package.json b/extensions/python/package.json index 612fcf7650..e7c75aa4ea 100644 --- a/extensions/python/package.json +++ b/extensions/python/package.json @@ -9,7 +9,7 @@ "activationEvents": ["onLanguage:python"], "main": "./out/pythonMain", "browser": "./dist/browser/pythonMain", - "extensionKind": [ "ui", "workspace" ], + "extensionKind": [ "ui", "workspace", "web" ], "contributes": { "languages": [{ "id": "python", diff --git a/extensions/github-browser/.vscodeignore b/extensions/search-result/.vscodeignore similarity index 67% rename from extensions/github-browser/.vscodeignore rename to extensions/search-result/.vscodeignore index 32fe3f0369..da3d276368 100644 --- a/extensions/github-browser/.vscodeignore +++ b/extensions/search-result/.vscodeignore @@ -1,11 +1,6 @@ -.vscode/** -build/** -dist/** -out/** src/** -typings/** -.gitignore -extension-browser.webpack.config.js -extension.webpack.config.js +out/** tsconfig.json +extension.webpack.config.js +extension-browser.webpack.config.js yarn.lock diff --git a/extensions/github-browser/extension-browser.webpack.config.js b/extensions/search-result/extension-browser.webpack.config.js similarity index 75% rename from extensions/github-browser/extension-browser.webpack.config.js rename to extensions/search-result/extension-browser.webpack.config.js index c6d40d066e..e7253e1211 100644 --- a/extensions/github-browser/extension-browser.webpack.config.js +++ b/extensions/search-result/extension-browser.webpack.config.js @@ -6,20 +6,17 @@ //@ts-check 'use strict'; -const path = require('path'); -const withBrowserDefaults = require('../shared.webpack.config').browser; -const config = withBrowserDefaults({ +const withBrowserDefaults = require('../shared.webpack.config').browser; +const path = require('path'); + +module.exports = withBrowserDefaults({ context: __dirname, - node: false, entry: { extension: './src/extension.ts' }, - resolve: { - alias: { - 'node-fetch': path.resolve(__dirname, 'node_modules/node-fetch/browser.js') - } + output: { + filename: 'extension.js', + path: path.join(__dirname, 'dist') } }); - -module.exports = config; diff --git a/extensions/search-result/package.json b/extensions/search-result/package.json index ffb5321ae4..7b43da243c 100644 --- a/extensions/search-result/package.json +++ b/extensions/search-result/package.json @@ -12,6 +12,7 @@ "Programming Languages" ], "main": "./out/extension.js", + "browser": "./dist/extension.js", "activationEvents": [ "*" ], diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index 69336137d4..bea8eaca21 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -126,6 +126,8 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u return vscode.Uri.file(pathUtils.join(process.env.HOME!, path.slice(2))); } + const uriFromFolderWithPath = (folder: vscode.WorkspaceFolder, path: string): vscode.Uri => + folder.uri.with({ path: pathUtils.join(folder.uri.fsPath, path) }); if (vscode.workspace.workspaceFolders) { const multiRootFormattedPath = /^(.*) • (.*)$/.exec(path); @@ -133,17 +135,18 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u const [, workspaceName, workspacePath] = multiRootFormattedPath; const folder = vscode.workspace.workspaceFolders.filter(wf => wf.name === workspaceName)[0]; if (folder) { - return vscode.Uri.file(pathUtils.join(folder.uri.fsPath, workspacePath)); + return uriFromFolderWithPath(folder, workspacePath); } } - else if (vscode.workspace.workspaceFolders.length === 1) { - return vscode.Uri.file(pathUtils.join(vscode.workspace.workspaceFolders[0].uri.fsPath, path)); + return uriFromFolderWithPath(vscode.workspace.workspaceFolders[0], path); } else if (resultsUri.scheme !== 'untitled') { // We're in a multi-root workspace, but the path is not multi-root formatted // Possibly a saved search from a single root session. Try checking if the search result document's URI is in a current workspace folder. const prefixMatch = vscode.workspace.workspaceFolders.filter(wf => resultsUri.toString().startsWith(wf.uri.toString()))[0]; - if (prefixMatch) { return vscode.Uri.file(pathUtils.join(prefixMatch.uri.fsPath, path)); } + if (prefixMatch) { + return uriFromFolderWithPath(prefixMatch, path); + } } } diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 86223e7721..102d128edb 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,86 +2,7 @@ # yarn lockfile v1 -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - 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" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - typescript@3.9.7: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/package.json b/package.json index 74bd5b03f2..e0d15a174f 100644 --- a/package.json +++ b/package.json @@ -93,10 +93,10 @@ "vscode-ripgrep": "^1.8.0", "vscode-sqlite3": "4.0.10", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0", + "xterm-addon-webgl": "0.8.0", "yauzl": "^2.9.2", "yazl": "^2.4.3", "zone.js": "^0.8.4" @@ -136,7 +136,7 @@ "css-loader": "^3.2.0", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "9.1.0", + "electron": "7.3.2", "eslint": "6.8.0", "eslint-plugin-jsdoc": "^19.1.0", "event-stream": "3.3.4", diff --git a/product.json b/product.json index 0fa86b0601..88e5258ed8 100644 --- a/product.json +++ b/product.json @@ -67,7 +67,8 @@ "extensionAllowedProposedApi": [ "ms-vscode.vscode-js-profile-flame", "ms-vscode.vscode-js-profile-table", - "ms-vscode.references-view" + "ms-vscode.references-view", + "ms-vscode.github-browser" ], "extensionsGallery": { "serviceUrl": "https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json" diff --git a/remote/.yarnrc b/remote/.yarnrc index c1a32ce532..1e16cde724 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,3 +1,3 @@ disturl "http://nodejs.org/dist" -target "12.14.1" +target "12.4.0" runtime "node" diff --git a/remote/package.json b/remote/package.json index 363a97d80c..ee4a00c04a 100644 --- a/remote/package.json +++ b/remote/package.json @@ -38,10 +38,10 @@ "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.8.0", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0", + "xterm-addon-webgl": "0.8.0", "yauzl": "^2.9.2", "yazl": "^2.4.3", "zone.js": "^0.8.4" diff --git a/remote/web/package.json b/remote/web/package.json index cef07e7f5d..7d6b0c4b3d 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -25,10 +25,10 @@ "slickgrid": "github:anthonydresser/SlickGrid#2.3.33", "vscode-oniguruma": "1.3.1", "vscode-textmate": "5.2.0", - "xterm": "4.8.1", + "xterm": "4.9.0-beta.8", "xterm-addon-search": "0.7.0", "xterm-addon-unicode11": "0.2.0", - "xterm-addon-webgl": "0.7.0", + "xterm-addon-webgl": "0.8.0", "zone.js": "^0.8.4" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 694113201c..733ba1e79d 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -373,15 +373,15 @@ xterm-addon-unicode11@0.2.0: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c" integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== -xterm-addon-webgl@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" - integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== +xterm-addon-webgl@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" + integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== -xterm@4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" - integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== +xterm@4.9.0-beta.8: + version "4.9.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" + integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== zone.js@^0.8.4: version "0.8.29" diff --git a/remote/yarn.lock b/remote/yarn.lock index 0ed3f67039..4b9f377e0b 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -776,15 +776,15 @@ xterm-addon-unicode11@0.2.0: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c" integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== -xterm-addon-webgl@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" - integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== +xterm-addon-webgl@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" + integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== -xterm@4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" - integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== +xterm@4.9.0-beta.8: + version "4.9.0-beta.8" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" + integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/serverless/code-web.js b/resources/serverless/code-web.js index 998d88b884..cb9c5ee580 100644 --- a/resources/serverless/code-web.js +++ b/resources/serverless/code-web.js @@ -64,56 +64,25 @@ const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`; const exists = (path) => util.promisify(fs.exists)(path); const readFile = (path) => util.promisify(fs.readFile)(path); -const readdir = (path) => util.promisify(fs.readdir)(path); -const readdirWithFileTypes = (path) => util.promisify(fs.readdir)(path, { withFileTypes: true }); async function getBuiltInExtensionInfos() { - const extensions = []; + const allExtensions = []; /** @type {Object.} */ const locations = {}; - for (const extensionsRoot of [BUILTIN_EXTENSIONS_ROOT, BUILTIN_MARKETPLACE_EXTENSIONS_ROOT]) { - if (await exists(extensionsRoot)) { - const children = await readdirWithFileTypes(extensionsRoot); - await Promise.all(children.map(async child => { - if (child.isDirectory()) { - const extensionPath = path.join(extensionsRoot, child.name); - const info = await getBuiltInExtensionInfo(extensionPath); - if (info) { - extensions.push(info); - locations[path.basename(extensionPath)] = extensionPath; - } - } - })); - } + const [localExtensions, marketplaceExtensions] = await Promise.all([ + extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT), + extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT), + ]); + for (const ext of localExtensions) { + allExtensions.push(ext); + locations[ext.extensionPath] = path.join(BUILTIN_EXTENSIONS_ROOT, ext.extensionPath); } - return { extensions, locations }; -} - -async function getBuiltInExtensionInfo(extensionPath) { - const packageJSON = await getExtensionPackageJSON(extensionPath); - if (!packageJSON) { - return undefined; + for (const ext of marketplaceExtensions) { + allExtensions.push(ext); + locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath); } - const builtInExtensionPath = path.basename(extensionPath); - - let children = []; - try { - children = await readdir(extensionPath); - } catch (error) { - console.log(`Can not read extension folder ${extensionPath}: ${error}`); - return; - } - const readme = children.find(child => /^readme(\.txt|\.md|)$/i.test(child)); - const changelog = children.find(child => /^changelog(\.txt|\.md|)$/i.test(child)); - const packageJSONNLS = children.find(child => /^package.nls.json$/i.test(child)); - return { - extensionPath: builtInExtensionPath, - packageJSON, - packageNLSPath: packageJSONNLS ? `${builtInExtensionPath}/${packageJSONNLS}` : undefined, - readmePath: readme ? `${builtInExtensionPath}/${readme}` : undefined, - changelogPath: changelog ? `${builtInExtensionPath}/${changelog}` : undefined - }; + return { extensions: allExtensions, locations }; } async function getDefaultExtensionInfos() { @@ -124,7 +93,7 @@ async function getDefaultExtensionInfos() { let extensionArg = args['extension']; if (!extensionArg) { - return { extensions, locations } + return { extensions, locations }; } const extensionPaths = Array.isArray(extensionArg) ? extensionArg : [extensionArg]; @@ -154,8 +123,6 @@ async function getExtensionPackageJSON(extensionPath) { } if (packageJSON.browser) { - packageJSON.main = packageJSON.browser; - let mainFilePath = path.join(extensionPath, packageJSON.browser); if (path.extname(mainFilePath) !== '.js') { mainFilePath += '.js'; @@ -164,7 +131,6 @@ async function getExtensionPackageJSON(extensionPath) { fancyLog(`${ansiColors.yellow('Warning')}: Could not find ${mainFilePath}. Use ${ansiColors.cyan('yarn gulp watch-web')} to build the built-in extensions.`); } } - packageJSON.extensionKind = ['web']; // enable for Web const packageNLSPath = path.join(extensionPath, 'package.nls.json'); const packageNLSExists = await exists(packageNLSPath); @@ -273,7 +239,9 @@ async function handleExtension(req, res, parsedUrl) { if (!filePath) { return serveError(req, res, 400, `Bad request.`); } - return serveFile(req, res, filePath); + return serveFile(req, res, filePath, { + 'Access-Control-Allow-Origin': '*' + }); } /** @@ -288,7 +256,9 @@ async function handleBuiltInExtension(req, res, parsedUrl) { if (!filePath) { return serveError(req, res, 400, `Bad request.`); } - return serveFile(req, res, filePath); + return serveFile(req, res, filePath, { + 'Access-Control-Allow-Origin': '*' + }); } /** @@ -309,7 +279,8 @@ async function handleRoot(req, res) { } const [owner, repo, ...branch] = gh.split('/', 3); - folderUri = { scheme: 'github', authority: branch.join('/') || 'HEAD', path: `/${owner}/${repo}` }; + const ref = branch.join('/'); + folderUri = { scheme: 'github', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' }; } else { let cs = qs.get('cs'); if (cs) { @@ -318,7 +289,8 @@ async function handleRoot(req, res) { } const [owner, repo, ...branch] = cs.split('/'); - folderUri = { scheme: 'codespace', authority: branch.join('/') || 'HEAD', path: `/${owner}/${repo}` }; + const ref = branch.join('/'); + folderUri = { scheme: 'codespace', authority: `${owner}+${repo}${ref ? `+${ref}` : ''}`, path: '/' }; } } } diff --git a/scripts/code-cli.bat b/scripts/code-cli.bat index a07ccc96bf..2e4e34ff32 100644 --- a/scripts/code-cli.bat +++ b/scripts/code-cli.bat @@ -5,27 +5,17 @@ title VSCode Dev pushd %~dp0\.. -:: Node modules -if not exist node_modules call yarn +:: Get electron, compile, built-in extensions +if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a set NAMESHORT=%NAMESHORT: "=% set NAMESHORT=%NAMESHORT:"=%.exe set CODE=".build\electron\%NAMESHORT%" -:: Download Electron if needed -node build\lib\electron.js -if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron - :: Manage built-in extensions if "%1"=="--builtin" goto builtin -:: Sync built-in extensions -node build\lib\builtInExtensions.js - -:: Build -if not exist out yarn compile - :: Configuration set ELECTRON_RUN_AS_NODE=1 set NODE_ENV=development diff --git a/scripts/code-cli.sh b/scripts/code-cli.sh index e4fa552e64..a792c08532 100755 --- a/scripts/code-cli.sh +++ b/scripts/code-cli.sh @@ -18,11 +18,10 @@ function code() { CODE=".build/electron/$NAME" fi - # Node modules - test -d node_modules || yarn - - # Get electron - yarn electron + # Get electron, compile, built-in extensions + if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then + node build/lib/preLaunch.js + fi # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -30,12 +29,6 @@ function code() { return fi - # Sync built-in extensions - node build/lib/builtInExtensions.js - - # Build - test -d out || yarn compile - ELECTRON_RUN_AS_NODE=1 \ NODE_ENV=development \ VSCODE_DEV=1 \ diff --git a/scripts/code.bat b/scripts/code.bat index c4c1cc7c05..7ef1fd33fe 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -5,26 +5,17 @@ title VSCode Dev pushd %~dp0\.. -:: Node modules -if not exist node_modules call yarn +:: Get electron, compile, built-in extensions +if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a set NAMESHORT=%NAMESHORT: "=% set NAMESHORT=%NAMESHORT:"=%.exe set CODE=".build\electron\%NAMESHORT%" -:: Get electron -call yarn electron - :: Manage built-in extensions if "%1"=="--builtin" goto builtin -:: Sync built-in extensions -node build\lib\builtInExtensions.js - -:: Build -if not exist out yarn compile - :: Configuration set NODE_ENV=development set VSCODE_DEV=1 diff --git a/scripts/code.sh b/scripts/code.sh index 390aa4b201..b19cc0df9f 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -24,11 +24,10 @@ function code() { CODE=".build/electron/$NAME" fi - # Node modules - test -d node_modules || yarn - - # Get electron - yarn electron + # Get electron, compile, built-in extensions + if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then + node build/lib/preLaunch.js + fi # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -36,12 +35,6 @@ function code() { return fi - # Sync built-in extensions - node build/lib/builtInExtensions.js - - # Build - test -d out || yarn compile - # Configuration export NODE_ENV=development export VSCODE_DEV=1 diff --git a/src/main.js b/src/main.js index 53a9d9ae77..183f9e072c 100644 --- a/src/main.js +++ b/src/main.js @@ -18,11 +18,7 @@ const bootstrap = require('./bootstrap'); const paths = require('./paths'); /** @type {any} */ const product = require('../product.json'); -const { app, protocol, crashReporter } = require('electron'); - -// Disable render process reuse, we still have -// non-context aware native modules in the renderer. -app.allowRendererProcessReuse = false; +const { app, protocol } = require('electron'); // Enable portable support const portable = bootstrap.configurePortable(product); @@ -42,13 +38,13 @@ if (args['nogpu']) { // {{SQL CARBON EDIT}} const userDataPath = getUserDataPath(args); app.setPath('userData', userDataPath); -// Configure static command line arguments -const argvConfig = configureCommandlineSwitchesSync(args); +// Set temp directory based on crash-reporter-directory CLI argument +// The crash reporter will store crashes in temp folder so we need +// to change that location accordingly. -// If a crash-reporter-directory is specified we store the crash reports -// in the specified directory and don't upload them to the crash server. +// If a crash-reporter-directory is specified we setup the crash reporter +// right from the beginning as early as possible to monitor all processes. let crashReporterDirectory = args['crash-reporter-directory']; -let submitURL = ''; if (crashReporterDirectory) { crashReporterDirectory = path.normalize(crashReporterDirectory); @@ -66,40 +62,22 @@ if (crashReporterDirectory) { } } - // Crashes are stored in the crashDumps directory by default, so we + // Crashes are stored in the temp directory by default, so we // need to change that directory to the provided one - console.log(`Found --crash-reporter-directory argument. Setting crashDumps directory to be '${crashReporterDirectory}'`); - app.setPath('crashDumps', crashReporterDirectory); -} else { - const appCenter = product.appCenter; - // Disable Appcenter crash reporting if - // * --crash-reporter-directory is specified - // * enable-crash-reporter runtime argument is set to 'false' - // * --disable-crash-reporter command line parameter is set - if (appCenter && argvConfig['enable-crash-reporter'] && !args['disable-crash-reporter']) { - const isWindows = (process.platform === 'win32'); - const isLinux = (process.platform === 'linux'); - const crashReporterId = argvConfig['crash-reporter-id']; - const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; - if (uuidPattern.test(crashReporterId)) { - submitURL = isWindows ? appCenter[process.arch === 'ia32' ? 'win32-ia32' : 'win32-x64'] : isLinux ? appCenter[`linux-x64`] : appCenter.darwin; - submitURL = submitURL.concat('&uid=', crashReporterId, '&iid=', crashReporterId, '&sid=', crashReporterId); - // Send the id for child node process that are explicitly starting crash reporter. - // For vscode this is ExtensionHost process currently. - process.argv.push('--crash-reporter-id', crashReporterId); - } - } -} + console.log(`Found --crash-reporter-directory argument. Setting temp directory to be '${crashReporterDirectory}'`); + app.setPath('temp', crashReporterDirectory); -// Start crash reporter for all processes -const productName = (product.crashReporter ? product.crashReporter.productName : undefined) || product.nameShort; -const companyName = (product.crashReporter ? product.crashReporter.companyName : undefined) || 'Microsoft'; -crashReporter.start({ - companyName: companyName, - productName: process.env['VSCODE_DEV'] ? `${productName} Dev` : productName, - submitURL, - uploadToServer: !crashReporterDirectory -}); + // Start crash reporter + const { crashReporter } = require('electron'); + const productName = (product.crashReporter && product.crashReporter.productName) || product.nameShort; + const companyName = (product.crashReporter && product.crashReporter.companyName) || 'Microsoft'; + crashReporter.start({ + companyName: companyName, + productName: process.env['VSCODE_DEV'] ? `${productName} Dev` : productName, + submitURL: '', + uploadToServer: false + }); +} // Set logs path before app 'ready' event if running portable // to ensure that no 'logs' folder is created on disk at a @@ -139,6 +117,9 @@ registerListeners(); // Cached data const nodeCachedDataDir = getNodeCachedDir(); +// Configure static command line arguments +const argvConfig = configureCommandlineSwitchesSync(args); + // Remove env set by snap https://github.com/microsoft/vscode/issues/85344 if (process.env['SNAP']) { delete process.env['GDK_PIXBUF_MODULE_FILE']; @@ -280,6 +261,9 @@ function configureCommandlineSwitchesSync(cliArgs) { app.commandLine.appendSwitch('js-flags', jsFlags); } + // TODO@Deepak Electron 7 workaround for https://github.com/microsoft/vscode/issues/88873 + app.commandLine.appendSwitch('disable-features', 'LayoutNG'); + return argvConfig; } diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index e2a76eaddd..0ed837d874 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -749,6 +749,16 @@ export function getShadowRoot(domNode: Node): ShadowRoot | null { return isShadowRoot(domNode) ? domNode : null; } +export function getActiveElement(): Element | null { + let result = document.activeElement; + + while (result?.shadowRoot) { + result = result.shadowRoot.activeElement; + } + + return result; +} + export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement { let style = document.createElement('style'); style.type = 'text/css'; diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 3133bc7851..9a3c07626b 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -137,17 +137,9 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => { DOM.EventHelper.stop(e, true); - // See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard - // > Writing to the clipboard - // > You can use the "cut" and "copy" commands without any special - // permission if you are using them in a short-lived event handler - // for a user action (for example, a click handler). - // => to get the Copy and Paste context menu actions working on Firefox, - // there should be no timeout here - if (this.options && this.options.isMenu) { - this.onClick(e); - } else { + // menus do not use the click event + if (!(this.options && this.options.isMenu)) { platform.setImmediate(() => this.onClick(e)); } })); diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index c7913e7413..297f815fae 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -173,7 +173,7 @@ export class ActionBar extends Disposable implements IActionRunner { this.focusTracker = this._register(DOM.trackFocus(this.domNode)); this._register(this.focusTracker.onDidBlur(() => { - if (document.activeElement === this.domNode || !DOM.isAncestor(document.activeElement, this.domNode)) { + if (DOM.getActiveElement() === this.domNode || !DOM.isAncestor(DOM.getActiveElement(), this.domNode)) { this._onDidBlur.fire(); this.focusedItem = undefined; } @@ -214,7 +214,7 @@ export class ActionBar extends Disposable implements IActionRunner { private updateFocusedItem(): void { for (let i = 0; i < this.actionsList.children.length; i++) { const elem = this.actionsList.children[i]; - if (DOM.isAncestor(document.activeElement, elem)) { + if (DOM.isAncestor(DOM.getActiveElement(), elem)) { this.focusedItem = i; break; } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index f6b1bae867..b8f31da856 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -156,7 +156,7 @@ export class ContextView extends Disposable { if (this.useShadowDOM) { this.shadowRootHostElement = DOM.$('.shadow-root-host'); this.container.appendChild(this.shadowRootHostElement); - this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'closed' }); + this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = `