Merge from vscode cfbd1999769f4f08dce29629fb92fdc0fac53829

This commit is contained in:
ADS Merger
2020-08-06 07:08:52 +00:00
parent 9c67832880
commit 540046ba00
362 changed files with 7588 additions and 6584 deletions

1
.gitignore vendored
View File

@@ -24,6 +24,7 @@ out-vscode-reh-web-min/
out-vscode-reh-web-pkg/ out-vscode-reh-web-pkg/
out-vscode-web/ out-vscode-web/
out-vscode-web-min/ out-vscode-web-min/
out-vscode-web-pkg/
src/vs/server src/vs/server
resources/server resources/server
build/node_modules build/node_modules

7
.vscode/launch.json vendored
View File

@@ -90,10 +90,10 @@
"port": 9222, "port": 9222,
"timeout": 20000, "timeout": 20000,
"env": { "env": {
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null "VSCODE_EXTHOST_WILL_SEND_SOCKET": null,
"VSCODE_SKIP_PRELAUNCH": "1"
}, },
"cleanUp": "wholeBrowser", "cleanUp": "wholeBrowser",
"breakOnLoad": false,
"urlFilter": "*workbench.html*", "urlFilter": "*workbench.html*",
"runtimeArgs": [ "runtimeArgs": [
"--inspect=5875", "--inspect=5875",
@@ -106,7 +106,8 @@
"outFiles": [ "outFiles": [
"${workspaceFolder}/out/**/*.js" "${workspaceFolder}/out/**/*.js"
], ],
"browserLaunchLocation": "workspace" "browserLaunchLocation": "workspace",
"preLaunchTask": "Ensure Prelaunch Dependencies",
}, },
{ {
"type": "chrome", "type": "chrome",

View File

@@ -8,8 +8,17 @@
{ {
"kind": 2, "kind": 2,
"language": "github-issues", "language": "github-issues",
"value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item ", "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item "
"editable": true },
{
"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, "kind": 1,
@@ -32,7 +41,7 @@
{ {
"kind": 2, "kind": 2,
"language": "github-issues", "language": "github-issues",
"value": "$inbox", "value": "$inbox -label:emmet",
"editable": false "editable": true
} }
] ]

10
.vscode/tasks.json vendored
View File

@@ -200,6 +200,14 @@
"source": "eslint", "source": "eslint",
"base": "$eslint-stylish" "base": "$eslint-stylish"
} }
} },
{
"type": "shell",
"command": "node build/lib/prelaunch.js",
"label": "Ensure Prelaunch Dependencies",
"presentation": {
"reveal": "silent"
}
},
] ]
} }

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron" disturl "https://atom.io/download/electron"
target "9.1.0" target "7.3.2"
runtime "electron" runtime "electron"

View File

@@ -1,7 +1,7 @@
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: 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 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -11,7 +11,7 @@ pr:
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: AzureKeyVault@1 - task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets' displayName: 'Azure Key Vault: Get Secrets'

View File

@@ -11,7 +11,7 @@ pr:
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: AzureKeyVault@1 - task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets' displayName: 'Azure Key Vault: Get Secrets'

View File

@@ -10,7 +10,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -1,7 +1,7 @@
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -16,7 +16,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true')) condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2

View File

@@ -9,7 +9,7 @@ pr: none
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -36,6 +36,18 @@ function updateDTSFile(outPath: string, tag: string) {
fs.writeFileSync(outPath, newContent); 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) { function getNewFileContent(content: string, tag: string) {
const oldheader = [ const oldheader = [
`/*---------------------------------------------------------------------------------------------`, `/*---------------------------------------------------------------------------------------------`,
@@ -44,7 +56,7 @@ function getNewFileContent(content: string, tag: string) {
` *--------------------------------------------------------------------------------------------*/` ` *--------------------------------------------------------------------------------------------*/`
].join('\n'); ].join('\n');
return getNewFileHeader(tag) + content.slice(oldheader.length); return convertTabsToSpaces(getNewFileHeader(tag) + content.slice(oldheader.length));
} }
function getNewFileHeader(tag: string) { function getNewFileHeader(tag: string) {

View File

@@ -1,7 +1,7 @@
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -1,7 +1,7 @@
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: 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 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -21,7 +21,7 @@ steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: "12.14.1" versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs: inputs:

View File

@@ -171,8 +171,8 @@ gulp.task(compileExtensionsBuildLegacyTask);
const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions'));
const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series(
cleanExtensionsBuildTask, cleanExtensionsBuildTask,
task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))), task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream(false).pipe(gulp.dest('.build'))),
task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))) task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream(false).pipe(gulp.dest('.build'))),
)); ));
gulp.task(compileExtensionsBuildTask); gulp.task(compileExtensionsBuildTask);

View File

@@ -42,8 +42,8 @@ const indentationFilter = [
'**', '**',
// except specific files // except specific files
'!ThirdPartyNotices.txt', '!**/ThirdPartyNotices.txt',
'!LICENSE.{txt,rtf}', '!**/LICENSE.{txt,rtf}',
'!LICENSES.chromium.html', '!LICENSES.chromium.html',
'!**/LICENSE', '!**/LICENSE',
'!src/vs/nls.js', '!src/vs/nls.js',

View File

@@ -100,7 +100,7 @@ function writeControlFile(control) {
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2)); fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
} }
function main() { exports.getBuiltInExtensions = function getBuiltInExtensions() {
log('Syncronizing built-in extensions...'); log('Syncronizing built-in extensions...');
log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`); log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`);
@@ -116,14 +116,16 @@ function main() {
writeControlFile(control); writeControlFile(control);
es.merge(streams) return new Promise((resolve, reject) => {
.on('error', err => { es.merge(streams)
console.error(err); .on('error', reject)
process.exit(1); .on('end', resolve);
}) });
.on('end', () => { };
process.exit(0);
});
}
main(); if (require.main === module) {
exports.getBuiltInExtensions().then(() => process.exit(0)).catch(err => {
console.error(err);
process.exit(1);
});
}

View File

@@ -4,7 +4,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); 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 es = require("event-stream");
const fs = require("fs"); const fs = require("fs");
const glob = require("glob"); const glob = require("glob");
@@ -22,22 +22,28 @@ const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors"); const ansiColors = require("ansi-colors");
const buffer = require('gulp-buffer'); const buffer = require('gulp-buffer');
const json = require("gulp-json-editor"); const json = require("gulp-json-editor");
const jsoncParser = require("jsonc-parser");
const webpack = require('webpack'); const webpack = require('webpack');
const webpackGulp = require('webpack-stream'); const webpackGulp = require('webpack-stream');
const util = require('./util'); const util = require('./util');
const root = path.dirname(path.dirname(__dirname)); const root = path.dirname(path.dirname(__dirname));
const commit = util.getVersion(root); const commit = util.getVersion(root);
const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`; const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`;
function minimizeLanguageJSON(input) { function minifyExtensionResources(input) {
const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
return input return input
.pipe(tmLanguageJsonFilter) .pipe(jsonFilter)
.pipe(buffer()) .pipe(buffer())
.pipe(es.mapSync((f) => { .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; return f;
})) }))
.pipe(tmLanguageJsonFilter.restore); .pipe(jsonFilter.restore);
} }
function updateExtensionPackageJSON(input, update) { function updateExtensionPackageJSON(input, update) {
const packageJsonFilter = filter('extensions/*/package.json', { restore: true }); const packageJsonFilter = filter('extensions/*/package.json', { restore: true });
@@ -57,24 +63,18 @@ function fromLocal(extensionPath, forWeb) {
let input = isWebPacked let input = isWebPacked
? fromLocalWebpack(extensionPath, webpackConfigFileName) ? fromLocalWebpack(extensionPath, webpackConfigFileName)
: fromLocalNormal(extensionPath); : fromLocalNormal(extensionPath);
if (forWeb) { if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data) => {
if (data.browser) {
data.main = data.browser;
}
data.extensionKind = ['web'];
return data;
});
}
else if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data) => { input = updateExtensionPackageJSON(input, (data) => {
delete data.scripts;
delete data.dependencies;
delete data.devDependencies;
if (data.main) { if (data.main) {
data.main = data.main.replace('/out/', /dist/); data.main = data.main.replace('/out/', /dist/);
} }
return data; return data;
}); });
} }
return minimizeLanguageJSON(input); return input;
} }
function fromLocalWebpack(extensionPath, webpackConfigFileName) { function fromLocalWebpack(extensionPath, webpackConfigFileName) {
const result = es.through(); const result = es.through();
@@ -194,7 +194,6 @@ function fromMarketplace(extensionName, version, metadata) {
exports.fromMarketplace = fromMarketplace; exports.fromMarketplace = fromMarketplace;
const excludedExtensions = [ const excludedExtensions = [
'vscode-api-tests', 'vscode-api-tests',
'vscode-web-playground',
'vscode-colorize-tests', 'vscode-colorize-tests',
'vscode-test-resolver', 'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
@@ -230,98 +229,105 @@ const rebuildExtensions = [
'big-data-cluster', 'big-data-cluster',
'mssql' 'mssql'
]; ];
const builtInExtensions = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')).builtInExtensions; const marketplaceWebExtensions = [
function packageLocalExtensionsStream() { 'ms-vscode.references-view'
const localExtensionDescriptions = glob.sync('extensions/*/package.json') ];
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 => { .map(manifestPath => {
const absoluteManifestPath = path.join(root, manifestPath);
const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionPath = path.dirname(path.join(root, manifestPath));
const extensionName = path.basename(extensionPath); 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 }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ name }) => builtInExtensions.every(b => b.name !== name))
.filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package .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) const localExtensionsStream = minifyExtensionResources(es.merge(...localExtensionsDescriptions.map(extension => {
return fromLocal(extension.path, forWeb)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
}); })));
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); let result;
return es.merge(nodeModules, ...localExtensions) if (forWeb) {
.pipe(util2.setExecutableBit(['**/*.sh'])); 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; exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
function packageLocalWebExtensionsStream() { function packageMarketplaceExtensionsStream(forWeb) {
const localExtensionDescriptions = glob.sync('extensions/*/package.json') const marketplaceExtensionsDescriptions = [
.filter(manifestPath => { ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)),
const packageJsonConfig = require(path.join(root, manifestPath)); ...(forWeb ? webBuiltInExtensions : [])
return !packageJsonConfig.main || packageJsonConfig.browser; ];
}) const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions
.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
.map(extension => { .map(extension => {
const input = fromMarketplace(extension.name, extension.version, extension.metadata) const input = fromMarketplace(extension.name, extension.version, extension.metadata)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
return updateExtensionPackageJSON(input, (data) => { return updateExtensionPackageJSON(input, (data) => {
if (data.main) { delete data.scripts;
data.browser = data.main; delete data.dependencies;
} delete data.devDependencies;
data.extensionKind = ['web'];
return data; return data;
}); });
}); })));
return es.merge(extensions); return (marketplaceExtensionsStream
.pipe(util2.setExecutableBit(['**/*.sh'])));
} }
exports.packageMarketplaceWebExtensionsStream = packageMarketplaceWebExtensionsStream; exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;
function scanBuiltinExtensions(extensionsRoot, forWeb) { function scanBuiltinExtensions(extensionsRoot, exclude = []) {
const scannedExtensions = []; const scannedExtensions = [];
const extensionsFolders = fs.readdirSync(extensionsRoot); try {
for (const extensionFolder of extensionsFolders) { const extensionsFolders = fs.readdirSync(extensionsRoot);
const packageJSONPath = path.join(extensionsRoot, extensionFolder, 'package.json'); for (const extensionFolder of extensionsFolders) {
if (!fs.existsSync(packageJSONPath)) { if (exclude.indexOf(extensionFolder) >= 0) {
continue; 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')); return scannedExtensions;
const extensionKind = packageJSON['extensionKind'] || []; }
if (forWeb && extensionKind.indexOf('web') === -1) { catch (ex) {
continue; return scannedExtensions;
}
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;
} }
exports.scanBuiltinExtensions = scanBuiltinExtensions; exports.scanBuiltinExtensions = scanBuiltinExtensions;
function packageExternalExtensionsStream() { function packageExternalExtensionsStream() {

View File

@@ -21,6 +21,7 @@ import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors'; import * as ansiColors from 'ansi-colors';
const buffer = require('gulp-buffer'); const buffer = require('gulp-buffer');
import json = require('gulp-json-editor'); import json = require('gulp-json-editor');
import * as jsoncParser from 'jsonc-parser';
const webpack = require('webpack'); const webpack = require('webpack');
const webpackGulp = require('webpack-stream'); const webpackGulp = require('webpack-stream');
const util = require('./util'); const util = require('./util');
@@ -28,16 +29,21 @@ const root = path.dirname(path.dirname(__dirname));
const commit = util.getVersion(root); const commit = util.getVersion(root);
const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`; const sourceMappingURLBase = `https://sqlopsbuilds.blob.core.windows.net/sourcemaps/${commit}`;
function minimizeLanguageJSON(input: Stream): Stream { function minifyExtensionResources(input: Stream): Stream {
const tmLanguageJsonFilter = filter('**/*.tmLanguage.json', { restore: true }); const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
return input return input
.pipe(tmLanguageJsonFilter) .pipe(jsonFilter)
.pipe(buffer()) .pipe(buffer())
.pipe(es.mapSync((f: File) => { .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; return f;
})) }))
.pipe(tmLanguageJsonFilter.restore); .pipe(jsonFilter.restore);
} }
function updateExtensionPackageJSON(input: Stream, update: (data: any) => any): Stream { function updateExtensionPackageJSON(input: Stream, update: (data: any) => any): Stream {
@@ -61,16 +67,11 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream {
? fromLocalWebpack(extensionPath, webpackConfigFileName) ? fromLocalWebpack(extensionPath, webpackConfigFileName)
: fromLocalNormal(extensionPath); : fromLocalNormal(extensionPath);
if (forWeb) { if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data: any) => {
if (data.browser) {
data.main = data.browser;
}
data.extensionKind = ['web'];
return data;
});
} else if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data: any) => { input = updateExtensionPackageJSON(input, (data: any) => {
delete data.scripts;
delete data.dependencies;
delete data.devDependencies;
if (data.main) { if (data.main) {
data.main = data.main.replace('/out/', /dist/); 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(json({ __metadata: metadata }))
.pipe(packageJsonFilter.restore); .pipe(packageJsonFilter.restore);
} }
const excludedExtensions = [ const excludedExtensions = [
'vscode-api-tests', 'vscode-api-tests',
'vscode-web-playground',
'vscode-colorize-tests', 'vscode-colorize-tests',
'vscode-test-resolver', 'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
@@ -266,6 +265,10 @@ const rebuildExtensions = [
'mssql' 'mssql'
]; ];
const marketplaceWebExtensions = [
'ms-vscode.references-view'
];
interface IBuiltInExtension { interface IBuiltInExtension {
name: string; name: string;
version: string; version: string;
@@ -273,113 +276,134 @@ interface IBuiltInExtension {
metadata: any; 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 { type ExtensionKind = 'ui' | 'workspace' | 'web';
const localExtensionDescriptions = (<string[]>glob.sync('extensions/*/package.json')) interface IExtensionManifest {
.map(manifestPath => { main: string;
const extensionPath = path.dirname(path.join(root, manifestPath)); browser: string;
const extensionName = path.basename(extensionPath); extensionKind?: ExtensionKind | ExtensionKind[];
return { name: extensionName, path: extensionPath }; }
}) /**
.filter(({ name }) => excludedExtensions.indexOf(name) === -1) * Loosely based on `getExtensionKind` from `src/vs/workbench/services/extensions/common/extensionsUtil.ts`
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)) */
.filter(({ name }) => externalExtensions.indexOf(name) === -1); // {{SQL CARBON EDIT}} Remove external Extensions with separate package function isWebExtension(manifest: IExtensionManifest): boolean {
if (typeof manifest.extensionKind !== 'undefined') {
const extensionKind = Array.isArray(manifest.extensionKind) ? manifest.extensionKind : [manifest.extensionKind];
const localExtensions = localExtensionDescriptions.map(extension => { return (extensionKind.indexOf('web') >= 0);
return fromLocal(extension.path, false) }
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); return (!Boolean(manifest.main) || Boolean(manifest.browser));
});
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
return es.merge(nodeModules, ...localExtensions)
.pipe(util2.setExecutableBit(['**/*.sh']));
} }
export function packageLocalWebExtensionsStream(): NodeJS.ReadWriteStream { export function packageLocalExtensionsStream(forWeb: boolean): Stream {
const localExtensionDescriptions = (<string[]>glob.sync('extensions/*/package.json')) const localExtensionsDescriptions = (
.filter(manifestPath => { (<string[]>glob.sync('extensions/*/package.json'))
const packageJsonConfig = require(path.join(root, manifestPath)); .map(manifestPath => {
return !packageJsonConfig.main || packageJsonConfig.browser; const absoluteManifestPath = path.join(root, manifestPath);
}) const extensionPath = path.dirname(path.join(root, manifestPath));
.map(manifestPath => { const extensionName = path.basename(extensionPath);
const extensionPath = path.dirname(path.join(root, manifestPath)); return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
const extensionName = path.basename(extensionPath); })
return { name: extensionName, path: extensionPath }; .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 => { let result: Stream;
return fromLocal(extension.path, true) if (forWeb) {
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); 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 { export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream {
const extensions = builtInExtensions.map(extension => { const marketplaceExtensionsDescriptions = [
return fromMarketplace(extension.name, extension.version, extension.metadata) ...builtInExtensions.filter(({ name }) => (forWeb ? marketplaceWebExtensions.indexOf(name) >= 0 : true)),
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); ...(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) return (
.pipe(util2.setExecutableBit(['**/*.sh'])); marketplaceExtensionsStream
} .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);
} }
export interface IScannedBuiltinExtension { export interface IScannedBuiltinExtension {
extensionPath: string, extensionPath: string;
packageJSON: any, packageJSON: any;
packageNLSPath?: string, packageNLS?: any;
readmePath?: string, readmePath?: string;
changelogPath?: string, changelogPath?: string;
} }
export function scanBuiltinExtensions(extensionsRoot: string, forWeb: boolean): IScannedBuiltinExtension[] { export function scanBuiltinExtensions(extensionsRoot: string, exclude: string[] = []): IScannedBuiltinExtension[] {
const scannedExtensions: 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) { try {
// temporary const extensionsFolders = fs.readdirSync(extensionsRoot);
packageJSON = translatePackageJSON(packageJSON, path.join(extensionsRoot, extensionFolder, packageNLS)); 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({ return scannedExtensions;
extensionPath: extensionFolder, } catch (ex) {
packageJSON, return scannedExtensions;
packageNLSPath: packageNLS ? path.join(extensionFolder, packageNLS) : undefined,
readmePath: readme ? path.join(extensionFolder, readme) : undefined,
changelogPath: changelog ? path.join(extensionFolder, changelog) : undefined,
});
} }
return scannedExtensions;
} }
export function packageExternalExtensionsStream(): NodeJS.ReadWriteStream { export function packageExternalExtensionsStream(): NodeJS.ReadWriteStream {

View File

@@ -246,6 +246,10 @@
"name": "vs/workbench/services/configurationResolver", "name": "vs/workbench/services/configurationResolver",
"project": "vscode-workbench" "project": "vscode-workbench"
}, },
{
"name": "vs/workbench/services/crashReporter",
"project": "vscode-workbench"
},
{ {
"name": "vs/workbench/services/dialogs", "name": "vs/workbench/services/dialogs",
"project": "vscode-workbench" "project": "vscode-workbench"

View File

@@ -72,7 +72,7 @@ function loader(src, bundledFileHeader, bundleLoader) {
})) }))
.pipe(concat('vs/loader.js'))); .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); const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
// If a bundle ends up including in any of the sources our copyright, then // 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 // 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 treatedSources = sources.map(function (source) {
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
const base = source.path ? root + `/${src}` : ''; 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({ return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', path: path,
base: base, base: base,
contents: Buffer.from(source.contents) contents: Buffer.from(contents)
}); });
}); });
return es.readArray(treatedSources) return es.readArray(treatedSources)
@@ -104,9 +106,9 @@ function toConcatStream(src, bundledFileHeader, sources, dest) {
.pipe(concat(dest)) .pipe(concat(dest))
.pipe(stats_1.createStatsStream(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 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 = [ const DEFAULT_FILE_HEADER = [
@@ -122,6 +124,7 @@ function optimizeTask(opts) {
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
const out = opts.out; const out = opts.out;
const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents);
return function () { return function () {
const bundlesStream = es.through(); // this stream will contain the bundled files const bundlesStream = es.through(); // this stream will contain the bundled files
const resourcesStream = es.through(); // this stream will contain the resources const resourcesStream = es.through(); // this stream will contain the resources
@@ -130,7 +133,7 @@ function optimizeTask(opts) {
if (err || !result) { if (err || !result) {
return bundlesStream.emit('error', JSON.stringify(err)); 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 // Remove css inlined resources
const filteredResources = resources.slice(); const filteredResources = resources.slice();
result.cssInlinedResources.forEach(function (resource) { result.cssInlinedResources.forEach(function (resource) {

View File

@@ -18,7 +18,6 @@ import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors'; import * as ansiColors from 'ansi-colors';
import * as path from 'path'; import * as path from 'path';
import * as pump from 'pump'; import * as pump from 'pump';
import * as sm from 'source-map';
import * as terser from 'terser'; import * as terser from 'terser';
import * as VinylFile from 'vinyl'; import * as VinylFile from 'vinyl';
import * as bundle from './bundle'; import * as bundle from './bundle';
@@ -50,10 +49,6 @@ export function loaderConfig() {
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; 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 { function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream {
let sources = [ let sources = [
`${src}/vs/loader.js` `${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); const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
// If a bundle ends up including in any of the sources our copyright, then // 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 treatedSources = sources.map(function (source) {
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
const base = source.path ? root + `/${src}` : ''; 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({ return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', path: path,
base: base, 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)); .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 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) * (out folder name)
*/ */
languages?: Language[]; 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 = [ const DEFAULT_FILE_HEADER = [
@@ -180,6 +183,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
const out = opts.out; const out = opts.out;
const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents);
return function () { return function () {
const bundlesStream = es.through(); // this stream will contain the bundled files 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) { bundle.bundle(entryPoints, loaderConfig, function (err, result) {
if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } 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 // Remove css inlined resources
const filteredResources = resources.slice(); const filteredResources = resources.slice();

55
build/lib/preLaunch.js Normal file
View File

@@ -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);
});
}

65
build/lib/preLaunch.ts Normal file
View File

@@ -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<string> = []) {
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);
});
}

View File

@@ -41,6 +41,7 @@
"gulp-sourcemaps": "^1.11.0", "gulp-sourcemaps": "^1.11.0",
"gulp-uglify": "^3.0.0", "gulp-uglify": "^3.0.0",
"iconv-lite-umd": "0.6.8", "iconv-lite-umd": "0.6.8",
"jsonc-parser": "^2.3.0",
"mime": "^1.3.4", "mime": "^1.3.4",
"minimatch": "3.0.4", "minimatch": "3.0.4",
"minimist": "^1.2.3", "minimist": "^1.2.3",
@@ -49,7 +50,7 @@
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"terser": "4.3.8", "terser": "4.3.8",
"typescript": "^4.0.0-dev.20200722", "typescript": "^4.0.0-dev.20200803",
"vsce": "1.48.0", "vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.6.0", "vscode-telemetry-extractor": "^1.6.0",
"xml2js": "^0.4.17" "xml2js": "^0.4.17"

View File

@@ -14,7 +14,8 @@
"checkJs": true, "checkJs": true,
"strict": true, "strict": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true "noUnusedParameters": true,
"newLine": "lf"
}, },
"include": [ "include": [
"**/*.ts" "**/*.ts"

View File

@@ -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" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 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: jsonfile@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 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" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^4.0.0-dev.20200722: typescript@^4.0.0-dev.20200803:
version "4.0.0-dev.20200722" version "4.0.0-dev.20200803"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200722.tgz#b59dd5a3cd84a98d5aae0e4f3a3c58f0c81a3b9b" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200803.tgz#ea8b0e9fb2ee3085598ff200c8568f04f4cbb2ba"
integrity sha512-MmJ1YyPNK3JYeKLiTg5sQXdeZaMgt99Fg4BMRZhJmhoq1/x2V1cpXMYvE1rtIYl9K7NvmTDdU3WDW7ZOD6ybaw== integrity sha512-f/jDkFqCs0gbUd5MCUijO9u3AOMx1x1HdRDDHSidlc6uPVEkRduxjeTFhIXbGutO7ivzv+aC2sxH+1FQwsyBcg==
typical@^4.0.0: typical@^4.0.0:
version "4.0.0" version "4.0.0"

View File

@@ -330,5 +330,34 @@
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
"SOFTWARE." "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."
]
} }
] ]

View File

@@ -6,7 +6,7 @@
"git": { "git": {
"name": "chromium", "name": "chromium",
"repositoryUrl": "https://chromium.googlesource.com/chromium/src", "repositoryUrl": "https://chromium.googlesource.com/chromium/src",
"commitHash": "894fb9eb56c6cbda65e3c3ae9ada6d4cb5850cc9" "commitHash": "e4745133a1d3745f066e068b8033c6a269b59caf"
} }
}, },
"licenseDetail": [ "licenseDetail": [
@@ -40,7 +40,7 @@
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
], ],
"isOnlyProductionDependency": true, "isOnlyProductionDependency": true,
"version": "83.0.4103.122" "version": "78.0.3904.130"
}, },
{ {
"component": { "component": {
@@ -48,11 +48,11 @@
"git": { "git": {
"name": "nodejs", "name": "nodejs",
"repositoryUrl": "https://github.com/nodejs/node", "repositoryUrl": "https://github.com/nodejs/node",
"commitHash": "9622fed3fb2cffcea9efff6c8cb4cc2def99d75d" "commitHash": "787378879acfb212ed4ff824bf9f767a24a5cb43a"
} }
}, },
"isOnlyProductionDependency": true, "isOnlyProductionDependency": true,
"version": "12.14.1" "version": "12.8.1"
}, },
{ {
"component": { "component": {
@@ -60,12 +60,12 @@
"git": { "git": {
"name": "electron", "name": "electron",
"repositoryUrl": "https://github.com/electron/electron", "repositoryUrl": "https://github.com/electron/electron",
"commitHash": "a822d2639a9c9c2c670e91d73f78e921865ce38e" "commitHash": "5f93e889020d279d5a9cd1ecab080ab467312447"
} }
}, },
"isOnlyProductionDependency": true, "isOnlyProductionDependency": true,
"license": "MIT", "license": "MIT",
"version": "9.1.0" "version": "7.3.2"
}, },
{ {
"component": { "component": {

View File

@@ -46,6 +46,15 @@
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'." "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": { "postAttachCommand": {
"type": [ "type": [
"string", "string",

View File

@@ -92,6 +92,15 @@
"type": "integer", "type": "integer",
"description": "The port VS Code can use to connect to its backend." "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": { "codespaces": {
"type": "object", "type": "object",
"description": "Codespaces-specific configuration." "description": "Codespaces-specific configuration."

View File

@@ -42,11 +42,11 @@ export class SettingsDocument {
}); });
} }
// sync.ignoredExtensions // settingsSync.ignoredExtensions
if (location.path[0] === 'sync.ignoredExtensions') { if (location.path[0] === 'settingsSync.ignoredExtensions') {
let ignoredExtensions = []; let ignoredExtensions = [];
try { try {
ignoredExtensions = parse(this.document.getText())['sync.ignoredExtensions']; ignoredExtensions = parse(this.document.getText())['settingsSync.ignoredExtensions'];
} catch (e) {/* ignore error */ } } catch (e) {/* ignore error */ }
return provideInstalledExtensionProposals(ignoredExtensions, range, true); 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('[')) { 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 // Suggestion model word matching includes closed sqaure bracket and ending quote
// Hence include them in the proposal to replace // 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 this.provideLanguageCompletionItemsForLanguageOverrides(location, range, language => `"[${language}]"`);
} }
return Promise.resolve([]); return Promise.resolve([]);

View File

@@ -14,6 +14,7 @@
"id": "dockerfile", "id": "dockerfile",
"extensions": [ ".dockerfile", ".containerfile" ], "extensions": [ ".dockerfile", ".containerfile" ],
"filenames": [ "Dockerfile", "Containerfile" ], "filenames": [ "Dockerfile", "Containerfile" ],
"filenamePatterns": [ "Dockerfile.*", "Containerfile.*" ],
"aliases": [ "Dockerfile", "Containerfile" ], "aliases": [ "Dockerfile", "Containerfile" ],
"configuration": "./language-configuration.json" "configuration": "./language-configuration.json"
}], }],

View File

@@ -3,4 +3,5 @@ src/**
tsconfig.json tsconfig.json
out/** out/**
extension.webpack.config.js extension.webpack.config.js
yarn.lock extension-browser.webpack.config.js
yarn.lock

View File

@@ -753,149 +753,49 @@
"group": "navigation", "group": "navigation",
"when": "scmProvider == git" "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", "command": "git.checkout",
"group": "2_branch", "group": "1_header",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.publish", "command": "git.clone",
"group": "2_branch", "group": "1_header",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStaged", "submenu": "git.commit",
"group": "4_commit", "group": "2_main@1",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStagedSigned", "submenu": "git.changes",
"group": "4_commit", "group": "2_main@2",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStagedAmend", "submenu": "git.pullpush",
"group": "4_commit", "group": "2_main@3",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAll", "submenu": "git.branch",
"group": "4_commit", "group": "2_main@4",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAllSigned", "submenu": "git.remotes",
"group": "4_commit", "group": "2_main@5",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAllAmend", "submenu": "git.stash",
"group": "4_commit", "group": "2_main@6",
"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",
"when": "scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.showOutput", "command": "git.showOutput",
"group": "7_repository", "group": "3_footer",
"when": "scmProvider == git" "when": "scmProvider == git"
} }
], ],
@@ -1307,8 +1207,184 @@
"group": "5_copy@2", "group": "5_copy@2",
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file:commit\\b/" "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": { "configuration": {
"title": "Git", "title": "Git",
"properties": { "properties": {
@@ -1425,6 +1501,11 @@
"description": "%config.ignoreMissingGitWarning%", "description": "%config.ignoreMissingGitWarning%",
"default": false "default": false
}, },
"git.ignoreWindowsGit27Warning": {
"type": "boolean",
"description": "%config.ignoreWindowsGit27Warning%",
"default": false
},
"git.ignoreLimitWarning": { "git.ignoreLimitWarning": {
"type": "boolean", "type": "boolean",
"description": "%config.ignoreLimitWarning%", "description": "%config.ignoreLimitWarning%",

View File

@@ -99,6 +99,7 @@
"config.branchWhitespaceChar": "The character to replace whitespace in new branch names.", "config.branchWhitespaceChar": "The character to replace whitespace in new branch names.",
"config.ignoreLegacyWarning": "Ignores the legacy Git warning.", "config.ignoreLegacyWarning": "Ignores the legacy Git warning.",
"config.ignoreMissingGitWarning": "Ignores the warning when Git is missing.", "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.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository.",
"config.defaultCloneDirectory": "The default location to clone a git repository.", "config.defaultCloneDirectory": "The default location to clone a git repository.",
"config.enableSmartCommit": "Commit all changes when there are no staged changes.", "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.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.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.", "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.added": "Color for added resources.",
"colors.modified": "Color for modified resources.", "colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.", "colors.deleted": "Color for deleted resources.",

View File

@@ -543,11 +543,11 @@ export class CommandCenter {
const uri = Uri.file(repositoryPath); const uri = Uri.file(repositoryPath);
if (openFolder) { if (openFolder) {
commands.executeCommand('vscode.openFolder', uri); commands.executeCommand('vscode.openFolder', uri, { forceReuseWindow: true });
} else if (result === addToWorkspace) { } else if (result === addToWorkspace) {
workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri }); workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri });
} else if (result === openNewWindow) { } else if (result === openNewWindow) {
commands.executeCommand('vscode.openFolder', uri, true); commands.executeCommand('vscode.openFolder', uri, { forceNewWindow: true });
} }
} catch (err) { } catch (err) {
if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) {

View File

@@ -209,14 +209,25 @@ async function checkGitWindows(info: IGit): Promise<void> {
return; return;
} }
const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreWindowsGit27Warning') === true;
if (shouldIgnore) {
return;
}
const update = localize('updateGit', "Update Git"); const update = localize('updateGit', "Update Git");
const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
const choice = await window.showWarningMessage( 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), 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) { if (choice === update) {
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/')); commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
} else if (choice === neverShowAgain) {
await config.update('ignoreWindowsGit27Warning', true, true);
} }
} }

View File

@@ -61,6 +61,15 @@ class SyncStatusBar {
} }
constructor(private repository: Repository, private remoteSourceProviderRegistry: IRemoteSourceProviderRegistry) { 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.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables);
repository.onDidChangeOperations(this.onDidChangeOperations, 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')); const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync'));
onEnablementChange(this.updateEnablement, this, this.disposables); onEnablementChange(this.updateEnablement, this, this.disposables);
this.updateEnablement(); this.updateEnablement();
this._state = {
enabled: true,
isSyncRunning: false,
hasRemotes: false,
HEAD: undefined,
remoteSourceProviders: this.remoteSourceProviderRegistry.getRemoteProviders()
.filter(p => !!p.publishRepository)
};
} }
private updateEnablement(): void { private updateEnablement(): void {

View File

@@ -65,27 +65,32 @@ export class GitTimelineProvider implements TimelineProvider {
readonly id = 'git-history'; readonly id = 'git-history';
readonly label = localize('git.timeline.source', '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 repo: Repository | undefined;
private repoDisposable: Disposable | undefined; private repoDisposable: Disposable | undefined;
private repoStatusDate: Date | undefined; private repoStatusDate: Date | undefined;
constructor(private readonly _model: Model) { constructor(private readonly model: Model) {
this.disposable = Disposable.from( this.disposable = Disposable.from(
_model.onDidOpenRepository(this.onRepositoriesChanged, this), model.onDidOpenRepository(this.onRepositoriesChanged, this),
workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this),
); );
if (model.repositories.length) {
this.ensureProviderRegistration();
}
} }
dispose() { dispose() {
this.providerDisposable?.dispose();
this.disposable.dispose(); this.disposable.dispose();
} }
async provideTimeline(uri: Uri, options: TimelineOptions, _token: CancellationToken): Promise<Timeline> { async provideTimeline(uri: Uri, options: TimelineOptions, _token: CancellationToken): Promise<Timeline> {
// console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`); // console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`);
const repo = this._model.getRepository(uri); const repo = this.model.getRepository(uri);
if (!repo) { if (!repo) {
this.repoDisposable?.dispose(); this.repoDisposable?.dispose();
this.repoStatusDate = undefined; this.repoStatusDate = undefined;
@@ -110,7 +115,7 @@ export class GitTimelineProvider implements TimelineProvider {
let limit: number | undefined; let limit: number | undefined;
if (options.limit !== undefined && typeof options.limit !== 'number') { if (options.limit !== undefined && typeof options.limit !== 'number') {
try { 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) { 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 // 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; 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) { private onRepositoriesChanged(_repo: Repository) {
// console.log(`GitTimelineProvider.onRepositoriesChanged`); // console.log(`GitTimelineProvider.onRepositoriesChanged`);
this.ensureProviderRegistration();
// TODO@eamodio: Being naive for now and just always refreshing each time there is a new repository // TODO@eamodio: Being naive for now and just always refreshing each time there is a new repository
this.fireChanged(); this.fireChanged();
} }

View File

@@ -1,8 +1,10 @@
.gitignore
src/** src/**
!src/common/config.json !src/common/config.json
out/** out/**
build/** build/**
extension.webpack.config.js extension.webpack.config.js
extension-browser.webpack.config.js
tsconfig.json tsconfig.json
yarn.lock yarn.lock
README.md README.md

View File

@@ -9,7 +9,7 @@ import { keychain } from './common/keychain';
import { GitHubServer, NETWORK_ERROR } from './githubServer'; import { GitHubServer, NETWORK_ERROR } from './githubServer';
import Logger from './common/logger'; import Logger from './common/logger';
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>(); export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
interface SessionData { interface SessionData {
id: string; id: string;

View File

@@ -79,7 +79,7 @@ export class GitHubServer {
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
if (this.isTestEnvironment(callbackUri)) { 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'); } if (!token) { throw new Error('Sign in failed: No token provided'); }
this.updateStatusBarItem(false); this.updateStatusBarItem(false);
return token; return token;

View File

@@ -1,3 +0,0 @@
dist
out
node_modules

View File

@@ -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.

View File

@@ -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'
}
});

View File

@@ -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"
}
}

View File

@@ -1,4 +0,0 @@
{
"displayName": "GitHub Browser",
"description": "Remotely browse a GitHub repository"
}

View File

@@ -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<T extends string | Uri = string> {
type: 'created';
size: number;
timestamp: number;
uri: T;
hash: string;
originalHash: string;
}
interface ChangeOperation<T extends string | Uri = string> {
type: 'changed';
size: number;
timestamp: number;
uri: T;
hash: string;
originalHash: string;
}
interface DeleteOperation<T extends string | Uri = string> {
type: 'deleted';
size: undefined;
timestamp: number;
uri: T;
hash: undefined;
originalHash: undefined;
}
export type Operation = CreateOperation<Uri> | ChangeOperation<Uri> | DeleteOperation<Uri>;
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<ChangeStoreEvent>;
acceptAll(rootUri: Uri): Promise<void>;
discard(uri: Uri): Promise<void>;
discardAll(rootUri: Uri): Promise<void>;
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<ChangeStoreEvent>;
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<Uint8Array>): Promise<void>;
onFileCreated(uri: Uri, content: Uint8Array): Promise<void>;
onFileDeleted(uri: Uri): Promise<void>;
}
export class ChangeStore implements IChangeStore, IWritableChangeStore {
private _onDidChange = new EventEmitter<ChangeStoreEvent>();
get onDidChange(): Event<ChangeStoreEvent> {
return this._onDidChange.event;
}
constructor(private readonly memento: Memento) { }
async acceptAll(rootUri: Uri): Promise<void> {
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<void> {
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<void> {
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<Uint8Array>): Promise<void> {
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<void> {
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<void> {
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<void> {
await this.memento.update(`${workingOperationsKeyPrefix}${rootUri.toString()}`, operations);
}
private async saveWorkingContent(uri: Uri, content: string): Promise<void> {
await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, content);
}
private async discardWorkingContent(uri: Uri): Promise<void> {
await this.memento.update(`${workingFileKeyPrefix}${uri.toString()}`, undefined);
}
}

View File

@@ -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<T> {
context: T;
name: string;
folderUri: Uri;
}
export class ContextStore<T> {
private _onDidChange = new EventEmitter<Uri>();
get onDidChange(): Event<Uri> {
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<T>(`${this.originalScheme}.context|${this.getOriginalResource(uri).toString()}`);
}
getForWorkspace(): WorkspaceFolderContext<T>[] {
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 });
}
}

View File

@@ -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<GitHubApiContext>('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');
}

View File

@@ -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<FileChangeEvent[]>();
get onDidChangeFile(): Event<FileChangeEvent[]> {
return this._onDidChangeFile.event;
}
private readonly disposable: Disposable;
constructor(
readonly scheme: string,
private readonly contextStore: ContextStore<GitHubApiContext>,
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<FileStat> {
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<void> {
// TODO@eamodio only support files for now
throw FileSystemError.NoPermissions();
}
async readFile(uri: Uri): Promise<Uint8Array> {
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<void> {
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<void> {
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<void> {
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<void> {
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<TextSearchResult>,
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
}

View File

@@ -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<T>(obj: T | Promise<T>): obj is Promise<T> {
return typeof (obj as Promise<T>)?.then === 'function';
}
export function gate<T extends (...arg: any) => any>(resolver?: (...args: Parameters<T>) => 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<T>))}`;
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;
};
};
}

View File

@@ -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 Array<unknown>> = T extends (infer U)[] ? U : never;
type GitCreateTreeParamsTree = ArrayElement<NonNullable<Parameters<Octokit['git']['createTree']>[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<Uri>();
get onDidChangeContext(): Event<Uri> {
return this._onDidChangeContext.event;
}
private readonly disposable: Disposable;
constructor(private readonly context: ContextStore<GitHubApiContext>) {
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<typeof Octokit>[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<string | undefined> {
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<T>(uri: Uri, innerQuery: string): Promise<T | undefined> {
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<SearchQueryResults> {
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<T>(query: string, variables: { [key: string]: string | number }): Promise<T | undefined> {
return (await this.graphql())<T>(query, variables);
}
private readonly pendingContextRequests = new Map<string, Promise<GitHubApiContext>>();
async getContext(uri: Uri): Promise<GitHubApiContext> {
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<string, GitHubApiContext>();
private async getContextCore(rootUri: Uri): Promise<GitHubApiContext> {
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;
}

View File

@@ -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<FileChangeEvent[]>();
get onDidChangeFile(): Event<FileChangeEvent[]> {
return this._onDidChangeFile.event;
}
private readonly disposable: Disposable;
private fsCache = new Map<string, Map<string, any>>();
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<string, any>();
this.fsCache.set(rootUri.toString(), cache);
}
return cache;
}
//#region FileSystemProvider
watch(): Disposable {
return emptyDisposable;
}
async stat(uri: Uri): Promise<FileStat> {
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<void> {
throw FileSystemError.NoPermissions();
}
async readFile(uri: Uri): Promise<Uint8Array> {
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<void> {
throw FileSystemError.NoPermissions();
}
delete(_uri: Uri, _options: { recursive: boolean }): void | Thenable<void> {
throw FileSystemError.NoPermissions();
}
rename(_oldUri: Uri, _newUri: Uri, _options: { overwrite: boolean }): void | Thenable<void> {
throw FileSystemError.NoPermissions();
}
copy(_source: Uri, _destination: Uri, _options: { overwrite: boolean }): void | Thenable<void> {
throw FileSystemError.NoPermissions();
}
//#endregion
//#region FileSearchProvider
private fileSearchCache = new Map<string, Fuzzysort.Prepared[]>();
async provideFileSearchResults(
query: FileSearchQuery,
options: FileSearchOptions,
token: CancellationToken,
): Promise<Uri[]> {
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<TextSearchResult>,
_token: CancellationToken,
): Promise<TextSearchComplete> {
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<T>(uri: Uri, query: string, cache?: Map<string, any>): Promise<T | undefined> {
const key = `${uri.toString()}:${getHashCode(query)}`;
let data = cache?.get(key);
if (data !== undefined) {
return data as T;
}
data = await this.github.fsQuery<T>(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;
}

View File

@@ -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<T, TMapped>(
source: Iterable<T> | IterableIterator<T>,
predicateMapper: (item: T) => TMapped | undefined | null,
): Iterable<TMapped> {
for (const item of source) {
const mapped = predicateMapper(item);
if (mapped !== undefined && mapped !== null) {
yield mapped;
}
}
}
export function* map<T, TMapped>(
source: Iterable<T> | IterableIterator<T>,
mapper: (item: T) => TMapped,
): Iterable<TMapped> {
for (const item of source) {
yield mapper(item);
}
}
}

View File

@@ -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<void> {
const operations = this.changeStore
.getChanges(sourceControl.rootUri!)
.map<CommitOperation>(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<void> {
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<SourceControlResourceState>(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 });
}
}

View File

@@ -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<string> {
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;
}
}
}
}

View File

@@ -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<string, StatusBarItem>();
constructor(
private readonly contextStore: ContextStore<GitHubApiContext>,
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<GitHubApiContext>) {
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);
}
}
}
}
}

View File

@@ -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.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
/// <reference path="../../../types/lib.textEncoder.d.ts" />

View File

@@ -1,14 +0,0 @@
{
"extends": "../shared.tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"lib": [
"es2018",
"dom"
],
"outDir": "./out"
},
"include": [
"src/**/*"
]
}

View File

@@ -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=

View File

@@ -140,6 +140,10 @@ export async function publishRepository(gitAPI: GitAPI, repository?: Repository)
const ignored = new Set(children); const ignored = new Set(children);
result.forEach(c => ignored.delete(c.label)); result.forEach(c => ignored.delete(c.label));
if (ignored.size === 0) {
return;
}
const raw = [...ignored].map(i => `/${i}`).join('\n'); const raw = [...ignored].map(i => `/${i}`).join('\n');
const encoder = new TextEncoder(); const encoder = new TextEncoder();
await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw)); await vscode.workspace.fs.writeFile(gitignore, encoder.encode(raw));

View File

@@ -4,6 +4,7 @@ tsconfig.json
out/test/** out/test/**
out/** out/**
extension.webpack.config.js extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json cgmanifest.json
yarn.lock yarn.lock
preview-src/** preview-src/**

View File

@@ -4,7 +4,8 @@
"description": "%description%", "description": "%description%",
"extensionKind": [ "extensionKind": [
"ui", "ui",
"workspace" "workspace",
"web"
], ],
"version": "1.0.0", "version": "1.0.0",
"publisher": "vscode", "publisher": "vscode",

View File

@@ -14,7 +14,7 @@
"dependencies": { "dependencies": {
"jsonc-parser": "^2.2.1", "jsonc-parser": "^2.2.1",
"request-light": "^0.3.0", "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-languageserver": "7.0.0-next.3",
"vscode-uri": "^2.1.2" "vscode-uri": "^2.1.2"
}, },

View File

@@ -80,10 +80,10 @@ request-light@^0.3.0:
https-proxy-agent "^2.2.4" https-proxy-agent "^2.2.4"
vscode-nls "^4.1.1" vscode-nls "^4.1.1"
vscode-json-languageservice@^3.7.0: vscode-json-languageservice@^3.8.0:
version "3.7.0" version "3.8.0"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.7.0.tgz#0174417f139cf41dd60c84538fd052385bfb46f6" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.8.0.tgz#c7e7283f993e3db39fa5501407b023ada6fd3ae3"
integrity sha512-nGLqcBhTjdfkl8Dz9sYGK/ZCTjscYFoIjYw+qqkWB+vyNfM0k/AyIoT73DQvB/PArteCKjEVfQUF72GRZEDSbQ== integrity sha512-sYz5JElJMIlPoqhrRfG3VKnDjnPinLdblIiEVsJgTz1kj2hWD2q5BSbo+evH/5/jKDXDLfA8kb0lHC4vd5g5zg==
dependencies: dependencies:
jsonc-parser "^2.2.1" jsonc-parser "^2.2.1"
vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-textdocument "^1.0.1"

View File

@@ -1,4 +1,5 @@
test/** test/**
test-workspace/**
src/** src/**
tsconfig.json tsconfig.json
out/test/** out/test/**

View File

@@ -128,21 +128,12 @@ textarea:focus {
} }
p { p {
margin-bottom: 1.5em; margin-bottom: 0.7em;
}
li > p {
margin-bottom: 0;
}
/* don't space 2 paragraphs too far apart */
p + p {
margin-top: -0.8em;
} }
ul, ul,
ol { ol {
margin-bottom: 1.5em; margin-bottom: 0.7em;
} }
hr { hr {

View File

@@ -129,7 +129,6 @@ export class MarkdownEngine {
} }
this.currentDocument = document.uri; this.currentDocument = document.uri;
this._slugCount = new Map<string, number>();
const tokens = this.tokenizeString(document.getText(), engine); const tokens = this.tokenizeString(document.getText(), engine);
this._tokenCache.update(document, config, tokens); this._tokenCache.update(document, config, tokens);
@@ -144,6 +143,8 @@ export class MarkdownEngine {
} }
private tokenizeString(text: string, engine: MarkdownIt) { private tokenizeString(text: string, engine: MarkdownIt) {
this._slugCount = new Map<string, number>();
return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {}); return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {});
} }
@@ -362,4 +363,3 @@ function normalizeHighlightLang(lang: string | undefined) {
return lang; return lang;
} }
} }

View File

@@ -2,4 +2,5 @@ src/**
tsconfig.json tsconfig.json
out/** out/**
extension.webpack.config.js extension.webpack.config.js
yarn.lock extension-browser.webpack.config.js
yarn.lock

View File

@@ -1,10 +1,14 @@
.vscode/** .vscode/**
.vscode-test/** .vscode-test/**
out/test/** out/test/**
out/**
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
src/** src/**
.gitignore .gitignore
vsc-extension-quickstart.md vsc-extension-quickstart.md
**/tsconfig.json **/tsconfig.json
**/tslint.json **/tslint.json
**/*.map **/*.map
**/*.ts **/*.ts

View File

@@ -17,7 +17,8 @@
], ],
"extensionKind": [ "extensionKind": [
"ui", "ui",
"workspace" "workspace",
"web"
], ],
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js", "main": "./out/extension.js",

View File

@@ -73,7 +73,7 @@ function parseQuery(uri: vscode.Uri) {
}, {}); }, {});
} }
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>(); export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
export const REFRESH_NETWORK_FAILURE = 'Network failure'; export const REFRESH_NETWORK_FAILURE = 'Network failure';
@@ -339,7 +339,7 @@ export class AzureActiveDirectoryService {
} }
private getCallbackEnvironment(callbackUri: vscode.Uri): string { 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},`; return `${callbackUri.authority},`;
} }
@@ -471,7 +471,10 @@ export class AzureActiveDirectoryService {
redirect_uri: redirectUrl 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', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',

View File

@@ -7,8 +7,5 @@
}, },
"scripts": { "scripts": {
"postinstall": "node ./postinstall" "postinstall": "node ./postinstall"
},
"devDependencies": {
"rimraf": "^3.0.2"
} }
} }

View File

@@ -1,6 +1,8 @@
test/** test/**
src/** src/**
out/**
tsconfig.json tsconfig.json
extension.webpack.config.js extension.webpack.config.js
extension-browser.webpack.config.js
cgmanifest.json cgmanifest.json
.vscode .vscode

View File

@@ -9,7 +9,7 @@
"activationEvents": ["onLanguage:python"], "activationEvents": ["onLanguage:python"],
"main": "./out/pythonMain", "main": "./out/pythonMain",
"browser": "./dist/browser/pythonMain", "browser": "./dist/browser/pythonMain",
"extensionKind": [ "ui", "workspace" ], "extensionKind": [ "ui", "workspace", "web" ],
"contributes": { "contributes": {
"languages": [{ "languages": [{
"id": "python", "id": "python",

View File

@@ -1,11 +1,6 @@
.vscode/**
build/**
dist/**
out/**
src/** src/**
typings/** out/**
.gitignore
extension-browser.webpack.config.js
extension.webpack.config.js
tsconfig.json tsconfig.json
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock yarn.lock

View File

@@ -6,20 +6,17 @@
//@ts-check //@ts-check
'use strict'; '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, context: __dirname,
node: false,
entry: { entry: {
extension: './src/extension.ts' extension: './src/extension.ts'
}, },
resolve: { output: {
alias: { filename: 'extension.js',
'node-fetch': path.resolve(__dirname, 'node_modules/node-fetch/browser.js') path: path.join(__dirname, 'dist')
}
} }
}); });
module.exports = config;

View File

@@ -12,6 +12,7 @@
"Programming Languages" "Programming Languages"
], ],
"main": "./out/extension.js", "main": "./out/extension.js",
"browser": "./dist/extension.js",
"activationEvents": [ "activationEvents": [
"*" "*"
], ],

View File

@@ -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))); 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) { if (vscode.workspace.workspaceFolders) {
const multiRootFormattedPath = /^(.*) • (.*)$/.exec(path); const multiRootFormattedPath = /^(.*) • (.*)$/.exec(path);
@@ -133,17 +135,18 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u
const [, workspaceName, workspacePath] = multiRootFormattedPath; const [, workspaceName, workspacePath] = multiRootFormattedPath;
const folder = vscode.workspace.workspaceFolders.filter(wf => wf.name === workspaceName)[0]; const folder = vscode.workspace.workspaceFolders.filter(wf => wf.name === workspaceName)[0];
if (folder) { if (folder) {
return vscode.Uri.file(pathUtils.join(folder.uri.fsPath, workspacePath)); return uriFromFolderWithPath(folder, workspacePath);
} }
} }
else if (vscode.workspace.workspaceFolders.length === 1) { 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') { } else if (resultsUri.scheme !== 'untitled') {
// We're in a multi-root workspace, but the path is not multi-root formatted // 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. // 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]; 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);
}
} }
} }

View File

@@ -2,86 +2,7 @@
# yarn lockfile v1 # 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: typescript@3.9.7:
version "3.9.7" version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== 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=

View File

@@ -93,10 +93,10 @@
"vscode-ripgrep": "^1.8.0", "vscode-ripgrep": "^1.8.0",
"vscode-sqlite3": "4.0.10", "vscode-sqlite3": "4.0.10",
"vscode-textmate": "5.2.0", "vscode-textmate": "5.2.0",
"xterm": "4.8.1", "xterm": "4.9.0-beta.8",
"xterm-addon-search": "0.7.0", "xterm-addon-search": "0.7.0",
"xterm-addon-unicode11": "0.2.0", "xterm-addon-unicode11": "0.2.0",
"xterm-addon-webgl": "0.7.0", "xterm-addon-webgl": "0.8.0",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
@@ -136,7 +136,7 @@
"css-loader": "^3.2.0", "css-loader": "^3.2.0",
"debounce": "^1.0.0", "debounce": "^1.0.0",
"deemon": "^1.4.0", "deemon": "^1.4.0",
"electron": "9.1.0", "electron": "7.3.2",
"eslint": "6.8.0", "eslint": "6.8.0",
"eslint-plugin-jsdoc": "^19.1.0", "eslint-plugin-jsdoc": "^19.1.0",
"event-stream": "3.3.4", "event-stream": "3.3.4",

View File

@@ -67,7 +67,8 @@
"extensionAllowedProposedApi": [ "extensionAllowedProposedApi": [
"ms-vscode.vscode-js-profile-flame", "ms-vscode.vscode-js-profile-flame",
"ms-vscode.vscode-js-profile-table", "ms-vscode.vscode-js-profile-table",
"ms-vscode.references-view" "ms-vscode.references-view",
"ms-vscode.github-browser"
], ],
"extensionsGallery": { "extensionsGallery": {
"serviceUrl": "https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json" "serviceUrl": "https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json"

View File

@@ -1,3 +1,3 @@
disturl "http://nodejs.org/dist" disturl "http://nodejs.org/dist"
target "12.14.1" target "12.4.0"
runtime "node" runtime "node"

View File

@@ -38,10 +38,10 @@
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.8.0", "vscode-ripgrep": "^1.8.0",
"vscode-textmate": "5.2.0", "vscode-textmate": "5.2.0",
"xterm": "4.8.1", "xterm": "4.9.0-beta.8",
"xterm-addon-search": "0.7.0", "xterm-addon-search": "0.7.0",
"xterm-addon-unicode11": "0.2.0", "xterm-addon-unicode11": "0.2.0",
"xterm-addon-webgl": "0.7.0", "xterm-addon-webgl": "0.8.0",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"

View File

@@ -25,10 +25,10 @@
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33", "slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"vscode-oniguruma": "1.3.1", "vscode-oniguruma": "1.3.1",
"vscode-textmate": "5.2.0", "vscode-textmate": "5.2.0",
"xterm": "4.8.1", "xterm": "4.9.0-beta.8",
"xterm-addon-search": "0.7.0", "xterm-addon-search": "0.7.0",
"xterm-addon-unicode11": "0.2.0", "xterm-addon-unicode11": "0.2.0",
"xterm-addon-webgl": "0.7.0", "xterm-addon-webgl": "0.8.0",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
} }
} }

View File

@@ -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" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c"
integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q==
xterm-addon-webgl@0.7.0: xterm-addon-webgl@0.8.0:
version "0.7.0" version "0.8.0"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f"
integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ==
xterm@4.8.1: xterm@4.9.0-beta.8:
version "4.8.1" version "4.9.0-beta.8"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805"
integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA==
zone.js@^0.8.4: zone.js@^0.8.4:
version "0.8.29" version "0.8.29"

View File

@@ -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" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c"
integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q== integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q==
xterm-addon-webgl@0.7.0: xterm-addon-webgl@0.8.0:
version "0.7.0" version "0.8.0"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0.tgz#a13732ac937170e53ce02ec91963da042c80614b" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f"
integrity sha512-PMWLgccAF31GulCYkQxIA8qwMI4q4UbRi5O/zwMnSJWBozB0yy84lX31ZhJeJhcrlEn1Vpcd+OUGPE8Z1hBjnw== integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ==
xterm@4.8.1: xterm@4.9.0-beta.8:
version "4.8.1" version "4.9.0-beta.8"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805"
integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ== integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA==
yauzl@^2.9.2: yauzl@^2.9.2:
version "2.10.0" version "2.10.0"

View File

@@ -64,56 +64,25 @@ const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;
const exists = (path) => util.promisify(fs.exists)(path); const exists = (path) => util.promisify(fs.exists)(path);
const readFile = (path) => util.promisify(fs.readFile)(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() { async function getBuiltInExtensionInfos() {
const extensions = []; const allExtensions = [];
/** @type {Object.<string, string>} */ /** @type {Object.<string, string>} */
const locations = {}; const locations = {};
for (const extensionsRoot of [BUILTIN_EXTENSIONS_ROOT, BUILTIN_MARKETPLACE_EXTENSIONS_ROOT]) { const [localExtensions, marketplaceExtensions] = await Promise.all([
if (await exists(extensionsRoot)) { extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT),
const children = await readdirWithFileTypes(extensionsRoot); extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT),
await Promise.all(children.map(async child => { ]);
if (child.isDirectory()) { for (const ext of localExtensions) {
const extensionPath = path.join(extensionsRoot, child.name); allExtensions.push(ext);
const info = await getBuiltInExtensionInfo(extensionPath); locations[ext.extensionPath] = path.join(BUILTIN_EXTENSIONS_ROOT, ext.extensionPath);
if (info) {
extensions.push(info);
locations[path.basename(extensionPath)] = extensionPath;
}
}
}));
}
} }
return { extensions, locations }; for (const ext of marketplaceExtensions) {
} allExtensions.push(ext);
locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath);
async function getBuiltInExtensionInfo(extensionPath) {
const packageJSON = await getExtensionPackageJSON(extensionPath);
if (!packageJSON) {
return undefined;
} }
const builtInExtensionPath = path.basename(extensionPath); return { extensions: allExtensions, locations };
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
};
} }
async function getDefaultExtensionInfos() { async function getDefaultExtensionInfos() {
@@ -124,7 +93,7 @@ async function getDefaultExtensionInfos() {
let extensionArg = args['extension']; let extensionArg = args['extension'];
if (!extensionArg) { if (!extensionArg) {
return { extensions, locations } return { extensions, locations };
} }
const extensionPaths = Array.isArray(extensionArg) ? extensionArg : [extensionArg]; const extensionPaths = Array.isArray(extensionArg) ? extensionArg : [extensionArg];
@@ -154,8 +123,6 @@ async function getExtensionPackageJSON(extensionPath) {
} }
if (packageJSON.browser) { if (packageJSON.browser) {
packageJSON.main = packageJSON.browser;
let mainFilePath = path.join(extensionPath, packageJSON.browser); let mainFilePath = path.join(extensionPath, packageJSON.browser);
if (path.extname(mainFilePath) !== '.js') { if (path.extname(mainFilePath) !== '.js') {
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.`); 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 packageNLSPath = path.join(extensionPath, 'package.nls.json');
const packageNLSExists = await exists(packageNLSPath); const packageNLSExists = await exists(packageNLSPath);
@@ -273,7 +239,9 @@ async function handleExtension(req, res, parsedUrl) {
if (!filePath) { if (!filePath) {
return serveError(req, res, 400, `Bad request.`); 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) { if (!filePath) {
return serveError(req, res, 400, `Bad request.`); 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); 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 { } else {
let cs = qs.get('cs'); let cs = qs.get('cs');
if (cs) { if (cs) {
@@ -318,7 +289,8 @@ async function handleRoot(req, res) {
} }
const [owner, repo, ...branch] = cs.split('/'); 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: '/' };
} }
} }
} }

View File

@@ -5,27 +5,17 @@ title VSCode Dev
pushd %~dp0\.. pushd %~dp0\..
:: Node modules :: Get electron, compile, built-in extensions
if not exist node_modules call yarn 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 for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
set NAMESHORT=%NAMESHORT: "=% set NAMESHORT=%NAMESHORT: "=%
set NAMESHORT=%NAMESHORT:"=%.exe set NAMESHORT=%NAMESHORT:"=%.exe
set CODE=".build\electron\%NAMESHORT%" 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 :: Manage built-in extensions
if "%1"=="--builtin" goto builtin if "%1"=="--builtin" goto builtin
:: Sync built-in extensions
node build\lib\builtInExtensions.js
:: Build
if not exist out yarn compile
:: Configuration :: Configuration
set ELECTRON_RUN_AS_NODE=1 set ELECTRON_RUN_AS_NODE=1
set NODE_ENV=development set NODE_ENV=development

View File

@@ -18,11 +18,10 @@ function code() {
CODE=".build/electron/$NAME" CODE=".build/electron/$NAME"
fi fi
# Node modules # Get electron, compile, built-in extensions
test -d node_modules || yarn if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then
node build/lib/preLaunch.js
# Get electron fi
yarn electron
# Manage built-in extensions # Manage built-in extensions
if [[ "$1" == "--builtin" ]]; then if [[ "$1" == "--builtin" ]]; then
@@ -30,12 +29,6 @@ function code() {
return return
fi fi
# Sync built-in extensions
node build/lib/builtInExtensions.js
# Build
test -d out || yarn compile
ELECTRON_RUN_AS_NODE=1 \ ELECTRON_RUN_AS_NODE=1 \
NODE_ENV=development \ NODE_ENV=development \
VSCODE_DEV=1 \ VSCODE_DEV=1 \

View File

@@ -5,26 +5,17 @@ title VSCode Dev
pushd %~dp0\.. pushd %~dp0\..
:: Node modules :: Get electron, compile, built-in extensions
if not exist node_modules call yarn 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 for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
set NAMESHORT=%NAMESHORT: "=% set NAMESHORT=%NAMESHORT: "=%
set NAMESHORT=%NAMESHORT:"=%.exe set NAMESHORT=%NAMESHORT:"=%.exe
set CODE=".build\electron\%NAMESHORT%" set CODE=".build\electron\%NAMESHORT%"
:: Get electron
call yarn electron
:: Manage built-in extensions :: Manage built-in extensions
if "%1"=="--builtin" goto builtin if "%1"=="--builtin" goto builtin
:: Sync built-in extensions
node build\lib\builtInExtensions.js
:: Build
if not exist out yarn compile
:: Configuration :: Configuration
set NODE_ENV=development set NODE_ENV=development
set VSCODE_DEV=1 set VSCODE_DEV=1

Some files were not shown because too many files have changed in this diff Show More