mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-03 18:40:29 -04:00
Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)
This commit is contained in:
@@ -65,8 +65,7 @@ interface Asset {
|
|||||||
platform: string;
|
platform: string;
|
||||||
type: string;
|
type: string;
|
||||||
url: string;
|
url: string;
|
||||||
// {{SQL CARBON EDIT}}
|
mooncakeUrl?: string;
|
||||||
mooncakeUrl: string | undefined;
|
|
||||||
hash: string;
|
hash: string;
|
||||||
sha256hash: string;
|
sha256hash: string;
|
||||||
size: number;
|
size: number;
|
||||||
@@ -189,56 +188,18 @@ async function publish(commit: string, quality: string, platform: string, type:
|
|||||||
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
|
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
|
||||||
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
|
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
|
||||||
await assertContainer(blobService, quality);
|
await assertContainer(blobService, quality);
|
||||||
|
|
||||||
const blobExists = await doesAssetExist(blobService, quality, blobName);
|
const blobExists = await doesAssetExist(blobService, quality, blobName);
|
||||||
|
|
||||||
const promises = [];
|
if (blobExists) {
|
||||||
|
|
||||||
if (!blobExists) {
|
|
||||||
promises.push(uploadBlob(blobService, quality, blobName, file));
|
|
||||||
}
|
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
|
||||||
if (process.env['MOONCAKE_STORAGE_ACCESS_KEY']) {
|
|
||||||
const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`)
|
|
||||||
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
|
|
||||||
|
|
||||||
// mooncake is fussy and far away, this is needed!
|
|
||||||
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
assertContainer(blobService, quality),
|
|
||||||
assertContainer(mooncakeBlobService, quality)
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [blobExists, moooncakeBlobExists] = await Promise.all([
|
|
||||||
doesAssetExist(blobService, quality, blobName),
|
|
||||||
doesAssetExist(mooncakeBlobService, quality, blobName)
|
|
||||||
]);
|
|
||||||
|
|
||||||
const promises: Array<Promise<void>> = [];
|
|
||||||
|
|
||||||
if (!blobExists) {
|
|
||||||
promises.push(uploadBlob(blobService, quality, blobName, file));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moooncakeBlobExists) {
|
|
||||||
promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('Skipping Mooncake publishing.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promises.length === 0) {
|
|
||||||
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
|
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Uploading blobs to Azure storage...');
|
console.log('Uploading blobs to Azure storage...');
|
||||||
|
|
||||||
await Promise.all(promises);
|
await uploadBlob(blobService, quality, blobName, file);
|
||||||
|
|
||||||
console.log('Blobs successfully uploaded.');
|
console.log('Blobs successfully uploaded.');
|
||||||
|
|
||||||
@@ -250,8 +211,6 @@ async function publish(commit: string, quality: string, platform: string, type:
|
|||||||
platform: platform,
|
platform: platform,
|
||||||
type: type,
|
type: type,
|
||||||
url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`,
|
url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`,
|
||||||
// {{SQL CARBON EDIT}}
|
|
||||||
mooncakeUrl: process.env['MOONCAKE_CDN_URL'] ? `${process.env['MOONCAKE_CDN_URL']}/${quality}/${blobName}` : undefined,
|
|
||||||
hash: sha1hash,
|
hash: sha1hash,
|
||||||
sha256hash,
|
sha256hash,
|
||||||
size
|
size
|
||||||
|
|||||||
176
build/azure-pipelines/common/sync-mooncake.ts
Normal file
176
build/azure-pipelines/common/sync-mooncake.ts
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import * as url from 'url';
|
||||||
|
import * as azure from 'azure-storage';
|
||||||
|
import * as mime from 'mime';
|
||||||
|
import { DocumentClient, RetrievedDocument } from 'documentdb';
|
||||||
|
|
||||||
|
function log(...args: any[]) {
|
||||||
|
console.log(...[`[${new Date().toISOString()}]`, ...args]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(...args: any[]) {
|
||||||
|
console.error(...[`[${new Date().toISOString()}]`, ...args]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv.length < 3) {
|
||||||
|
error('Usage: node sync-mooncake.js <quality>');
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Build extends RetrievedDocument {
|
||||||
|
assets: Asset[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Asset {
|
||||||
|
platform: string;
|
||||||
|
type: string;
|
||||||
|
url: string;
|
||||||
|
mooncakeUrl: string;
|
||||||
|
hash: string;
|
||||||
|
sha256hash: string;
|
||||||
|
size: number;
|
||||||
|
supportsFastUpdate?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBuild(commit: string, quality: string, platform: string, type: string, asset: Asset): Promise<void> {
|
||||||
|
const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT']!, { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
|
||||||
|
const collection = 'dbs/builds/colls/' + quality;
|
||||||
|
const updateQuery = {
|
||||||
|
query: 'SELECT TOP 1 * FROM c WHERE c.id = @id',
|
||||||
|
parameters: [{ name: '@id', value: commit }]
|
||||||
|
};
|
||||||
|
|
||||||
|
let updateTries = 0;
|
||||||
|
|
||||||
|
function _update(): Promise<void> {
|
||||||
|
updateTries++;
|
||||||
|
|
||||||
|
return new Promise<void>((c, e) => {
|
||||||
|
client.queryDocuments(collection, updateQuery).toArray((err, results) => {
|
||||||
|
if (err) { return e(err); }
|
||||||
|
if (results.length !== 1) { return e(new Error('No documents')); }
|
||||||
|
|
||||||
|
const release = results[0];
|
||||||
|
|
||||||
|
release.assets = [
|
||||||
|
...release.assets.filter((a: any) => !(a.platform === platform && a.type === type)),
|
||||||
|
asset
|
||||||
|
];
|
||||||
|
|
||||||
|
client.replaceDocument(release._self, release, err => {
|
||||||
|
if (err && err.code === 409 && updateTries < 5) { return c(_update()); }
|
||||||
|
if (err) { return e(err); }
|
||||||
|
|
||||||
|
log('Build successfully updated.');
|
||||||
|
c();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return _update();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sync(commit: string, quality: string): Promise<void> {
|
||||||
|
log(`Synchronizing Mooncake assets for ${quality}, ${commit}...`);
|
||||||
|
|
||||||
|
const cosmosdb = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT']!, { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
|
||||||
|
const collection = `dbs/builds/colls/${quality}`;
|
||||||
|
const query = {
|
||||||
|
query: 'SELECT TOP 1 * FROM c WHERE c.id = @id',
|
||||||
|
parameters: [{ name: '@id', value: commit }]
|
||||||
|
};
|
||||||
|
|
||||||
|
const build = await new Promise<Build>((c, e) => {
|
||||||
|
cosmosdb.queryDocuments(collection, query).toArray((err, results) => {
|
||||||
|
if (err) { return e(err); }
|
||||||
|
if (results.length !== 1) { return e(new Error('No documents')); }
|
||||||
|
c(results[0] as Build);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
log(`Found build for ${commit}, with ${build.assets.length} assets`);
|
||||||
|
|
||||||
|
const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']!;
|
||||||
|
|
||||||
|
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
|
||||||
|
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
|
||||||
|
|
||||||
|
const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`)
|
||||||
|
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
|
||||||
|
|
||||||
|
// mooncake is fussy and far away, this is needed!
|
||||||
|
blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
|
||||||
|
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
|
||||||
|
|
||||||
|
for (const asset of build.assets) {
|
||||||
|
try {
|
||||||
|
const blobPath = url.parse(asset.url).path;
|
||||||
|
|
||||||
|
if (!blobPath) {
|
||||||
|
throw new Error(`Failed to parse URL: ${asset.url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blobName = blobPath.replace(/^\/\w+\//, '');
|
||||||
|
|
||||||
|
log(`Found ${blobName}`);
|
||||||
|
|
||||||
|
if (asset.mooncakeUrl) {
|
||||||
|
log(` Already in Mooncake ✔️`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const readStream = blobService.createReadStream(quality, blobName, undefined!);
|
||||||
|
const blobOptions: azure.BlobService.CreateBlockBlobRequestOptions = {
|
||||||
|
contentSettings: {
|
||||||
|
contentType: mime.lookup(blobPath),
|
||||||
|
cacheControl: 'max-age=31536000, public'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeStream = mooncakeBlobService.createWriteStreamToBlockBlob(quality, blobName, blobOptions, undefined);
|
||||||
|
|
||||||
|
log(` Uploading to Mooncake...`);
|
||||||
|
await new Promise((c, e) => readStream.pipe(writeStream).on('finish', c).on('error', e));
|
||||||
|
|
||||||
|
log(` Updating build in DB...`);
|
||||||
|
asset.mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`;
|
||||||
|
await updateBuild(commit, quality, asset.platform, asset.type, asset);
|
||||||
|
|
||||||
|
log(` Done ✔️`);
|
||||||
|
} catch (err) {
|
||||||
|
error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`All done ✔️`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(): void {
|
||||||
|
if (process.env['VSCODE_BUILD_SKIP_PUBLISH']) {
|
||||||
|
error('Skipping publish due to VSCODE_BUILD_SKIP_PUBLISH');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commit = process.env['BUILD_SOURCEVERSION'];
|
||||||
|
|
||||||
|
if (!commit) {
|
||||||
|
error('Skipping publish due to missing BUILD_SOURCEVERSION');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quality = process.argv[2];
|
||||||
|
|
||||||
|
sync(commit, quality).catch(err => {
|
||||||
|
error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -78,7 +78,6 @@ steps:
|
|||||||
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
||||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
|
||||||
node build/azure-pipelines/common/publish.js \
|
node build/azure-pipelines/common/publish.js \
|
||||||
"$(VSCODE_QUALITY)" \
|
"$(VSCODE_QUALITY)" \
|
||||||
darwin \
|
darwin \
|
||||||
|
|||||||
29
build/azure-pipelines/distro-build.yml
Normal file
29
build/azure-pipelines/distro-build.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
trigger:
|
||||||
|
branches:
|
||||||
|
include: ['master', 'release/*']
|
||||||
|
pr:
|
||||||
|
branches:
|
||||||
|
include: ['master', 'release/*']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: NodeTool@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: "10.15.1"
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cat << EOF > ~/.netrc
|
||||||
|
machine github.com
|
||||||
|
login vscode
|
||||||
|
password $(VSCODE_MIXIN_PASSWORD)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git config user.email "vscode@microsoft.com"
|
||||||
|
git config user.name "VSCode"
|
||||||
|
|
||||||
|
git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git"
|
||||||
|
git fetch distro
|
||||||
|
git merge $(node -p "require('./package.json').distro")
|
||||||
|
|
||||||
|
displayName: Merge Distro
|
||||||
@@ -68,7 +68,6 @@ steps:
|
|||||||
|
|
||||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
|
||||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
|
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
|
||||||
|
|
||||||
# Publish hockeyapp symbols
|
# Publish hockeyapp symbols
|
||||||
@@ -83,7 +82,6 @@ steps:
|
|||||||
|
|
||||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
|
||||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
|
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
|
||||||
|
|
||||||
# Publish RPM
|
# Publish RPM
|
||||||
@@ -95,7 +93,6 @@ steps:
|
|||||||
|
|
||||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
|
||||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
|
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
|
||||||
|
|
||||||
# Publish Snap
|
# Publish Snap
|
||||||
|
|||||||
@@ -46,5 +46,4 @@ steps:
|
|||||||
# Publish snap package
|
# Publish snap package
|
||||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
|
||||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"
|
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"
|
||||||
@@ -62,4 +62,18 @@ jobs:
|
|||||||
pool:
|
pool:
|
||||||
vmImage: macOS 10.13
|
vmImage: macOS 10.13
|
||||||
steps:
|
steps:
|
||||||
- template: darwin/product-build-darwin.yml
|
- template: darwin/product-build-darwin.yml
|
||||||
|
|
||||||
|
- job: Mooncake
|
||||||
|
pool:
|
||||||
|
vmImage: 'Ubuntu-16.04'
|
||||||
|
condition: true
|
||||||
|
dependsOn:
|
||||||
|
- Windows
|
||||||
|
- Windows32
|
||||||
|
- Linux
|
||||||
|
- LinuxSnap
|
||||||
|
- Linux32
|
||||||
|
- macOS
|
||||||
|
steps:
|
||||||
|
- template: sync-mooncake.yml
|
||||||
18
build/azure-pipelines/sync-mooncake.yml
Normal file
18
build/azure-pipelines/sync-mooncake.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
steps:
|
||||||
|
- task: NodeTool@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: "10.15.1"
|
||||||
|
|
||||||
|
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||||
|
inputs:
|
||||||
|
versionSpec: "1.10.1"
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
(cd build ; yarn)
|
||||||
|
|
||||||
|
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||||
|
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||||
|
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||||
|
node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY"
|
||||||
@@ -133,7 +133,6 @@ steps:
|
|||||||
$Version = $PackageJson.version
|
$Version = $PackageJson.version
|
||||||
$Quality = "$env:VSCODE_QUALITY"
|
$Quality = "$env:VSCODE_QUALITY"
|
||||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
|
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
|
||||||
$env:MOONCAKE_STORAGE_ACCESS_KEY = "$(MOONCAKE_STORAGE_ACCESS_KEY)"
|
|
||||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
|
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
|
||||||
|
|
||||||
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
|
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const indentationFilter = [
|
|||||||
'!build/azure-pipelines/**/*.js',
|
'!build/azure-pipelines/**/*.js',
|
||||||
'!build/azure-pipelines/**/*.config',
|
'!build/azure-pipelines/**/*.config',
|
||||||
'!**/Dockerfile',
|
'!**/Dockerfile',
|
||||||
|
'!**/Dockerfile.*',
|
||||||
'!**/*.Dockerfile',
|
'!**/*.Dockerfile',
|
||||||
'!**/*.dockerfile',
|
'!**/*.dockerfile',
|
||||||
'!extensions/markdown-language-features/media/*.js'
|
'!extensions/markdown-language-features/media/*.js'
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ const vscodeResources = [
|
|||||||
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
|
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
|
||||||
'out-build/vs/workbench/services/files/**/*.exe',
|
'out-build/vs/workbench/services/files/**/*.exe',
|
||||||
'out-build/vs/workbench/services/files/**/*.md',
|
'out-build/vs/workbench/services/files/**/*.md',
|
||||||
|
'out-build/vs/workbench/services/files2/**/*.exe',
|
||||||
|
'out-build/vs/workbench/services/files2/**/*.md',
|
||||||
'out-build/vs/code/electron-browser/workbench/**',
|
'out-build/vs/code/electron-browser/workbench/**',
|
||||||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||||
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
||||||
@@ -425,6 +427,8 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||||||
|
|
||||||
result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' })
|
result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' })
|
||||||
.pipe(replace('@@NAME@@', product.nameShort))
|
.pipe(replace('@@NAME@@', product.nameShort))
|
||||||
|
.pipe(replace('@@PRODNAME@@', product.nameLong))
|
||||||
|
.pipe(replace('@@VERSION@@', version))
|
||||||
.pipe(replace('@@COMMIT@@', commit))
|
.pipe(replace('@@COMMIT@@', commit))
|
||||||
.pipe(replace('@@APPNAME@@', product.applicationName))
|
.pipe(replace('@@APPNAME@@', product.applicationName))
|
||||||
.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
|
.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
|
||||||
@@ -433,6 +437,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||||||
.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
|
.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
|
||||||
} else if (platform === 'linux') {
|
} else if (platform === 'linux') {
|
||||||
result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' })
|
result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' })
|
||||||
|
.pipe(replace('@@PRODNAME@@', product.nameLong))
|
||||||
.pipe(replace('@@NAME@@', product.applicationName))
|
.pipe(replace('@@NAME@@', product.applicationName))
|
||||||
.pipe(rename('bin/' + product.applicationName)));
|
.pipe(rename('bin/' + product.applicationName)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function log(message: any, ...rest: any[]): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Language {
|
export interface Language {
|
||||||
id: string; // laguage id, e.g. zh-tw, de
|
id: string; // language id, e.g. zh-tw, de
|
||||||
translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used)
|
translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used)
|
||||||
folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used)
|
folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used)
|
||||||
}
|
}
|
||||||
@@ -1378,4 +1378,4 @@ function decodeEntities(value: string): string {
|
|||||||
|
|
||||||
function pseudify(message: string) {
|
function pseudify(message: string) {
|
||||||
return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async function _doExecute(task) {
|
|||||||
// Always invoke as if it were a callback task
|
// Always invoke as if it were a callback task
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (task.length === 1) {
|
if (task.length === 1) {
|
||||||
// this is a calback task
|
// this is a callback task
|
||||||
task((err) => {
|
task((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ async function _doExecute(task: Task): Promise<void> {
|
|||||||
// Always invoke as if it were a callback task
|
// Always invoke as if it were a callback task
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (task.length === 1) {
|
if (task.length === 1) {
|
||||||
// this is a calback task
|
// this is a callback task
|
||||||
task((err) => {
|
task((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ function update(options) {
|
|||||||
let translationPaths = [];
|
let translationPaths = [];
|
||||||
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
|
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
console.log(`Error occured while importing translations:`);
|
console.log(`Error occurred while importing translations:`);
|
||||||
translationPaths = undefined;
|
translationPaths = undefined;
|
||||||
if (Array.isArray(error)) {
|
if (Array.isArray(error)) {
|
||||||
error.forEach(console.log);
|
error.forEach(console.log);
|
||||||
@@ -100,7 +100,7 @@ function update(options) {
|
|||||||
gulp.src(path.join(location, languageId, '**', '*.xlf'))
|
gulp.src(path.join(location, languageId, '**', '*.xlf'))
|
||||||
.pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps'))
|
.pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps'))
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
console.log(`Error occured while importing translations:`);
|
console.log(`Error occurred while importing translations:`);
|
||||||
translationPaths = undefined;
|
translationPaths = undefined;
|
||||||
if (Array.isArray(error)) {
|
if (Array.isArray(error)) {
|
||||||
error.forEach(console.log);
|
error.forEach(console.log);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
// enable JavaScript type checking for the language service
|
// enable JavaScript type checking for the language service
|
||||||
// use the tsconfig.build.json for compiling wich disable JavaScript
|
// use the tsconfig.build.json for compiling which disable JavaScript
|
||||||
// type checking so that JavaScript file are not transpiled
|
// type checking so that JavaScript file are not transpiled
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
@@ -22,4 +22,4 @@
|
|||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules/**"
|
"node_modules/**"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
|
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
|
||||||
"url": "vscode://schemas/settings/user"
|
"url": "vscode://schemas/settings/user"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fileMatch": "%MACHINE_SETTINGS_HOME%/settings.json",
|
||||||
|
"url": "vscode://schemas/settings/machine"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fileMatch": "%APP_WORKSPACES_HOME%/*/workspace.json",
|
"fileMatch": "%APP_WORKSPACES_HOME%/*/workspace.json",
|
||||||
"url": "vscode://schemas/workspaceConfig"
|
"url": "vscode://schemas/workspaceConfig"
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ function getSchemaAssociation(_context: ExtensionContext): ISchemaAssociations {
|
|||||||
}
|
}
|
||||||
if (fileMatch[0] === '%') {
|
if (fileMatch[0] === '%') {
|
||||||
fileMatch = fileMatch.replace(/%APP_SETTINGS_HOME%/, '/User');
|
fileMatch = fileMatch.replace(/%APP_SETTINGS_HOME%/, '/User');
|
||||||
|
fileMatch = fileMatch.replace(/%MACHINE_SETTINGS_HOME%/, '/Machine');
|
||||||
fileMatch = fileMatch.replace(/%APP_WORKSPACES_HOME%/, '/Workspaces');
|
fileMatch = fileMatch.replace(/%APP_WORKSPACES_HOME%/, '/Workspaces');
|
||||||
} else if (fileMatch.charAt(0) !== '/' && !fileMatch.match(/\w+:\/\//)) {
|
} else if (fileMatch.charAt(0) !== '/' && !fileMatch.match(/\w+:\/\//)) {
|
||||||
fileMatch = '/' + fileMatch;
|
fileMatch = '/' + fileMatch;
|
||||||
|
|||||||
@@ -101,21 +101,19 @@ export class MarkdownContentProvider {
|
|||||||
return href;
|
return href;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use href if it is already an URL
|
if (href.startsWith('http:') || href.startsWith('https:') || href.startsWith('file:')) {
|
||||||
const hrefUri = vscode.Uri.parse(href);
|
return href;
|
||||||
if (['http', 'https'].indexOf(hrefUri.scheme) >= 0) {
|
|
||||||
return hrefUri.toString(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use href as file URI if it is absolute
|
// Assume it must be a local file
|
||||||
if (path.isAbsolute(href) || hrefUri.scheme === 'file') {
|
if (path.isAbsolute(href)) {
|
||||||
return vscode.Uri.file(href)
|
return vscode.Uri.file(href)
|
||||||
.with({ scheme: 'vscode-resource' })
|
.with({ scheme: 'vscode-resource' })
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a workspace relative path if there is a workspace
|
// Use a workspace relative path if there is a workspace
|
||||||
let root = vscode.workspace.getWorkspaceFolder(resource);
|
const root = vscode.workspace.getWorkspaceFolder(resource);
|
||||||
if (root) {
|
if (root) {
|
||||||
return vscode.Uri.file(path.join(root.uri.fsPath, href))
|
return vscode.Uri.file(path.join(root.uri.fsPath, href))
|
||||||
.with({ scheme: 'vscode-resource' })
|
.with({ scheme: 'vscode-resource' })
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Dependencies shared by all extensions",
|
"description": "Dependencies shared by all extensions",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"typescript": "3.4.1"
|
"typescript": "3.4.3-insiders.20190408"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "node ./postinstall"
|
"postinstall": "node ./postinstall"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
typescript@3.4.1:
|
typescript@3.4.3-insiders.20190408:
|
||||||
version "3.4.1"
|
version "3.4.3-insiders.20190408"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3-insiders.20190408.tgz#18d98336c693a13dc8b2d5f39b70268c018c650b"
|
||||||
integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==
|
integrity sha512-5SI6EA+2u0ea/Uy0qCEczh8vBR0ByVaCFCyU0RdROROw8V5O4OIQHMFcnIdyg+nnfRGYp39PxvllGMDpsTFOOQ==
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5%
|
|||||||
:: if %errorlevel% neq 0 exit /b %errorlevel%
|
:: if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
:: Tests in the extension host
|
:: Tests in the extension host
|
||||||
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||||
call .\scripts\code.bat %~dp0\..\extensions\markdown-language-features\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
call .\scripts\code.bat %~dp0\..\extensions\markdown-language-features\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||||
call .\scripts\code.bat %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
call .\scripts\code.bat %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
:: call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR% .
|
:: call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
|
||||||
:: if %errorlevel% neq 0 exit /b %errorlevel%
|
:: if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
:: Integration & performance tests in AMD
|
:: Integration & performance tests in AMD
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ cd $ROOT
|
|||||||
|
|
||||||
# Tests in the extension host
|
# Tests in the extension host
|
||||||
# TODO port over an re-enable API tests
|
# TODO port over an re-enable API tests
|
||||||
# ./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
#./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
#./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
|
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
./scripts/code.sh $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
./scripts/code.sh $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
|
|
||||||
mkdir $ROOT/extensions/emmet/test-fixtures
|
mkdir -p $ROOT/extensions/emmet/test-fixtures
|
||||||
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started .
|
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||||
rm -r $ROOT/extensions/emmet/test-fixtures
|
rm -rf $ROOT/extensions/emmet/test-fixtures
|
||||||
|
|
||||||
# Tests in commonJS
|
# Tests in commonJS
|
||||||
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||||
|
|||||||
@@ -146,6 +146,11 @@ function configureCommandlineSwitches(cliArgs, nodeCachedDataDir) {
|
|||||||
if (jsFlags) {
|
if (jsFlags) {
|
||||||
app.commandLine.appendSwitch('--js-flags', jsFlags);
|
app.commandLine.appendSwitch('--js-flags', jsFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable smooth scrolling for Webviews
|
||||||
|
if (cliArgs['disable-smooth-scrolling']) {
|
||||||
|
app.commandLine.appendSwitch('disable-smooth-scrolling');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { nb, IConnectionProfile } from 'azdata';
|
import { nb, IConnectionProfile } from 'azdata';
|
||||||
import * as vsExtTypes from 'vs/workbench/api/node/extHostTypes';
|
import * as vsExtTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
// SQL added extension host types
|
// SQL added extension host types
|
||||||
export enum ServiceOptionType {
|
export enum ServiceOptionType {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import {
|
import {
|
||||||
ExtHostAccountManagementShape,
|
ExtHostAccountManagementShape,
|
||||||
MainThreadAccountManagementShape,
|
MainThreadAccountManagementShape,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
import { SqlMainContext, MainThreadCredentialManagementShape, ExtHostCredentialManagementShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
import { SqlMainContext, MainThreadCredentialManagementShape, ExtHostCredentialManagementShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
class CredentialAdapter {
|
class CredentialAdapter {
|
||||||
public provider: azdata.CredentialProvider;
|
public provider: azdata.CredentialProvider;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { SqlMainContext, MainThreadDataProtocolShape, ExtHostDataProtocolShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
import { SqlMainContext, MainThreadDataProtocolShape, ExtHostDataProtocolShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||||
import { DataProviderType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { DataProviderType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import { localize } from 'vs/nls';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { SqlMainContext, ExtHostModelViewTreeViewsShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
import { SqlMainContext, ExtHostModelViewTreeViewsShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||||
import { ITreeComponentItem } from 'sql/workbench/common/views';
|
import { ITreeComponentItem } from 'sql/workbench/common/views';
|
||||||
import { CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
|
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as vsTreeExt from 'vs/workbench/api/node/extHostTreeViews';
|
import * as vsTreeExt from 'vs/workbench/api/common/extHostTreeViews';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import * as vscode from 'vscode';
|
|||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { dispose } from 'vs/base/common/lifecycle';
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ok } from 'vs/base/common/assert';
|
import { ok } from 'vs/base/common/assert';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import {
|
import {
|
||||||
ExtHostResourceProviderShape,
|
ExtHostResourceProviderShape,
|
||||||
MainThreadResourceProviderShape,
|
MainThreadResourceProviderShape,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
import { SqlMainContext, MainThreadSerializationProviderShape, ExtHostSerializationProviderShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
import { SqlMainContext, MainThreadSerializationProviderShape, ExtHostSerializationProviderShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
class SerializationAdapter {
|
class SerializationAdapter {
|
||||||
private _provider: azdata.SerializationProvider;
|
private _provider: azdata.SerializationProvider;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import { validateConstraint } from 'vs/base/common/types';
|
import { validateConstraint } from 'vs/base/common/types';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
import * as extHostApi from 'vs/workbench/api/node/extHost.api.impl';
|
import * as extHostApi from 'vs/workbench/api/node/extHost.api.impl';
|
||||||
import { IInitData, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IInitData, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
@@ -20,8 +19,6 @@ import { ExtHostDataProtocol } from 'sql/workbench/api/node/extHostDataProtocol'
|
|||||||
import { ExtHostSerializationProvider } from 'sql/workbench/api/node/extHostSerializationProvider';
|
import { ExtHostSerializationProvider } from 'sql/workbench/api/node/extHostSerializationProvider';
|
||||||
import { ExtHostResourceProvider } from 'sql/workbench/api/node/extHostResourceProvider';
|
import { ExtHostResourceProvider } from 'sql/workbench/api/node/extHostResourceProvider';
|
||||||
import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes';
|
import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
|
||||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration';
|
|
||||||
import { ExtHostModalDialogs } from 'sql/workbench/api/node/extHostModalDialog';
|
import { ExtHostModalDialogs } from 'sql/workbench/api/node/extHostModalDialog';
|
||||||
import { ExtHostTasks } from 'sql/workbench/api/node/extHostTasks';
|
import { ExtHostTasks } from 'sql/workbench/api/node/extHostTasks';
|
||||||
import { ExtHostDashboardWebviews } from 'sql/workbench/api/node/extHostDashboardWebview';
|
import { ExtHostDashboardWebviews } from 'sql/workbench/api/node/extHostDashboardWebview';
|
||||||
@@ -29,18 +26,21 @@ import { ExtHostModelView } from 'sql/workbench/api/node/extHostModelView';
|
|||||||
import { ExtHostConnectionManagement } from 'sql/workbench/api/node/extHostConnectionManagement';
|
import { ExtHostConnectionManagement } from 'sql/workbench/api/node/extHostConnectionManagement';
|
||||||
import { ExtHostDashboard } from 'sql/workbench/api/node/extHostDashboard';
|
import { ExtHostDashboard } from 'sql/workbench/api/node/extHostDashboard';
|
||||||
import { ExtHostObjectExplorer } from 'sql/workbench/api/node/extHostObjectExplorer';
|
import { ExtHostObjectExplorer } from 'sql/workbench/api/node/extHostObjectExplorer';
|
||||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||||
import { ExtHostModelViewDialog } from 'sql/workbench/api/node/extHostModelViewDialog';
|
import { ExtHostModelViewDialog } from 'sql/workbench/api/node/extHostModelViewDialog';
|
||||||
import { ExtHostModelViewTreeViews } from 'sql/workbench/api/node/extHostModelViewTree';
|
import { ExtHostModelViewTreeViews } from 'sql/workbench/api/node/extHostModelViewTree';
|
||||||
import { ExtHostQueryEditor } from 'sql/workbench/api/node/extHostQueryEditor';
|
import { ExtHostQueryEditor } from 'sql/workbench/api/node/extHostQueryEditor';
|
||||||
import { ExtHostBackgroundTaskManagement } from './extHostBackgroundTaskManagement';
|
import { ExtHostBackgroundTaskManagement } from './extHostBackgroundTaskManagement';
|
||||||
import { ExtHostNotebook } from 'sql/workbench/api/node/extHostNotebook';
|
import { ExtHostNotebook } from 'sql/workbench/api/node/extHostNotebook';
|
||||||
import { ExtHostNotebookDocumentsAndEditors } from 'sql/workbench/api/node/extHostNotebookDocumentsAndEditors';
|
import { ExtHostNotebookDocumentsAndEditors } from 'sql/workbench/api/node/extHostNotebookDocumentsAndEditors';
|
||||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
|
||||||
import { ExtHostExtensionManagement } from 'sql/workbench/api/node/extHostExtensionManagement';
|
import { ExtHostExtensionManagement } from 'sql/workbench/api/node/extHostExtensionManagement';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
|
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||||
|
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||||
|
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||||
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
export interface ISqlExtensionApiFactory {
|
export interface ISqlExtensionApiFactory {
|
||||||
vsCodeFactory(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
vsCodeFactory(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
* 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.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { equal } from 'assert';
|
import { equal, fail } from 'assert';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
|
||||||
import { resolveQueryFilePath } from 'sql/workbench/services/insights/common/insightsUtils';
|
import { resolveQueryFilePath } from 'sql/workbench/services/insights/common/insightsUtils';
|
||||||
import { TestWindowService } from 'sqltest/stubs/windowTestService';
|
|
||||||
|
|
||||||
import * as path from 'vs/base/common/path';
|
import * as path from 'vs/base/common/path';
|
||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
@@ -16,69 +15,129 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
|||||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
||||||
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
|
import { IExtensionHostDebugParams, IDebugParams, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||||
|
|
||||||
|
class TestEnvironmentService implements IWorkbenchEnvironmentService {
|
||||||
|
machineSettingsHome: string;
|
||||||
|
machineSettingsPath: string;
|
||||||
|
extensionDevelopmentLocationURI?: URI[];
|
||||||
|
|
||||||
|
constructor(private userEnv: { [key: string]: any }) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get configuration(): IWindowConfiguration {
|
||||||
|
return {
|
||||||
|
userEnv: this.userEnv
|
||||||
|
} as IWindowConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
_serviceBrand: any;
|
||||||
|
args: ParsedArgs;
|
||||||
|
execPath: string;
|
||||||
|
cliPath: string;
|
||||||
|
appRoot: string;
|
||||||
|
userHome: string;
|
||||||
|
userDataPath: string;
|
||||||
|
appNameLong: string;
|
||||||
|
appQuality?: string;
|
||||||
|
appSettingsHome: string;
|
||||||
|
appSettingsPath: string;
|
||||||
|
appKeybindingsPath: string;
|
||||||
|
settingsSearchBuildId?: number;
|
||||||
|
settingsSearchUrl?: string;
|
||||||
|
globalStorageHome: string;
|
||||||
|
workspaceStorageHome: string;
|
||||||
|
backupHome: string;
|
||||||
|
backupWorkspacesPath: string;
|
||||||
|
untitledWorkspacesHome: URI;
|
||||||
|
isExtensionDevelopment: boolean;
|
||||||
|
disableExtensions: boolean | string[];
|
||||||
|
builtinExtensionsPath: string;
|
||||||
|
extensionsPath: string;
|
||||||
|
extensionTestsLocationURI?: URI;
|
||||||
|
debugExtensionHost: IExtensionHostDebugParams;
|
||||||
|
debugSearch: IDebugParams;
|
||||||
|
logExtensionHostCommunication: boolean;
|
||||||
|
isBuilt: boolean;
|
||||||
|
wait: boolean;
|
||||||
|
status: boolean;
|
||||||
|
log?: string;
|
||||||
|
logsPath: string;
|
||||||
|
verbose: boolean;
|
||||||
|
skipGettingStarted: boolean;
|
||||||
|
skipReleaseNotes: boolean;
|
||||||
|
skipAddToRecentlyOpened: boolean;
|
||||||
|
mainIPCHandle: string;
|
||||||
|
sharedIPCHandle: string;
|
||||||
|
nodeCachedDataDir?: string;
|
||||||
|
installSourcePath: string;
|
||||||
|
disableUpdates: boolean;
|
||||||
|
disableCrashReporter: boolean;
|
||||||
|
driverHandle?: string;
|
||||||
|
driverVerbose: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
suite('Insights Utils tests', function () {
|
suite('Insights Utils tests', function () {
|
||||||
let testRootPath: string;
|
let testRootPath: string;
|
||||||
let queryFileDir: string;
|
let queryFileDir: string;
|
||||||
let queryFilePath: string;
|
let queryFilePath: string;
|
||||||
|
|
||||||
suiteSetup(done => {
|
suiteSetup(async () => {
|
||||||
// Create test file - just needs to exist for verifying the path resolution worked correctly
|
// Create test file - just needs to exist for verifying the path resolution worked correctly
|
||||||
testRootPath = path.join(os.tmpdir(), 'adstests');
|
testRootPath = path.join(os.tmpdir(), 'adstests');
|
||||||
queryFileDir = getRandomTestPath(testRootPath, 'insightsutils');
|
queryFileDir = getRandomTestPath(testRootPath, 'insightsutils');
|
||||||
pfs.mkdirp(queryFileDir).then(() => {
|
await pfs.mkdirp(queryFileDir);
|
||||||
queryFilePath = path.join(queryFileDir, 'test.sql');
|
queryFilePath = path.join(queryFileDir, 'test.sql');
|
||||||
pfs.writeFile(queryFilePath, '').then(done());
|
await pfs.writeFile(queryFilePath, '');
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath resolves path correctly with fully qualified path', async () => {
|
test('resolveQueryFilePath resolves path correctly with fully qualified path', async () => {
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({}),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({}),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
new TestContextService(),
|
new TestContextService(),
|
||||||
undefined);
|
undefined);
|
||||||
|
|
||||||
let resolvedPath = await resolveQueryFilePath(queryFilePath, new TestContextService(), configurationResolverService);
|
const resolvedPath = await resolveQueryFilePath(queryFilePath, new TestContextService(), configurationResolverService);
|
||||||
equal(resolvedPath, queryFilePath);
|
equal(resolvedPath, queryFilePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath resolves path correctly with workspaceRoot var and non-empty workspace containing file', async () => {
|
test('resolveQueryFilePath resolves path correctly with workspaceRoot var and non-empty workspace containing file', async () => {
|
||||||
// Create mock context service with our test folder added as a workspace folder for resolution
|
// Create mock context service with our test folder added as a workspace folder for resolution
|
||||||
let contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace(
|
new Workspace(
|
||||||
'TestWorkspace',
|
'TestWorkspace',
|
||||||
toWorkspaceFolders([{ path: queryFileDir }])
|
toWorkspaceFolders([{ path: queryFileDir }])
|
||||||
));
|
));
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({}),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({}),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
contextService,
|
contextService,
|
||||||
undefined);
|
undefined);
|
||||||
|
|
||||||
let resolvedPath = await resolveQueryFilePath(path.join('${workspaceRoot}', 'test.sql'), contextService, configurationResolverService);
|
const resolvedPath = await resolveQueryFilePath(path.join('${workspaceRoot}', 'test.sql'), contextService, configurationResolverService);
|
||||||
equal(resolvedPath, queryFilePath);
|
equal(resolvedPath, queryFilePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath throws with workspaceRoot var and non-empty workspace not containing file', async (done) => {
|
test('resolveQueryFilePath throws with workspaceRoot var and non-empty workspace not containing file', async (done) => {
|
||||||
let tokenizedPath = path.join('${workspaceRoot}', 'test.sql');
|
const tokenizedPath = path.join('${workspaceRoot}', 'test.sql');
|
||||||
// Create mock context service with a folder NOT containing our test file to verify it returns original path
|
// Create mock context service with a folder NOT containing our test file to verify it returns original path
|
||||||
let contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace(
|
new Workspace(
|
||||||
'TestWorkspace',
|
'TestWorkspace',
|
||||||
toWorkspaceFolders([{ path: os.tmpdir() }])
|
toWorkspaceFolders([{ path: os.tmpdir() }])
|
||||||
));
|
));
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({}),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({}),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
contextService,
|
contextService,
|
||||||
@@ -86,6 +145,7 @@ suite('Insights Utils tests', function () {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await resolveQueryFilePath(tokenizedPath, contextService, configurationResolverService);
|
await resolveQueryFilePath(tokenizedPath, contextService, configurationResolverService);
|
||||||
|
fail('Should have thrown');
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
done();
|
done();
|
||||||
@@ -93,15 +153,14 @@ suite('Insights Utils tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath throws with workspaceRoot var and empty workspace', async (done) => {
|
test('resolveQueryFilePath throws with workspaceRoot var and empty workspace', async (done) => {
|
||||||
let tokenizedPath = path.join('${workspaceRoot}', 'test.sql');
|
const tokenizedPath = path.join('${workspaceRoot}', 'test.sql');
|
||||||
// Create mock context service with an empty workspace
|
// Create mock context service with an empty workspace
|
||||||
let contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace(
|
new Workspace(
|
||||||
'TestWorkspace'));
|
'TestWorkspace'));
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({}),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({}),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
contextService,
|
contextService,
|
||||||
@@ -109,6 +168,7 @@ suite('Insights Utils tests', function () {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await resolveQueryFilePath(tokenizedPath, contextService, configurationResolverService);
|
await resolveQueryFilePath(tokenizedPath, contextService, configurationResolverService);
|
||||||
|
fail('Should have thrown');
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
done();
|
done();
|
||||||
@@ -116,47 +176,44 @@ suite('Insights Utils tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath resolves path correctly with env var and empty workspace', async () => {
|
test('resolveQueryFilePath resolves path correctly with env var and empty workspace', async () => {
|
||||||
let contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace('TestWorkspace'));
|
new Workspace('TestWorkspace'));
|
||||||
|
|
||||||
// Create mock window service with env variable containing test folder for resolution
|
// Create mock window service with env variable containing test folder for resolution
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({ TEST_PATH: queryFileDir }),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({ TEST_PATH: queryFileDir }),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined);
|
undefined);
|
||||||
|
|
||||||
let resolvedPath = await resolveQueryFilePath(path.join('${env:TEST_PATH}', 'test.sql'), contextService, configurationResolverService);
|
const resolvedPath = await resolveQueryFilePath(path.join('${env:TEST_PATH}', 'test.sql'), contextService, configurationResolverService);
|
||||||
equal(resolvedPath, queryFilePath);
|
equal(resolvedPath, queryFilePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath resolves path correctly with env var and non-empty workspace', async () => {
|
test('resolveQueryFilePath resolves path correctly with env var and non-empty workspace', async () => {
|
||||||
let contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace('TestWorkspace', toWorkspaceFolders([{ path: os.tmpdir() }])));
|
new Workspace('TestWorkspace', toWorkspaceFolders([{ path: os.tmpdir() }])));
|
||||||
|
|
||||||
// Create mock window service with env variable containing test folder for resolution
|
// Create mock window service with env variable containing test folder for resolution
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({ TEST_PATH: queryFileDir }),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({ TEST_PATH: queryFileDir }),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined);
|
undefined);
|
||||||
|
|
||||||
let resolvedPath = await resolveQueryFilePath(path.join('${env:TEST_PATH}', 'test.sql'), contextService, configurationResolverService);
|
const resolvedPath = await resolveQueryFilePath(path.join('${env:TEST_PATH}', 'test.sql'), contextService, configurationResolverService);
|
||||||
equal(resolvedPath, queryFilePath);
|
equal(resolvedPath, queryFilePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveQueryFilePath throws if invalid param var specified', async (done) => {
|
test('resolveQueryFilePath throws if invalid param var specified', async (done) => {
|
||||||
let invalidPath = path.join('${INVALID}', 'test.sql');
|
const invalidPath = path.join('${INVALID}', 'test.sql');
|
||||||
let configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
new TestWindowService({}),
|
|
||||||
undefined,
|
|
||||||
undefined,
|
undefined,
|
||||||
|
new TestEnvironmentService({}),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
@@ -164,8 +221,8 @@ suite('Insights Utils tests', function () {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await resolveQueryFilePath(invalidPath, new TestContextService(), configurationResolverService);
|
await resolveQueryFilePath(invalidPath, new TestContextService(), configurationResolverService);
|
||||||
}
|
fail('Should have thrown');
|
||||||
catch (e) {
|
} catch (e) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { IDimension } from 'vs/editor/common/editorCommon';
|
|||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
export class EditorGroupTestService implements IEditorGroupsService {
|
export class EditorGroupTestService implements IEditorGroupsService {
|
||||||
|
willRestoreEditors: boolean;
|
||||||
dimension: IDimension;
|
dimension: IDimension;
|
||||||
whenRestored: Promise<void>;
|
whenRestored: Promise<void>;
|
||||||
centerLayout(active: boolean): void {
|
centerLayout(active: boolean): void {
|
||||||
|
|||||||
@@ -115,6 +115,13 @@ export class DragMouseEvent extends StandardMouseEvent {
|
|||||||
|
|
||||||
export interface IMouseWheelEvent extends MouseEvent {
|
export interface IMouseWheelEvent extends MouseEvent {
|
||||||
readonly wheelDelta: number;
|
readonly wheelDelta: number;
|
||||||
|
readonly wheelDeltaX: number;
|
||||||
|
readonly wheelDeltaY: number;
|
||||||
|
|
||||||
|
readonly deltaX: number;
|
||||||
|
readonly deltaY: number;
|
||||||
|
readonly deltaZ: number;
|
||||||
|
readonly deltaMode: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IWebKitMouseWheelEvent {
|
interface IWebKitMouseWheelEvent {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
declare var Buffer: any;
|
declare var Buffer: any;
|
||||||
const hasBuffer = (typeof Buffer !== 'undefined');
|
export const hasBuffer = (typeof Buffer !== 'undefined');
|
||||||
|
|
||||||
let textEncoder: TextEncoder | null;
|
let textEncoder: TextEncoder | null;
|
||||||
let textDecoder: TextDecoder | null;
|
let textDecoder: TextDecoder | null;
|
||||||
@@ -20,6 +20,11 @@ export class VSBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static wrap(actual: Uint8Array): VSBuffer {
|
public static wrap(actual: Uint8Array): VSBuffer {
|
||||||
|
if (hasBuffer && !(Buffer.isBuffer(actual))) {
|
||||||
|
// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
||||||
|
// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
|
||||||
|
actual = Buffer.from(actual.buffer, actual.byteOffset, actual.byteLength);
|
||||||
|
}
|
||||||
return new VSBuffer(actual);
|
return new VSBuffer(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,3 +129,44 @@ function readUint8(source: Uint8Array, offset: number): number {
|
|||||||
function writeUint8(destination: Uint8Array, value: number, offset: number): void {
|
function writeUint8(destination: Uint8Array, value: number, offset: number): void {
|
||||||
destination[offset] = value;
|
destination[offset] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VSBufferReadable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from the underlying source. Will return
|
||||||
|
* null to indicate that no more data can be read.
|
||||||
|
*/
|
||||||
|
read(): VSBuffer | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to fully read a VSBuffer readable into a single buffer.
|
||||||
|
*/
|
||||||
|
export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
|
||||||
|
const chunks: VSBuffer[] = [];
|
||||||
|
|
||||||
|
let chunk: VSBuffer | null;
|
||||||
|
while (chunk = readable.read()) {
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return VSBuffer.concat(chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to convert a buffer into a readable buffer.
|
||||||
|
*/
|
||||||
|
export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
|
||||||
|
let done = false;
|
||||||
|
return {
|
||||||
|
read: () => {
|
||||||
|
if (done) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -265,33 +265,6 @@ export namespace Event {
|
|||||||
return emitter.event;
|
return emitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Similar to `buffer` but it buffers indefinitely and repeats
|
|
||||||
* the buffered events to every new listener.
|
|
||||||
*/
|
|
||||||
export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): Event<T> {
|
|
||||||
buffer = buffer.slice();
|
|
||||||
|
|
||||||
event(e => {
|
|
||||||
buffer.push(e);
|
|
||||||
emitter.fire(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
const flush = (listener: (e: T) => any, thisArgs?: any) => buffer.forEach(e => listener.call(thisArgs, e));
|
|
||||||
|
|
||||||
const emitter = new Emitter<T>({
|
|
||||||
onListenerDidAdd(emitter: Emitter<T>, listener: (e: T) => any, thisArgs?: any) {
|
|
||||||
if (nextTick) {
|
|
||||||
setTimeout(() => flush(listener, thisArgs));
|
|
||||||
} else {
|
|
||||||
flush(listener, thisArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return emitter.event;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChainableEvent<T> {
|
export interface IChainableEvent<T> {
|
||||||
event: Event<T>;
|
event: Event<T>;
|
||||||
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
||||||
|
|||||||
@@ -44,4 +44,6 @@ export namespace Schemas {
|
|||||||
export const data: string = 'data';
|
export const data: string = 'data';
|
||||||
|
|
||||||
export const command: string = 'command';
|
export const command: string = 'command';
|
||||||
|
|
||||||
|
export const vscodeRemote: string = 'vscode-remote';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,7 +284,6 @@ export namespace DataUri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class ResourceGlobMatcher {
|
export class ResourceGlobMatcher {
|
||||||
|
|
||||||
private readonly globalExpression: ParsedExpression;
|
private readonly globalExpression: ParsedExpression;
|
||||||
@@ -311,3 +310,16 @@ export class ResourceGlobMatcher {
|
|||||||
return !!this.globalExpression(resource.path);
|
return !!this.globalExpression(resource.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toLocalResource(resource: URI, authority: string | undefined): URI {
|
||||||
|
if (authority) {
|
||||||
|
let path = resource.path;
|
||||||
|
if (path && path[0] !== paths.posix.sep) {
|
||||||
|
path = paths.posix.sep + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource.with({ scheme: Schemas.vscodeRemote, authority, path });
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource.with({ scheme: Schemas.file });
|
||||||
|
}
|
||||||
20
src/vs/base/test/common/buffer.test.ts
Normal file
20
src/vs/base/test/common/buffer.test.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { hasBuffer, VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
|
suite('Buffer', () => {
|
||||||
|
|
||||||
|
if (hasBuffer) {
|
||||||
|
test('issue #71993 - VSBuffer#toString returns numbers', () => {
|
||||||
|
const data = new Uint8Array([1, 2, 3, 'h'.charCodeAt(0), 'i'.charCodeAt(0), 4, 5]).buffer;
|
||||||
|
const buffer = VSBuffer.wrap(new Uint8Array(data, 3, 2));
|
||||||
|
assert.deepEqual(buffer.toString(), 'hi');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@@ -645,67 +645,6 @@ suite('Event utils', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('echo', () => {
|
|
||||||
|
|
||||||
test('should echo events', () => {
|
|
||||||
const result: number[] = [];
|
|
||||||
const emitter = new Emitter<number>();
|
|
||||||
const event = emitter.event;
|
|
||||||
const echoEvent = Event.echo(event);
|
|
||||||
|
|
||||||
emitter.fire(1);
|
|
||||||
emitter.fire(2);
|
|
||||||
emitter.fire(3);
|
|
||||||
assert.deepEqual(result, []);
|
|
||||||
|
|
||||||
const listener = echoEvent(num => result.push(num));
|
|
||||||
assert.deepEqual(result, [1, 2, 3]);
|
|
||||||
|
|
||||||
emitter.fire(4);
|
|
||||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
|
||||||
|
|
||||||
listener.dispose();
|
|
||||||
emitter.fire(5);
|
|
||||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should echo events for every listener', () => {
|
|
||||||
const result1: number[] = [];
|
|
||||||
const result2: number[] = [];
|
|
||||||
const emitter = new Emitter<number>();
|
|
||||||
const event = emitter.event;
|
|
||||||
const echoEvent = Event.echo(event);
|
|
||||||
|
|
||||||
emitter.fire(1);
|
|
||||||
emitter.fire(2);
|
|
||||||
emitter.fire(3);
|
|
||||||
assert.deepEqual(result1, []);
|
|
||||||
assert.deepEqual(result2, []);
|
|
||||||
|
|
||||||
const listener1 = echoEvent(num => result1.push(num));
|
|
||||||
assert.deepEqual(result1, [1, 2, 3]);
|
|
||||||
assert.deepEqual(result2, []);
|
|
||||||
|
|
||||||
emitter.fire(4);
|
|
||||||
assert.deepEqual(result1, [1, 2, 3, 4]);
|
|
||||||
assert.deepEqual(result2, []);
|
|
||||||
|
|
||||||
const listener2 = echoEvent(num => result2.push(num));
|
|
||||||
assert.deepEqual(result1, [1, 2, 3, 4]);
|
|
||||||
assert.deepEqual(result2, [1, 2, 3, 4]);
|
|
||||||
|
|
||||||
emitter.fire(5);
|
|
||||||
assert.deepEqual(result1, [1, 2, 3, 4, 5]);
|
|
||||||
assert.deepEqual(result2, [1, 2, 3, 4, 5]);
|
|
||||||
|
|
||||||
listener1.dispose();
|
|
||||||
listener2.dispose();
|
|
||||||
emitter.fire(6);
|
|
||||||
assert.deepEqual(result1, [1, 2, 3, 4, 5]);
|
|
||||||
assert.deepEqual(result2, [1, 2, 3, 4, 5]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
suite('EventMultiplexer', () => {
|
suite('EventMultiplexer', () => {
|
||||||
|
|
||||||
test('works', () => {
|
test('works', () => {
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ td {
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr td:first-child {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/vs/code/electron-browser/processExplorer/media/collapsed.svg
Executable file
1
src/vs/code/electron-browser/processExplorer/media/collapsed.svg
Executable file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>
|
||||||
|
After Width: | Height: | Size: 139 B |
1
src/vs/code/electron-browser/processExplorer/media/expanded.svg
Executable file
1
src/vs/code/electron-browser/processExplorer/media/expanded.svg
Executable file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M11 10H5.344L11 4.414V10z"/></svg>
|
||||||
|
After Width: | Height: | Size: 118 B |
@@ -85,6 +85,20 @@ td {
|
|||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
padding-left: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
tbody > tr:hover {
|
tbody > tr:hover {
|
||||||
background-color: #2A2D2E;
|
background-color: #2A2D2E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 16px;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import 'vs/css!./media/processExplorer';
|
import 'vs/css!./media/processExplorer';
|
||||||
import { listProcesses } from 'vs/base/node/ps';
|
|
||||||
import { webFrame, ipcRenderer, clipboard } from 'electron';
|
import { webFrame, ipcRenderer, clipboard } from 'electron';
|
||||||
import { repeat } from 'vs/base/common/strings';
|
import { repeat } from 'vs/base/common/strings';
|
||||||
import { totalmem } from 'os';
|
import { totalmem } from 'os';
|
||||||
@@ -16,31 +15,46 @@ import * as platform from 'vs/base/common/platform';
|
|||||||
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
|
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
|
||||||
import { popup } from 'vs/base/parts/contextmenu/electron-browser/contextmenu';
|
import { popup } from 'vs/base/parts/contextmenu/electron-browser/contextmenu';
|
||||||
import { ProcessItem } from 'vs/base/common/processes';
|
import { ProcessItem } from 'vs/base/common/processes';
|
||||||
|
import { addDisposableListener } from 'vs/base/browser/dom';
|
||||||
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
|
|
||||||
|
|
||||||
let processList: any[];
|
|
||||||
let mapPidToWindowTitle = new Map<number, string>();
|
let mapPidToWindowTitle = new Map<number, string>();
|
||||||
|
|
||||||
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
||||||
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
||||||
|
const listeners: IDisposable[] = [];
|
||||||
|
const collapsedStateCache: Map<string, boolean> = new Map<string, boolean>();
|
||||||
|
let lastRequestTime: number;
|
||||||
|
|
||||||
function getProcessList(rootProcess: ProcessItem) {
|
interface FormattedProcessItem {
|
||||||
const processes: any[] = [];
|
cpu: string;
|
||||||
|
memory: string;
|
||||||
|
pid: string;
|
||||||
|
name: string;
|
||||||
|
formattedName: string;
|
||||||
|
cmd: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProcessList(rootProcess: ProcessItem, isLocal: boolean): FormattedProcessItem[] {
|
||||||
|
const processes: FormattedProcessItem[] = [];
|
||||||
|
|
||||||
if (rootProcess) {
|
if (rootProcess) {
|
||||||
getProcessItem(processes, rootProcess, 0);
|
getProcessItem(processes, rootProcess, 0, isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return processes;
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcessItem(processes: any[], item: ProcessItem, indent: number): void {
|
function getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, indent: number, isLocal: boolean): void {
|
||||||
const isRoot = (indent === 0);
|
const isRoot = (indent === 0);
|
||||||
|
|
||||||
const MB = 1024 * 1024;
|
const MB = 1024 * 1024;
|
||||||
|
|
||||||
let name = item.name;
|
let name = item.name;
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
name = `${product.applicationName} main`;
|
name = isLocal ? `${product.applicationName} main` : 'remote agent';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'window') {
|
if (name === 'window') {
|
||||||
@@ -52,9 +66,9 @@ function getProcessItem(processes: any[], item: ProcessItem, indent: number): vo
|
|||||||
const formattedName = isRoot ? name : `${repeat(' ', indent)} ${name}`;
|
const formattedName = isRoot ? name : `${repeat(' ', indent)} ${name}`;
|
||||||
const memory = process.platform === 'win32' ? item.mem : (totalmem() * (item.mem / 100));
|
const memory = process.platform === 'win32' ? item.mem : (totalmem() * (item.mem / 100));
|
||||||
processes.push({
|
processes.push({
|
||||||
cpu: Number(item.load.toFixed(0)),
|
cpu: item.load.toFixed(0),
|
||||||
memory: Number((memory / MB).toFixed(0)),
|
memory: (memory / MB).toFixed(0),
|
||||||
pid: Number((item.pid).toFixed(0)),
|
pid: item.pid.toFixed(0),
|
||||||
name,
|
name,
|
||||||
formattedName,
|
formattedName,
|
||||||
cmd: item.cmd
|
cmd: item.cmd
|
||||||
@@ -62,7 +76,7 @@ function getProcessItem(processes: any[], item: ProcessItem, indent: number): vo
|
|||||||
|
|
||||||
// Recurse into children if any
|
// Recurse into children if any
|
||||||
if (Array.isArray(item.children)) {
|
if (Array.isArray(item.children)) {
|
||||||
item.children.forEach(child => getProcessItem(processes, child, indent + 1));
|
item.children.forEach(child => getProcessItem(processes, child, indent + 1, isLocal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +85,7 @@ function isDebuggable(cmd: string): boolean {
|
|||||||
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
|
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachTo(item: ProcessItem) {
|
function attachTo(item: FormattedProcessItem) {
|
||||||
const config: any = {
|
const config: any = {
|
||||||
type: 'node',
|
type: 'node',
|
||||||
request: 'attach',
|
request: 'attach',
|
||||||
@@ -113,35 +127,82 @@ function getProcessIdWithHighestProperty(processList: any[], propertyName: strin
|
|||||||
return maxProcessId;
|
return maxProcessId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProcessInfo(processList: any[]): void {
|
function updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: HTMLImageElement, sectionName: string) {
|
||||||
|
if (shouldExpand) {
|
||||||
|
body.classList.remove('hidden');
|
||||||
|
collapsedStateCache.set(sectionName, false);
|
||||||
|
twistie.src = './media/expanded.svg';
|
||||||
|
} else {
|
||||||
|
body.classList.add('hidden');
|
||||||
|
collapsedStateCache.set(sectionName, true);
|
||||||
|
twistie.src = './media/collapsed.svg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderProcessFetchError(sectionName: string, errorMessage: string) {
|
||||||
|
const container = document.getElementById('process-list');
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = document.createElement('tbody');
|
||||||
|
|
||||||
|
renderProcessGroupHeader(sectionName, body, container);
|
||||||
|
|
||||||
|
const errorRow = document.createElement('tr');
|
||||||
|
const data = document.createElement('td');
|
||||||
|
data.textContent = errorMessage;
|
||||||
|
data.className = 'error';
|
||||||
|
data.colSpan = 4;
|
||||||
|
errorRow.appendChild(data);
|
||||||
|
|
||||||
|
body.appendChild(errorRow);
|
||||||
|
container.appendChild(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderProcessGroupHeader(sectionName: string, body: HTMLElement, container: HTMLElement) {
|
||||||
|
const headerRow = document.createElement('tr');
|
||||||
|
const data = document.createElement('td');
|
||||||
|
data.textContent = sectionName;
|
||||||
|
data.colSpan = 4;
|
||||||
|
headerRow.appendChild(data);
|
||||||
|
|
||||||
|
const twistie = document.createElement('img');
|
||||||
|
updateSectionCollapsedState(!collapsedStateCache.get(sectionName), body, twistie, sectionName);
|
||||||
|
data.prepend(twistie);
|
||||||
|
|
||||||
|
listeners.push(addDisposableListener(data, 'click', (e) => {
|
||||||
|
const isHidden = body.classList.contains('hidden');
|
||||||
|
updateSectionCollapsedState(isHidden, body, twistie, sectionName);
|
||||||
|
}));
|
||||||
|
|
||||||
|
container.appendChild(headerRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTableSection(sectionName: string, processList: FormattedProcessItem[], renderManySections: boolean, sectionIsLocal: boolean): void {
|
||||||
const container = document.getElementById('process-list');
|
const container = document.getElementById('process-list');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = '';
|
|
||||||
const highestCPUProcess = getProcessIdWithHighestProperty(processList, 'cpu');
|
const highestCPUProcess = getProcessIdWithHighestProperty(processList, 'cpu');
|
||||||
const highestMemoryProcess = getProcessIdWithHighestProperty(processList, 'memory');
|
const highestMemoryProcess = getProcessIdWithHighestProperty(processList, 'memory');
|
||||||
|
|
||||||
const tableHead = document.createElement('thead');
|
const body = document.createElement('tbody');
|
||||||
tableHead.innerHTML = `<tr>
|
|
||||||
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
|
|
||||||
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
|
|
||||||
<th scope="col" class="pid">${localize('pid', "pid")}</th>
|
|
||||||
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
|
|
||||||
</tr>`;
|
|
||||||
|
|
||||||
const tableBody = document.createElement('tbody');
|
if (renderManySections) {
|
||||||
|
renderProcessGroupHeader(sectionName, body, container);
|
||||||
|
}
|
||||||
|
|
||||||
processList.forEach(p => {
|
processList.forEach(p => {
|
||||||
const row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
row.id = p.pid;
|
row.id = p.pid.toString();
|
||||||
|
|
||||||
const cpu = document.createElement('td');
|
const cpu = document.createElement('td');
|
||||||
p.pid === highestCPUProcess
|
p.pid === highestCPUProcess
|
||||||
? cpu.classList.add('centered', 'highest')
|
? cpu.classList.add('centered', 'highest')
|
||||||
: cpu.classList.add('centered');
|
: cpu.classList.add('centered');
|
||||||
cpu.textContent = p.cpu;
|
cpu.textContent = p.cpu.toString();
|
||||||
|
|
||||||
const memory = document.createElement('td');
|
const memory = document.createElement('td');
|
||||||
p.pid === highestMemoryProcess
|
p.pid === highestMemoryProcess
|
||||||
@@ -160,10 +221,45 @@ function updateProcessInfo(processList: any[]): void {
|
|||||||
name.textContent = p.formattedName;
|
name.textContent = p.formattedName;
|
||||||
|
|
||||||
row.append(cpu, memory, pid, name);
|
row.append(cpu, memory, pid, name);
|
||||||
tableBody.appendChild(row);
|
|
||||||
|
listeners.push(addDisposableListener(row, 'contextmenu', (e) => {
|
||||||
|
showContextMenu(e, p, sectionIsLocal);
|
||||||
|
}));
|
||||||
|
|
||||||
|
body.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
container.append(tableHead, tableBody);
|
container.appendChild(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProcessInfo(processLists: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]): void {
|
||||||
|
const container = document.getElementById('process-list');
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.innerHTML = '';
|
||||||
|
listeners.forEach(l => l.dispose());
|
||||||
|
|
||||||
|
const tableHead = document.createElement('thead');
|
||||||
|
tableHead.innerHTML = `<tr>
|
||||||
|
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
|
||||||
|
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
|
||||||
|
<th scope="col" class="pid">${localize('pid', "pid")}</th>
|
||||||
|
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
|
||||||
|
</tr>`;
|
||||||
|
|
||||||
|
container.append(tableHead);
|
||||||
|
|
||||||
|
const hasMultipleMachines = Object.keys(processLists).length > 1;
|
||||||
|
processLists.forEach((remote, i) => {
|
||||||
|
const isLocal = i === 0;
|
||||||
|
if (isRemoteDiagnosticError(remote.rootProcess)) {
|
||||||
|
renderProcessFetchError(remote.name, remote.rootProcess.errorMessage);
|
||||||
|
} else {
|
||||||
|
renderTableSection(remote.name, getProcessList(remote.rootProcess, isLocal), hasMultipleMachines, isLocal);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStyles(styles: ProcessExplorerStyles): void {
|
function applyStyles(styles: ProcessExplorerStyles): void {
|
||||||
@@ -171,11 +267,11 @@ function applyStyles(styles: ProcessExplorerStyles): void {
|
|||||||
const content: string[] = [];
|
const content: string[] = [];
|
||||||
|
|
||||||
if (styles.hoverBackground) {
|
if (styles.hoverBackground) {
|
||||||
content.push(`tbody > tr:hover { background-color: ${styles.hoverBackground}; }`);
|
content.push(`tbody > tr:hover, table > tr:hover { background-color: ${styles.hoverBackground}; }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styles.hoverForeground) {
|
if (styles.hoverForeground) {
|
||||||
content.push(`tbody > tr:hover{ color: ${styles.hoverForeground}; }`);
|
content.push(`tbody > tr:hover, table > tr:hover { color: ${styles.hoverForeground}; }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styles.highlightForeground) {
|
if (styles.highlightForeground) {
|
||||||
@@ -200,13 +296,13 @@ function applyZoom(zoomLevel: number): void {
|
|||||||
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
|
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showContextMenu(e: MouseEvent) {
|
function showContextMenu(e: MouseEvent, item: FormattedProcessItem, isLocal: boolean) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const items: IContextMenuItem[] = [];
|
const items: IContextMenuItem[] = [];
|
||||||
|
const pid = Number(item.pid);
|
||||||
|
|
||||||
const pid = parseInt((e.currentTarget as HTMLElement).id);
|
if (isLocal) {
|
||||||
if (pid && typeof pid === 'number') {
|
|
||||||
items.push({
|
items.push({
|
||||||
label: localize('killProcess', "Kill Process"),
|
label: localize('killProcess', "Kill Process"),
|
||||||
click() {
|
click() {
|
||||||
@@ -224,48 +320,37 @@ function showContextMenu(e: MouseEvent) {
|
|||||||
items.push({
|
items.push({
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
label: localize('copy', "Copy"),
|
label: localize('copy', "Copy"),
|
||||||
click() {
|
click() {
|
||||||
const row = document.getElementById(pid.toString());
|
const row = document.getElementById(pid.toString());
|
||||||
if (row) {
|
if (row) {
|
||||||
clipboard.writeText(row.innerText);
|
clipboard.writeText(row.innerText);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
label: localize('copyAll', "Copy All"),
|
|
||||||
click() {
|
|
||||||
const processList = document.getElementById('process-list');
|
|
||||||
if (processList) {
|
|
||||||
clipboard.writeText(processList.innerText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const item = processList.filter(process => process.pid === pid)[0];
|
|
||||||
if (item && isDebuggable(item.cmd)) {
|
|
||||||
items.push({
|
|
||||||
type: 'separator'
|
|
||||||
});
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
label: localize('debug', "Debug"),
|
|
||||||
click() {
|
|
||||||
attachTo(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
label: localize('copyAll', "Copy All"),
|
||||||
|
click() {
|
||||||
|
const processList = document.getElementById('process-list');
|
||||||
|
if (processList) {
|
||||||
|
clipboard.writeText(processList.innerText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (item && isLocal && isDebuggable(item.cmd)) {
|
||||||
items.push({
|
items.push({
|
||||||
label: localize('copyAll', "Copy All"),
|
type: 'separator'
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
label: localize('debug', "Debug"),
|
||||||
click() {
|
click() {
|
||||||
const processList = document.getElementById('process-list');
|
attachTo(item);
|
||||||
if (processList) {
|
|
||||||
clipboard.writeText(processList.innerText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -273,6 +358,22 @@ function showContextMenu(e: MouseEvent) {
|
|||||||
popup(items);
|
popup(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestProcessList(totalWaitTime: number): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
const nextRequestTime = Date.now();
|
||||||
|
const waited = totalWaitTime + nextRequestTime - lastRequestTime;
|
||||||
|
lastRequestTime = nextRequestTime;
|
||||||
|
|
||||||
|
// Wait at least a second between requests.
|
||||||
|
if (waited > 1000) {
|
||||||
|
ipcRenderer.send('windowsInfoRequest');
|
||||||
|
ipcRenderer.send('vscode:listProcesses');
|
||||||
|
} else {
|
||||||
|
requestProcessList(waited);
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
export function startup(data: ProcessExplorerData): void {
|
export function startup(data: ProcessExplorerData): void {
|
||||||
applyStyles(data.styles);
|
applyStyles(data.styles);
|
||||||
applyZoom(data.zoomLevel);
|
applyZoom(data.zoomLevel);
|
||||||
@@ -283,23 +384,14 @@ export function startup(data: ProcessExplorerData): void {
|
|||||||
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
|
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
ipcRenderer.on('vscode:listProcessesResponse', (_event: Event, processRoots: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]) => {
|
||||||
ipcRenderer.send('windowsInfoRequest');
|
updateProcessInfo(processRoots);
|
||||||
|
requestProcessList(0);
|
||||||
listProcesses(data.pid).then(processes => {
|
});
|
||||||
processList = getProcessList(processes);
|
|
||||||
updateProcessInfo(processList);
|
|
||||||
|
|
||||||
const tableRows = document.getElementsByTagName('tr');
|
|
||||||
for (let i = 0; i < tableRows.length; i++) {
|
|
||||||
const tableRow = tableRows[i];
|
|
||||||
tableRow.addEventListener('contextmenu', (e) => {
|
|
||||||
showContextMenu(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 1200);
|
|
||||||
|
|
||||||
|
lastRequestTime = Date.now();
|
||||||
|
ipcRenderer.send('windowsInfoRequest');
|
||||||
|
ipcRenderer.send('vscode:listProcesses');
|
||||||
|
|
||||||
document.onkeydown = (e: KeyboardEvent) => {
|
document.onkeydown = (e: KeyboardEvent) => {
|
||||||
const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey;
|
const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
|
|||||||
|
|
||||||
services.set(IEnvironmentService, environmentService);
|
services.set(IEnvironmentService, environmentService);
|
||||||
services.set(ILogService, logService);
|
services.set(ILogService, logService);
|
||||||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
|
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
|
|||||||
instantiationService.invokeFunction(accessor => {
|
instantiationService.invokeFunction(accessor => {
|
||||||
const services = new ServiceCollection();
|
const services = new ServiceCollection();
|
||||||
const environmentService = accessor.get(IEnvironmentService);
|
const environmentService = accessor.get(IEnvironmentService);
|
||||||
const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
|
const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
|
||||||
const telemetryLogService = new FollowerLogService(logLevelClient, createSpdLogService('telemetry', initData.logLevel, environmentService.logsPath));
|
const telemetryLogService = new FollowerLogService(logLevelClient, createSpdLogService('telemetry', initData.logLevel, environmentService.logsPath));
|
||||||
telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
|
telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
|
||||||
telemetryLogService.info('===========================================================');
|
telemetryLogService.info('===========================================================');
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ import { storeBackgroundColor } from 'vs/code/electron-main/theme';
|
|||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { join, sep } from 'vs/base/common/path';
|
import { join, sep } from 'vs/base/common/path';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
||||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap';
|
import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap';
|
||||||
@@ -748,7 +748,7 @@ export class CodeApplication extends Disposable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protocol.registerBufferProtocol(REMOTE_HOST_SCHEME, async (request, callback) => {
|
protocol.registerBufferProtocol(Schemas.vscodeRemote, async (request, callback) => {
|
||||||
if (request.method !== 'GET') {
|
if (request.method !== 'GET') {
|
||||||
return callback(undefined);
|
return callback(undefined);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ function createServices(args: ParsedArgs, bufferLogService: BufferLogService): I
|
|||||||
services.set(ILogService, logService);
|
services.set(ILogService, logService);
|
||||||
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
|
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
|
||||||
services.set(IStateService, new SyncDescriptor(StateService));
|
services.set(IStateService, new SyncDescriptor(StateService));
|
||||||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
|
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
||||||
|
|
||||||
|
|||||||
@@ -320,6 +320,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||||||
this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => {
|
this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => {
|
||||||
this.marketplaceHeadersPromise.then(headers => {
|
this.marketplaceHeadersPromise.then(headers => {
|
||||||
const requestHeaders = objects.assign(details.requestHeaders, headers);
|
const requestHeaders = objects.assign(details.requestHeaders, headers);
|
||||||
|
if (!this.configurationService.getValue('extensions.disableExperimentalAzureSearch')) {
|
||||||
|
requestHeaders['Cookie'] = `${requestHeaders['Cookie'] ? requestHeaders['Cookie'] + ';' : ''}EnableExternalSearchForVSCode=true`;
|
||||||
|
}
|
||||||
cb({ cancel: false, requestHeaders });
|
cb({ cancel: false, requestHeaders });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ function shouldSpawnCliProcess(argv: ParsedArgs): boolean {
|
|||||||
return !!argv['install-source']
|
return !!argv['install-source']
|
||||||
|| !!argv['list-extensions']
|
|| !!argv['list-extensions']
|
||||||
|| !!argv['install-extension']
|
|| !!argv['install-extension']
|
||||||
|| !!argv['uninstall-extension'];
|
|| !!argv['uninstall-extension']
|
||||||
|
|| !!argv['locate-extension'];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMainCli {
|
interface IMainCli {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import { IExtensionManifest, ExtensionType, isLanguagePackExtension } from 'vs/p
|
|||||||
import { isUIExtension } from 'vs/platform/extensions/node/extensionsUtil';
|
import { isUIExtension } from 'vs/platform/extensions/node/extensionsUtil';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
|
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
|
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
|
||||||
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
|
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
|
||||||
@@ -92,6 +93,10 @@ export class Main {
|
|||||||
const arg = argv['uninstall-extension'];
|
const arg = argv['uninstall-extension'];
|
||||||
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
|
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
|
||||||
await this.uninstallExtension(ids);
|
await this.uninstallExtension(ids);
|
||||||
|
} else if (argv['locate-extension']) {
|
||||||
|
const arg = argv['locate-extension'];
|
||||||
|
const ids: string[] = typeof arg === 'string' ? [arg] : arg;
|
||||||
|
await this.locateExtension(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +262,20 @@ export class Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async locateExtension(extensions: string[]): Promise<void> {
|
||||||
|
const installed = await this.extensionManagementService.getInstalled();
|
||||||
|
extensions.forEach(e => {
|
||||||
|
installed.forEach(i => {
|
||||||
|
if (i.identifier.id === e) {
|
||||||
|
if (i.location.scheme === Schemas.file) {
|
||||||
|
console.log(i.location.fsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async updateLocalizationsCache(): Promise<void> {
|
private async updateLocalizationsCache(): Promise<void> {
|
||||||
const localizationService = this.instantiationService.createInstance(LocalizationsService);
|
const localizationService = this.instantiationService.createInstance(LocalizationsService);
|
||||||
await localizationService.update();
|
await localizationService.update();
|
||||||
@@ -286,10 +305,10 @@ export function main(argv: ParsedArgs): Promise<void> {
|
|||||||
const stateService = accessor.get(IStateService);
|
const stateService = accessor.get(IStateService);
|
||||||
|
|
||||||
return Promise.all([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => {
|
return Promise.all([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => {
|
||||||
const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService;
|
const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService;
|
||||||
|
|
||||||
const services = new ServiceCollection();
|
const services = new ServiceCollection();
|
||||||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
|
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService, [false]));
|
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService, [false]));
|
||||||
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
|
||||||
@@ -321,4 +340,4 @@ export function main(argv: ParsedArgs): Promise<void> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,8 @@ export class MouseHandler extends ViewEventHandler {
|
|||||||
this._register(mouseEvents.onMouseDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e)));
|
this._register(mouseEvents.onMouseDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e)));
|
||||||
|
|
||||||
const onMouseWheel = (browserEvent: IMouseWheelEvent) => {
|
const onMouseWheel = (browserEvent: IMouseWheelEvent) => {
|
||||||
|
this.viewController.emitMouseWheel(browserEvent);
|
||||||
|
|
||||||
if (!this._context.configuration.editor.viewInfo.mouseWheelZoom) {
|
if (!this._context.configuration.editor.viewInfo.mouseWheelZoom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -259,6 +261,10 @@ export class MouseHandler extends ViewEventHandler {
|
|||||||
target: t
|
target: t
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public _onMouseWheel(e: IMouseWheelEvent): void {
|
||||||
|
this.viewController.emitMouseWheel(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MouseDownOperation extends Disposable {
|
class MouseDownOperation extends Disposable {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
import { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import * as editorOptions from 'vs/editor/common/config/editorOptions';
|
import * as editorOptions from 'vs/editor/common/config/editorOptions';
|
||||||
import { ICursors } from 'vs/editor/common/controller/cursorCommon';
|
import { ICursors } from 'vs/editor/common/controller/cursorCommon';
|
||||||
@@ -461,6 +461,12 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
|||||||
* @event
|
* @event
|
||||||
*/
|
*/
|
||||||
onMouseLeave(listener: (e: IPartialEditorMouseEvent) => void): IDisposable;
|
onMouseLeave(listener: (e: IPartialEditorMouseEvent) => void): IDisposable;
|
||||||
|
/**
|
||||||
|
* An event emitted on a "mousewheel"
|
||||||
|
* @event
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
onMouseWheel(listener: (e: IMouseWheelEvent) => void): IDisposable;
|
||||||
/**
|
/**
|
||||||
* An event emitted on a "keyup".
|
* An event emitted on a "keyup".
|
||||||
* @event
|
* @event
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Position } from 'vs/editor/common/core/position';
|
|||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
||||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||||
|
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
|
||||||
export interface IMouseDispatchData {
|
export interface IMouseDispatchData {
|
||||||
position: Position;
|
position: Position;
|
||||||
@@ -316,4 +317,8 @@ export class ViewController {
|
|||||||
public emitMouseDrop(e: IPartialEditorMouseEvent): void {
|
public emitMouseDrop(e: IPartialEditorMouseEvent): void {
|
||||||
this.outgoingEvents.emitMouseDrop(e);
|
this.outgoingEvents.emitMouseDrop(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitMouseWheel(e: IMouseWheelEvent): void {
|
||||||
|
this.outgoingEvents.emitMouseWheel(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Range } from 'vs/editor/common/core/range';
|
|||||||
import { IScrollEvent } from 'vs/editor/common/editorCommon';
|
import { IScrollEvent } from 'vs/editor/common/editorCommon';
|
||||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||||
|
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
|
||||||
export interface EventCallback<T> {
|
export interface EventCallback<T> {
|
||||||
(event: T): void;
|
(event: T): void;
|
||||||
@@ -31,6 +32,7 @@ export class ViewOutgoingEvents extends Disposable {
|
|||||||
public onMouseDown: EventCallback<IEditorMouseEvent> | null = null;
|
public onMouseDown: EventCallback<IEditorMouseEvent> | null = null;
|
||||||
public onMouseDrag: EventCallback<IEditorMouseEvent> | null = null;
|
public onMouseDrag: EventCallback<IEditorMouseEvent> | null = null;
|
||||||
public onMouseDrop: EventCallback<IPartialEditorMouseEvent> | null = null;
|
public onMouseDrop: EventCallback<IPartialEditorMouseEvent> | null = null;
|
||||||
|
public onMouseWheel: EventCallback<IMouseWheelEvent> | null = null;
|
||||||
|
|
||||||
private readonly _viewModel: IViewModel;
|
private readonly _viewModel: IViewModel;
|
||||||
|
|
||||||
@@ -111,6 +113,12 @@ export class ViewOutgoingEvents extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitMouseWheel(e: IMouseWheelEvent): void {
|
||||||
|
if (this.onMouseWheel) {
|
||||||
|
this.onMouseWheel(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent;
|
private _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent;
|
||||||
private _convertViewToModelMouseEvent(e: IPartialEditorMouseEvent): IPartialEditorMouseEvent;
|
private _convertViewToModelMouseEvent(e: IPartialEditorMouseEvent): IPartialEditorMouseEvent;
|
||||||
private _convertViewToModelMouseEvent(e: IEditorMouseEvent | IPartialEditorMouseEvent): IEditorMouseEvent | IPartialEditorMouseEvent {
|
private _convertViewToModelMouseEvent(e: IEditorMouseEvent | IPartialEditorMouseEvent): IEditorMouseEvent | IPartialEditorMouseEvent {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import 'vs/css!./media/tokens';
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
import { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
@@ -186,6 +186,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
private readonly _onMouseLeave: Emitter<editorBrowser.IPartialEditorMouseEvent> = this._register(new Emitter<editorBrowser.IPartialEditorMouseEvent>());
|
private readonly _onMouseLeave: Emitter<editorBrowser.IPartialEditorMouseEvent> = this._register(new Emitter<editorBrowser.IPartialEditorMouseEvent>());
|
||||||
public readonly onMouseLeave: Event<editorBrowser.IPartialEditorMouseEvent> = this._onMouseLeave.event;
|
public readonly onMouseLeave: Event<editorBrowser.IPartialEditorMouseEvent> = this._onMouseLeave.event;
|
||||||
|
|
||||||
|
private readonly _onMouseWheel: Emitter<IMouseWheelEvent> = this._register(new Emitter<IMouseWheelEvent>());
|
||||||
|
public readonly onMouseWheel: Event<IMouseWheelEvent> = this._onMouseWheel.event;
|
||||||
|
|
||||||
private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
|
private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
|
||||||
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
||||||
|
|
||||||
@@ -1442,6 +1445,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
// In IE, the focus is not synchronous, so we give it a little help
|
// In IE, the focus is not synchronous, so we give it a little help
|
||||||
this._editorWidgetFocus.setValue(true);
|
this._editorWidgetFocus.setValue(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
viewOutgoingEvents.onDidScroll = (e) => this._onDidScrollChange.fire(e);
|
viewOutgoingEvents.onDidScroll = (e) => this._onDidScrollChange.fire(e);
|
||||||
viewOutgoingEvents.onDidLoseFocus = () => this._editorTextFocus.setValue(false);
|
viewOutgoingEvents.onDidLoseFocus = () => this._editorTextFocus.setValue(false);
|
||||||
viewOutgoingEvents.onContextMenu = (e) => this._onContextMenu.fire(e);
|
viewOutgoingEvents.onContextMenu = (e) => this._onContextMenu.fire(e);
|
||||||
@@ -1452,6 +1456,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
viewOutgoingEvents.onKeyUp = (e) => this._onKeyUp.fire(e);
|
viewOutgoingEvents.onKeyUp = (e) => this._onKeyUp.fire(e);
|
||||||
viewOutgoingEvents.onMouseMove = (e) => this._onMouseMove.fire(e);
|
viewOutgoingEvents.onMouseMove = (e) => this._onMouseMove.fire(e);
|
||||||
viewOutgoingEvents.onMouseLeave = (e) => this._onMouseLeave.fire(e);
|
viewOutgoingEvents.onMouseLeave = (e) => this._onMouseLeave.fire(e);
|
||||||
|
viewOutgoingEvents.onMouseWheel = (e) => this._onMouseWheel.fire(e);
|
||||||
viewOutgoingEvents.onKeyDown = (e) => this._onKeyDown.fire(e);
|
viewOutgoingEvents.onKeyDown = (e) => this._onKeyDown.fire(e);
|
||||||
|
|
||||||
const view = new View(
|
const view = new View(
|
||||||
|
|||||||
@@ -1958,7 +1958,7 @@ export class EditorOptionsValidator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _santizeGotoLocationOpts(opts: IEditorOptions, defaults: InternalGoToLocationOptions): InternalGoToLocationOptions {
|
private static _sanitizeGotoLocationOpts(opts: IEditorOptions, defaults: InternalGoToLocationOptions): InternalGoToLocationOptions {
|
||||||
const gotoOpts = opts.gotoLocation || {};
|
const gotoOpts = opts.gotoLocation || {};
|
||||||
return {
|
return {
|
||||||
multiple: _stringSet<'peek' | 'gotoAndPeek' | 'goto'>(gotoOpts.multiple, defaults.multiple, ['peek', 'gotoAndPeek', 'goto'])
|
multiple: _stringSet<'peek' | 'gotoAndPeek' | 'goto'>(gotoOpts.multiple, defaults.multiple, ['peek', 'gotoAndPeek', 'goto'])
|
||||||
@@ -2117,7 +2117,7 @@ export class EditorOptionsValidator {
|
|||||||
suggestLineHeight: _clampedInt(opts.suggestLineHeight, defaults.suggestLineHeight, 0, 1000),
|
suggestLineHeight: _clampedInt(opts.suggestLineHeight, defaults.suggestLineHeight, 0, 1000),
|
||||||
tabCompletion: this._sanitizeTabCompletionOpts(opts.tabCompletion, defaults.tabCompletion),
|
tabCompletion: this._sanitizeTabCompletionOpts(opts.tabCompletion, defaults.tabCompletion),
|
||||||
suggest: this._sanitizeSuggestOpts(opts, defaults.suggest),
|
suggest: this._sanitizeSuggestOpts(opts, defaults.suggest),
|
||||||
gotoLocation: this._santizeGotoLocationOpts(opts, defaults.gotoLocation),
|
gotoLocation: this._sanitizeGotoLocationOpts(opts, defaults.gotoLocation),
|
||||||
selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight),
|
selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight),
|
||||||
occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight),
|
occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight),
|
||||||
codeLens: _boolean(opts.codeLens, defaults.codeLens),
|
codeLens: _boolean(opts.codeLens, defaults.codeLens),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
import { registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||||
import { CodeActionCommand, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction, AutoFixAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
import { CodeActionCommand, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction, AutoFixAction, FixAllAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||||
|
|
||||||
|
|
||||||
registerEditorContribution(QuickFixController);
|
registerEditorContribution(QuickFixController);
|
||||||
@@ -13,4 +13,5 @@ registerEditorAction(RefactorAction);
|
|||||||
registerEditorAction(SourceAction);
|
registerEditorAction(SourceAction);
|
||||||
registerEditorAction(OrganizeImportsAction);
|
registerEditorAction(OrganizeImportsAction);
|
||||||
registerEditorAction(AutoFixAction);
|
registerEditorAction(AutoFixAction);
|
||||||
|
registerEditorAction(FixAllAction);
|
||||||
registerEditorCommand(new CodeActionCommand());
|
registerEditorCommand(new CodeActionCommand());
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { KeyCode, KeyMod, ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
|||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||||
import { IEditorContribution, IScrollEvent, ScrollType } from 'vs/editor/common/editorCommon';
|
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
||||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
@@ -21,6 +21,7 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie
|
|||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
|
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
|
||||||
export class ContextMenuController implements IEditorContribution {
|
export class ContextMenuController implements IEditorContribution {
|
||||||
|
|
||||||
@@ -45,8 +46,8 @@ export class ContextMenuController implements IEditorContribution {
|
|||||||
this._editor = editor;
|
this._editor = editor;
|
||||||
|
|
||||||
this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e)));
|
this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e)));
|
||||||
this._toDispose.push(this._editor.onDidScrollChange((e: IScrollEvent) => {
|
this._toDispose.push(this._editor.onMouseWheel((e: IMouseWheelEvent) => {
|
||||||
if (this._contextMenuIsBeingShownCount > 0 && e.scrollTopChanged) {
|
if (this._contextMenuIsBeingShownCount > 0) {
|
||||||
this._contextViewService.hideContextView();
|
this._contextViewService.hideContextView();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ export async function formatDocumentWithSelectedProvider(
|
|||||||
const provider = getRealAndSyntheticDocumentFormattersOrdered(model);
|
const provider = getRealAndSyntheticDocumentFormattersOrdered(model);
|
||||||
const selected = await FormattingConflicts.select(provider, model, mode);
|
const selected = await FormattingConflicts.select(provider, model, mode);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
await instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, token);
|
await instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, mode, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +222,7 @@ export async function formatDocumentWithProvider(
|
|||||||
accessor: ServicesAccessor,
|
accessor: ServicesAccessor,
|
||||||
provider: DocumentFormattingEditProvider,
|
provider: DocumentFormattingEditProvider,
|
||||||
editorOrModel: ITextModel | IActiveCodeEditor,
|
editorOrModel: ITextModel | IActiveCodeEditor,
|
||||||
|
mode: FormattingMode,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const workerService = accessor.get(IEditorWorkerService);
|
const workerService = accessor.get(IEditorWorkerService);
|
||||||
@@ -255,10 +256,13 @@ export async function formatDocumentWithProvider(
|
|||||||
if (isCodeEditor(editorOrModel)) {
|
if (isCodeEditor(editorOrModel)) {
|
||||||
// use editor to apply edits
|
// use editor to apply edits
|
||||||
FormattingEdit.execute(editorOrModel, edits);
|
FormattingEdit.execute(editorOrModel, edits);
|
||||||
alertFormattingEdits(edits);
|
|
||||||
editorOrModel.pushUndoStop();
|
if (mode !== FormattingMode.Silent) {
|
||||||
editorOrModel.focus();
|
alertFormattingEdits(edits);
|
||||||
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
|
editorOrModel.pushUndoStop();
|
||||||
|
editorOrModel.focus();
|
||||||
|
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// use model to apply edits
|
// use model to apply edits
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
const storageKey = 'peekViewLayout';
|
const storageKey = 'peekViewLayout';
|
||||||
const data = <LayoutData>JSON.parse(this._storageService.get(storageKey, StorageScope.GLOBAL, '{}'));
|
const data = LayoutData.fromJSON(this._storageService.get(storageKey, StorageScope.GLOBAL, '{}'));
|
||||||
this._widget = this._instantiationService.createInstance(ReferenceWidget, this._editor, this._defaultTreeKeyboardSupport, data);
|
this._widget = this._instantiationService.createInstance(ReferenceWidget, this._editor, this._defaultTreeKeyboardSupport, data);
|
||||||
this._widget.setTitle(nls.localize('labelLoading', "Loading..."));
|
this._widget.setTitle(nls.localize('labelLoading', "Loading..."));
|
||||||
this._widget.show(range);
|
this._widget.show(range);
|
||||||
|
|||||||
@@ -157,9 +157,25 @@ class DecorationsManager implements IDisposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LayoutData {
|
export class LayoutData {
|
||||||
ratio: number;
|
ratio: number;
|
||||||
heightInLines: number;
|
heightInLines: number;
|
||||||
|
|
||||||
|
static fromJSON(raw: string): LayoutData {
|
||||||
|
let ratio: number | undefined;
|
||||||
|
let heightInLines: number | undefined;
|
||||||
|
try {
|
||||||
|
const data = <LayoutData>JSON.parse(raw);
|
||||||
|
ratio = data.ratio;
|
||||||
|
heightInLines = data.heightInLines;
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ratio: ratio || 0.7,
|
||||||
|
heightInLines: heightInLines || 18
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectionEvent {
|
export interface SelectionEvent {
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import * as arrays from 'vs/base/common/arrays';
|
|||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import * as objects from 'vs/base/common/objects';
|
import * as objects from 'vs/base/common/objects';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
import { OVERRIDE_PROPERTY_PATTERN, ConfigurationScope, IConfigurationRegistry, Extensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, toOverrides } from 'vs/platform/configuration/common/configuration';
|
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, toOverrides } from 'vs/platform/configuration/common/configuration';
|
||||||
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
export class ConfigurationModel implements IConfigurationModel {
|
export class ConfigurationModel implements IConfigurationModel {
|
||||||
|
|
||||||
@@ -195,10 +196,11 @@ export class DefaultConfigurationModel extends ConfigurationModel {
|
|||||||
|
|
||||||
export class ConfigurationModelParser {
|
export class ConfigurationModelParser {
|
||||||
|
|
||||||
|
private _raw: any = null;
|
||||||
private _configurationModel: ConfigurationModel | null = null;
|
private _configurationModel: ConfigurationModel | null = null;
|
||||||
private _parseErrors: any[] = [];
|
private _parseErrors: any[] = [];
|
||||||
|
|
||||||
constructor(protected readonly _name: string) { }
|
constructor(protected readonly _name: string, private _scopes?: ConfigurationScope[]) { }
|
||||||
|
|
||||||
get configurationModel(): ConfigurationModel {
|
get configurationModel(): ConfigurationModel {
|
||||||
return this._configurationModel || new ConfigurationModel();
|
return this._configurationModel || new ConfigurationModel();
|
||||||
@@ -208,15 +210,26 @@ export class ConfigurationModelParser {
|
|||||||
return this._parseErrors;
|
return this._parseErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public parse(content: string | null | undefined): void {
|
public parseContent(content: string | null | undefined): void {
|
||||||
if (content) {
|
if (content) {
|
||||||
const raw = this.parseContent(content);
|
const raw = this.doParseContent(content);
|
||||||
const configurationModel = this.parseRaw(raw);
|
this.parseRaw(raw);
|
||||||
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected parseContent(content: string): any {
|
public parseRaw(raw: any): void {
|
||||||
|
this._raw = raw;
|
||||||
|
const configurationModel = this.doParseRaw(raw);
|
||||||
|
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(): void {
|
||||||
|
if (this._raw) {
|
||||||
|
this.parseRaw(this._raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doParseContent(content: string): any {
|
||||||
let raw: any = {};
|
let raw: any = {};
|
||||||
let currentProperty: string | null = null;
|
let currentProperty: string | null = null;
|
||||||
let currentParent: any = [];
|
let currentParent: any = [];
|
||||||
@@ -273,12 +286,36 @@ export class ConfigurationModelParser {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected parseRaw(raw: any): IConfigurationModel {
|
protected doParseRaw(raw: any): IConfigurationModel {
|
||||||
|
if (this._scopes) {
|
||||||
|
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||||
|
raw = this.filterByScope(raw, configurationProperties, true, this._scopes);
|
||||||
|
}
|
||||||
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||||
const keys = Object.keys(raw);
|
const keys = Object.keys(raw);
|
||||||
const overrides: IOverrides[] = toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
const overrides: IOverrides[] = toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||||
return { contents, keys, overrides };
|
return { contents, keys, overrides };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private filterByScope(properties: {}, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }, filterOverriddenProperties: boolean, scopes: ConfigurationScope[]): {} {
|
||||||
|
const result = {};
|
||||||
|
for (let key in properties) {
|
||||||
|
if (OVERRIDE_PROPERTY_PATTERN.test(key) && filterOverriddenProperties) {
|
||||||
|
result[key] = this.filterByScope(properties[key], configurationProperties, false, scopes);
|
||||||
|
} else {
|
||||||
|
const scope = this.getScope(key, configurationProperties);
|
||||||
|
if (scopes.indexOf(scope) !== -1) {
|
||||||
|
result[key] = properties[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope {
|
||||||
|
const propertySchema = configurationProperties[key];
|
||||||
|
return propertySchema && typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Configuration {
|
export class Configuration {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class NodeBasedUserConfiguration extends Disposable {
|
|||||||
this.userConfigModelWatcher = new ConfigWatcher(this.settingsPath, {
|
this.userConfigModelWatcher = new ConfigWatcher(this.settingsPath, {
|
||||||
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsPath), parse: (content: string, parseErrors: any[]) => {
|
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsPath), parse: (content: string, parseErrors: any[]) => {
|
||||||
const userConfigModelParser = new ConfigurationModelParser(this.settingsPath);
|
const userConfigModelParser = new ConfigurationModelParser(this.settingsPath);
|
||||||
userConfigModelParser.parse(content);
|
userConfigModelParser.parseContent(content);
|
||||||
parseErrors = [...userConfigModelParser.errors];
|
parseErrors = [...userConfigModelParser.errors];
|
||||||
return userConfigModelParser;
|
return userConfigModelParser;
|
||||||
}, initCallback: () => c(undefined)
|
}, initCallback: () => c(undefined)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
|||||||
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration';
|
||||||
import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
|
||||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration';
|
import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration';
|
||||||
|
|
||||||
@@ -24,11 +23,11 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
|||||||
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IEnvironmentService environmentService: IEnvironmentService
|
configurationPath: string
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.userConfiguration = this._register(new NodeBasedUserConfiguration(environmentService.appSettingsPath));
|
this.userConfiguration = this._register(new NodeBasedUserConfiguration(configurationPath));
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
const defaults = new DefaultConfigurationModel();
|
const defaults = new DefaultConfigurationModel();
|
||||||
|
|||||||
@@ -250,10 +250,10 @@ suite('CustomConfigurationModel', () => {
|
|||||||
|
|
||||||
test('simple merge using models', () => {
|
test('simple merge using models', () => {
|
||||||
let base = new ConfigurationModelParser('base');
|
let base = new ConfigurationModelParser('base');
|
||||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||||
|
|
||||||
let add = new ConfigurationModelParser('add');
|
let add = new ConfigurationModelParser('add');
|
||||||
add.parse(JSON.stringify({ 'a': 3, 'c': 4 }));
|
add.parseContent(JSON.stringify({ 'a': 3, 'c': 4 }));
|
||||||
|
|
||||||
let result = base.configurationModel.merge(add.configurationModel);
|
let result = base.configurationModel.merge(add.configurationModel);
|
||||||
assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 });
|
assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 });
|
||||||
@@ -261,14 +261,14 @@ suite('CustomConfigurationModel', () => {
|
|||||||
|
|
||||||
test('simple merge with an undefined contents', () => {
|
test('simple merge with an undefined contents', () => {
|
||||||
let base = new ConfigurationModelParser('base');
|
let base = new ConfigurationModelParser('base');
|
||||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||||
let add = new ConfigurationModelParser('add');
|
let add = new ConfigurationModelParser('add');
|
||||||
let result = base.configurationModel.merge(add.configurationModel);
|
let result = base.configurationModel.merge(add.configurationModel);
|
||||||
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||||
|
|
||||||
base = new ConfigurationModelParser('base');
|
base = new ConfigurationModelParser('base');
|
||||||
add = new ConfigurationModelParser('add');
|
add = new ConfigurationModelParser('add');
|
||||||
add.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
add.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||||
result = base.configurationModel.merge(add.configurationModel);
|
result = base.configurationModel.merge(add.configurationModel);
|
||||||
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||||
|
|
||||||
@@ -280,25 +280,25 @@ suite('CustomConfigurationModel', () => {
|
|||||||
|
|
||||||
test('Recursive merge using config models', () => {
|
test('Recursive merge using config models', () => {
|
||||||
let base = new ConfigurationModelParser('base');
|
let base = new ConfigurationModelParser('base');
|
||||||
base.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
base.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||||
let add = new ConfigurationModelParser('add');
|
let add = new ConfigurationModelParser('add');
|
||||||
add.parse(JSON.stringify({ 'a': { 'b': 2 } }));
|
add.parseContent(JSON.stringify({ 'a': { 'b': 2 } }));
|
||||||
let result = base.configurationModel.merge(add.configurationModel);
|
let result = base.configurationModel.merge(add.configurationModel);
|
||||||
assert.deepEqual(result.contents, { 'a': { 'b': 2 } });
|
assert.deepEqual(result.contents, { 'a': { 'b': 2 } });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test contents while getting an existing property', () => {
|
test('Test contents while getting an existing property', () => {
|
||||||
let testObject = new ConfigurationModelParser('test');
|
let testObject = new ConfigurationModelParser('test');
|
||||||
testObject.parse(JSON.stringify({ 'a': 1 }));
|
testObject.parseContent(JSON.stringify({ 'a': 1 }));
|
||||||
assert.deepEqual(testObject.configurationModel.getValue('a'), 1);
|
assert.deepEqual(testObject.configurationModel.getValue('a'), 1);
|
||||||
|
|
||||||
testObject.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
testObject.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||||
assert.deepEqual(testObject.configurationModel.getValue('a'), { 'b': 1 });
|
assert.deepEqual(testObject.configurationModel.getValue('a'), { 'b': 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test contents are undefined for non existing properties', () => {
|
test('Test contents are undefined for non existing properties', () => {
|
||||||
const testObject = new ConfigurationModelParser('test');
|
const testObject = new ConfigurationModelParser('test');
|
||||||
testObject.parse(JSON.stringify({
|
testObject.parseContent(JSON.stringify({
|
||||||
awesome: true
|
awesome: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ suite('CustomConfigurationModel', () => {
|
|||||||
|
|
||||||
test('Test configWithOverrides gives all content merged with overrides', () => {
|
test('Test configWithOverrides gives all content merged with overrides', () => {
|
||||||
const testObject = new ConfigurationModelParser('test');
|
const testObject = new ConfigurationModelParser('test');
|
||||||
testObject.parse(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
testObject.parseContent(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
||||||
|
|
||||||
assert.deepEqual(testObject.configurationModel.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
|
assert.deepEqual(testObject.configurationModel.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
|
||||||
});
|
});
|
||||||
@@ -326,17 +326,17 @@ suite('CustomConfigurationModel', () => {
|
|||||||
|
|
||||||
test('Test update with empty data', () => {
|
test('Test update with empty data', () => {
|
||||||
const testObject = new ConfigurationModelParser('test');
|
const testObject = new ConfigurationModelParser('test');
|
||||||
testObject.parse('');
|
testObject.parseContent('');
|
||||||
|
|
||||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||||
|
|
||||||
testObject.parse(null!);
|
testObject.parseContent(null!);
|
||||||
|
|
||||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||||
|
|
||||||
testObject.parse(undefined!);
|
testObject.parseContent(undefined!);
|
||||||
|
|
||||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||||
@@ -472,7 +472,7 @@ suite('Configuration', () => {
|
|||||||
|
|
||||||
test('Test update value', () => {
|
test('Test update value', () => {
|
||||||
const parser = new ConfigurationModelParser('test');
|
const parser = new ConfigurationModelParser('test');
|
||||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||||
|
|
||||||
testObject.updateValue('a', 2);
|
testObject.updateValue('a', 2);
|
||||||
@@ -482,7 +482,7 @@ suite('Configuration', () => {
|
|||||||
|
|
||||||
test('Test update value after inspect', () => {
|
test('Test update value after inspect', () => {
|
||||||
const parser = new ConfigurationModelParser('test');
|
const parser = new ConfigurationModelParser('test');
|
||||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||||
|
|
||||||
testObject.inspect('a', {}, undefined);
|
testObject.inspect('a', {}, undefined);
|
||||||
|
|||||||
@@ -10,29 +10,17 @@ import * as fs from 'fs';
|
|||||||
|
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
|
||||||
import { parseArgs } from 'vs/platform/environment/node/argv';
|
|
||||||
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
|
|
||||||
import * as uuid from 'vs/base/common/uuid';
|
import * as uuid from 'vs/base/common/uuid';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { testFile } from 'vs/base/test/node/utils';
|
import { testFile } from 'vs/base/test/node/utils';
|
||||||
|
|
||||||
class SettingsTestEnvironmentService extends EnvironmentService {
|
|
||||||
|
|
||||||
constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) {
|
|
||||||
super(args, _execPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
get appSettingsPath(): string { return this.customAppSettingsHome; }
|
|
||||||
}
|
|
||||||
|
|
||||||
suite('ConfigurationService - Node', () => {
|
suite('ConfigurationService - Node', () => {
|
||||||
|
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
const res = await testFile('config', 'config.json');
|
const res = await testFile('config', 'config.json');
|
||||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
}>();
|
}>();
|
||||||
@@ -49,7 +37,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
testworkbench: {
|
testworkbench: {
|
||||||
editor: {
|
editor: {
|
||||||
@@ -71,7 +59,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(res.testFile, ',,,,');
|
fs.writeFileSync(res.testFile, ',,,,');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
}>();
|
}>();
|
||||||
@@ -87,7 +75,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
const newDir = path.join(parentDir, 'config', id);
|
const newDir = path.join(parentDir, 'config', id);
|
||||||
const testFile = path.join(newDir, 'config.json');
|
const testFile = path.join(newDir, 'config.json');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
|
const service = new ConfigurationService(testFile);
|
||||||
|
|
||||||
const config = service.getValue<{ foo: string }>();
|
const config = service.getValue<{ foo: string }>();
|
||||||
assert.ok(config);
|
assert.ok(config);
|
||||||
@@ -98,7 +86,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
test('trigger configuration change event', async () => {
|
test('trigger configuration change event', async () => {
|
||||||
const res = await testFile('config', 'config.json');
|
const res = await testFile('config', 'config.json');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
return new Promise((c, e) => {
|
return new Promise((c, e) => {
|
||||||
service.onDidChangeConfiguration(() => {
|
service.onDidChangeConfiguration(() => {
|
||||||
assert.equal(service.getValue('foo'), 'bar');
|
assert.equal(service.getValue('foo'), 'bar');
|
||||||
@@ -115,7 +103,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
let config = service.getValue<{
|
let config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
}>();
|
}>();
|
||||||
@@ -163,7 +151,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let serviceWithoutFile = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, '__testFile'));
|
let serviceWithoutFile = new ConfigurationService('__testFile');
|
||||||
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
||||||
|
|
||||||
assert.ok(setting);
|
assert.ok(setting);
|
||||||
@@ -172,7 +160,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
return testFile('config', 'config.json').then(async res => {
|
return testFile('config', 'config.json').then(async res => {
|
||||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||||
|
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
const service = new ConfigurationService(res.testFile);
|
||||||
|
|
||||||
let setting = service.getValue<ITestSetting>();
|
let setting = service.getValue<ITestSetting>();
|
||||||
|
|
||||||
@@ -205,7 +193,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const r = await testFile('config', 'config.json');
|
const r = await testFile('config', 'config.json');
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, r.testFile));
|
const service = new ConfigurationService(r.testFile);
|
||||||
let res = service.inspect('something.missing');
|
let res = service.inspect('something.missing');
|
||||||
assert.strictEqual(res.value, undefined);
|
assert.strictEqual(res.value, undefined);
|
||||||
assert.strictEqual(res.default, undefined);
|
assert.strictEqual(res.default, undefined);
|
||||||
@@ -241,7 +229,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const r = await testFile('config', 'config.json');
|
const r = await testFile('config', 'config.json');
|
||||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, r.testFile));
|
const service = new ConfigurationService(r.testFile);
|
||||||
let res = service.inspect('lookup.service.testNullSetting');
|
let res = service.inspect('lookup.service.testNullSetting');
|
||||||
assert.strictEqual(res.default, null);
|
assert.strictEqual(res.default, null);
|
||||||
assert.strictEqual(res.value, null);
|
assert.strictEqual(res.value, null);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
|
|||||||
import { EventType, $, removeNode } from 'vs/base/browser/dom';
|
import { EventType, $, removeNode } from 'vs/base/browser/dom';
|
||||||
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
|
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { domEvent } from 'vs/base/browser/event';
|
import { domEvent } from 'vs/base/browser/event';
|
||||||
|
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
|
||||||
export interface IContextMenuHandlerOptions {
|
export interface IContextMenuHandlerOptions {
|
||||||
blockMouse: boolean;
|
blockMouse: boolean;
|
||||||
@@ -83,6 +84,25 @@ export class ContextMenuHandler {
|
|||||||
menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
||||||
menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
||||||
domEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);
|
domEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);
|
||||||
|
domEvent(window, EventType.MOUSE_DOWN)((e: MouseEvent) => {
|
||||||
|
let event = new StandardMouseEvent(e);
|
||||||
|
let element: HTMLElement | null = event.target;
|
||||||
|
|
||||||
|
// Don't do anything as we are likely creating a context menu
|
||||||
|
if (event.rightButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (element) {
|
||||||
|
if (element === container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.contextViewService.hideContextView(true);
|
||||||
|
}, null, menuDisposables);
|
||||||
|
|
||||||
return combinedDisposable([...menuDisposables, menu]);
|
return combinedDisposable([...menuDisposables, menu]);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ export interface IRemoteDiagnosticInfo extends IDiagnosticInfo {
|
|||||||
hostName: string;
|
hostName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRemoteDiagnosticError {
|
||||||
|
hostName: string;
|
||||||
|
errorMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IDiagnosticInfoOptions {
|
export interface IDiagnosticInfoOptions {
|
||||||
includeProcesses?: boolean;
|
includeProcesses?: boolean;
|
||||||
folders?: UriComponents[];
|
folders?: UriComponents[];
|
||||||
@@ -46,4 +51,8 @@ export interface WorkspaceStats {
|
|||||||
configFiles: WorkspaceStatItem[];
|
configFiles: WorkspaceStatItem[];
|
||||||
fileCount: number;
|
fileCount: number;
|
||||||
maxFilesReached: boolean;
|
maxFilesReached: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError {
|
||||||
|
return !!x.hostName && !!x.errorMessage;
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ import { app } from 'electron';
|
|||||||
import { basename } from 'vs/base/common/path';
|
import { basename } from 'vs/base/common/path';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IMachineInfo, WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { IMachineInfo, WorkspaceStats, SystemInfo, IRemoteDiagnosticInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
|
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||||
import { ProcessItem } from 'vs/base/common/processes';
|
import { ProcessItem } from 'vs/base/common/processes';
|
||||||
|
|
||||||
@@ -92,23 +92,28 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
try {
|
try {
|
||||||
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||||
remoteData.forEach(diagnostics => {
|
remoteData.forEach(diagnostics => {
|
||||||
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
|
if (isRemoteDiagnosticError(diagnostics)) {
|
||||||
if (diagnostics.processes) {
|
processInfo += `\n${diagnostics.errorMessage}`;
|
||||||
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
|
workspaceInfo += `\n${diagnostics.errorMessage}`;
|
||||||
}
|
} else {
|
||||||
|
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
|
||||||
|
if (diagnostics.processes) {
|
||||||
|
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (diagnostics.workspaceMetadata) {
|
if (diagnostics.workspaceMetadata) {
|
||||||
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
|
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
|
||||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||||
const metadata = diagnostics.workspaceMetadata[folder];
|
const metadata = diagnostics.workspaceMetadata[folder];
|
||||||
|
|
||||||
let countMessage = `${metadata.fileCount} files`;
|
let countMessage = `${metadata.fileCount} files`;
|
||||||
if (metadata.maxFilesReached) {
|
if (metadata.maxFilesReached) {
|
||||||
countMessage = `more than ${countMessage}`;
|
countMessage = `more than ${countMessage}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
|
||||||
|
workspaceInfo += this.formatWorkspaceStats(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
|
|
||||||
workspaceInfo += this.formatWorkspaceStats(metadata);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -135,7 +140,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
processArgs: `${info.mainArguments.join(' ')}`,
|
processArgs: `${info.mainArguments.join(' ')}`,
|
||||||
gpuStatus: app.getGPUFeatureStatus(),
|
gpuStatus: app.getGPUFeatureStatus(),
|
||||||
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
|
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
|
||||||
remoteData: await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })
|
remoteData: (await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })).filter((x): x is IRemoteDiagnosticInfo => !(x instanceof Error))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -169,25 +174,29 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
try {
|
try {
|
||||||
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||||
data.forEach(diagnostics => {
|
data.forEach(diagnostics => {
|
||||||
output.push('\n\n');
|
if (isRemoteDiagnosticError(diagnostics)) {
|
||||||
output.push(`Remote: ${diagnostics.hostName}`);
|
output.push(`\n${diagnostics.errorMessage}`);
|
||||||
output.push(this.formatMachineInfo(diagnostics.machineInfo));
|
} else {
|
||||||
|
output.push('\n\n');
|
||||||
|
output.push(`Remote: ${diagnostics.hostName}`);
|
||||||
|
output.push(this.formatMachineInfo(diagnostics.machineInfo));
|
||||||
|
|
||||||
if (diagnostics.processes) {
|
if (diagnostics.processes) {
|
||||||
output.push(this.formatProcessList(info, diagnostics.processes));
|
output.push(this.formatProcessList(info, diagnostics.processes));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diagnostics.workspaceMetadata) {
|
if (diagnostics.workspaceMetadata) {
|
||||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||||
const metadata = diagnostics.workspaceMetadata[folder];
|
const metadata = diagnostics.workspaceMetadata[folder];
|
||||||
|
|
||||||
let countMessage = `${metadata.fileCount} files`;
|
let countMessage = `${metadata.fileCount} files`;
|
||||||
if (metadata.maxFilesReached) {
|
if (metadata.maxFilesReached) {
|
||||||
countMessage = `more than ${countMessage}`;
|
countMessage = `more than ${countMessage}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push(`Folder (${folder}): ${countMessage}`);
|
||||||
|
output.push(this.formatWorkspaceStats(metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push(`Folder (${folder}): ${countMessage}`);
|
|
||||||
output.push(this.formatWorkspaceStats(metadata));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -306,13 +315,13 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
output.push('CPU %\tMem MB\t PID\tProcess');
|
output.push('CPU %\tMem MB\t PID\tProcess');
|
||||||
|
|
||||||
if (rootProcess) {
|
if (rootProcess) {
|
||||||
this.formatProcessItem(mapPidToWindowTitle, output, rootProcess, 0);
|
this.formatProcessItem(info.mainPID, mapPidToWindowTitle, output, rootProcess, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join('\n');
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatProcessItem(mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
|
private formatProcessItem(mainPid: number, mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
|
||||||
const isRoot = (indent === 0);
|
const isRoot = (indent === 0);
|
||||||
|
|
||||||
const MB = 1024 * 1024;
|
const MB = 1024 * 1024;
|
||||||
@@ -320,7 +329,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
// Format name with indent
|
// Format name with indent
|
||||||
let name: string;
|
let name: string;
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
name = `${product.applicationName} main`;
|
name = item.pid === mainPid ? `${product.applicationName} main` : 'remote agent';
|
||||||
} else {
|
} else {
|
||||||
name = `${repeat(' ', indent)} ${item.name}`;
|
name = `${repeat(' ', indent)} ${item.name}`;
|
||||||
|
|
||||||
@@ -333,7 +342,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
|||||||
|
|
||||||
// Recurse into children if any
|
// Recurse into children if any
|
||||||
if (Array.isArray(item.children)) {
|
if (Array.isArray(item.children)) {
|
||||||
item.children.forEach(child => this.formatProcessItem(mapPidToWindowTitle, output, child, indent + 1));
|
item.children.forEach(child => this.formatProcessItem(mainPid, mapPidToWindowTitle, output, child, indent + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,12 +226,12 @@ export async function registerWindowDriver(accessor: ServicesAccessor): Promise<
|
|||||||
const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry');
|
const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry');
|
||||||
const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel);
|
const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel);
|
||||||
|
|
||||||
await windowDriverRegistry.registerWindowDriver(windowService.getCurrentWindowId());
|
await windowDriverRegistry.registerWindowDriver(windowService.windowId);
|
||||||
// const options = await windowDriverRegistry.registerWindowDriver(windowId);
|
// const options = await windowDriverRegistry.registerWindowDriver(windowId);
|
||||||
|
|
||||||
// if (options.verbose) {
|
// if (options.verbose) {
|
||||||
// windowDriver.openDevTools();
|
// windowDriver.openDevTools();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.getCurrentWindowId()));
|
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.windowId));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export interface ParsedArgs {
|
|||||||
'show-versions'?: boolean;
|
'show-versions'?: boolean;
|
||||||
'install-extension'?: string | string[];
|
'install-extension'?: string | string[];
|
||||||
'uninstall-extension'?: string | string[];
|
'uninstall-extension'?: string | string[];
|
||||||
|
'locate-extension'?: string | string[];
|
||||||
'enable-proposed-api'?: string | string[];
|
'enable-proposed-api'?: string | string[];
|
||||||
'open-url'?: boolean;
|
'open-url'?: boolean;
|
||||||
'skip-getting-started'?: boolean;
|
'skip-getting-started'?: boolean;
|
||||||
@@ -109,6 +110,9 @@ export interface IEnvironmentService {
|
|||||||
appSettingsPath: string;
|
appSettingsPath: string;
|
||||||
appKeybindingsPath: string;
|
appKeybindingsPath: string;
|
||||||
|
|
||||||
|
machineSettingsHome: string;
|
||||||
|
machineSettingsPath: string;
|
||||||
|
|
||||||
settingsSearchBuildId?: number;
|
settingsSearchBuildId?: number;
|
||||||
settingsSearchUrl?: string;
|
settingsSearchUrl?: string;
|
||||||
|
|
||||||
@@ -124,7 +128,7 @@ export interface IEnvironmentService {
|
|||||||
disableExtensions: boolean | string[];
|
disableExtensions: boolean | string[];
|
||||||
builtinExtensionsPath: string;
|
builtinExtensionsPath: string;
|
||||||
extensionsPath: string;
|
extensionsPath: string;
|
||||||
extensionDevelopmentLocationURI?: URI | URI[];
|
extensionDevelopmentLocationURI?: URI[];
|
||||||
extensionTestsLocationURI?: URI;
|
extensionTestsLocationURI?: URI;
|
||||||
|
|
||||||
debugExtensionHost: IExtensionHostDebugParams;
|
debugExtensionHost: IExtensionHostDebugParams;
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export const options: Option[] = [
|
|||||||
{ id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") },
|
{ id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") },
|
||||||
|
|
||||||
{ id: 'remote', type: 'string' },
|
{ id: 'remote', type: 'string' },
|
||||||
|
{ id: 'locate-extension', type: 'string' },
|
||||||
{ id: 'extensionDevelopmentPath', type: 'string' },
|
{ id: 'extensionDevelopmentPath', type: 'string' },
|
||||||
{ id: 'extensionTestsPath', type: 'string' },
|
{ id: 'extensionTestsPath', type: 'string' },
|
||||||
{ id: 'debugId', type: 'string' },
|
{ id: 'debugId', type: 'string' },
|
||||||
|
|||||||
@@ -110,6 +110,12 @@ export class EnvironmentService implements IEnvironmentService {
|
|||||||
@memoize
|
@memoize
|
||||||
get appSettingsPath(): string { return path.join(this.appSettingsHome, 'settings.json'); }
|
get appSettingsPath(): string { return path.join(this.appSettingsHome, 'settings.json'); }
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
get machineSettingsHome(): string { return path.join(this.userDataPath, 'Machine'); }
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
get machineSettingsPath(): string { return path.join(this.machineSettingsHome, 'settings.json'); }
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get globalStorageHome(): string { return path.join(this.appSettingsHome, 'globalStorage'); }
|
get globalStorageHome(): string { return path.join(this.appSettingsHome, 'globalStorage'); }
|
||||||
|
|
||||||
@@ -172,7 +178,7 @@ export class EnvironmentService implements IEnvironmentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get extensionDevelopmentLocationURI(): URI | URI[] | undefined {
|
get extensionDevelopmentLocationURI(): URI[] | undefined {
|
||||||
const s = this._args.extensionDevelopmentPath;
|
const s = this._args.extensionDevelopmentPath;
|
||||||
if (Array.isArray(s)) {
|
if (Array.isArray(s)) {
|
||||||
return s.map(p => {
|
return s.map(p => {
|
||||||
@@ -183,9 +189,9 @@ export class EnvironmentService implements IEnvironmentService {
|
|||||||
});
|
});
|
||||||
} else if (s) {
|
} else if (s) {
|
||||||
if (/^[^:/?#]+?:\/\//.test(s)) {
|
if (/^[^:/?#]+?:\/\//.test(s)) {
|
||||||
return URI.parse(s);
|
return [URI.parse(s)];
|
||||||
}
|
}
|
||||||
return URI.file(path.normalize(s));
|
return [URI.file(path.normalize(s))];
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadAllDependencies(extensions: IExtensionIdentifier[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
loadAllDependencies(extensions: IExtensionIdentifier[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
||||||
return this.getDependenciesReccursively(extensions.map(e => e.id), [], token);
|
return this.getDependenciesRecursively(extensions.map(e => e.id), [], token);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise<IGalleryExtensionVersion[]> {
|
getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise<IGalleryExtensionVersion[]> {
|
||||||
@@ -812,7 +812,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDependenciesReccursively(toGet: string[], result: IGalleryExtension[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
private getDependenciesRecursively(toGet: string[], result: IGalleryExtension[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
||||||
if (!toGet || !toGet.length) {
|
if (!toGet || !toGet.length) {
|
||||||
return Promise.resolve(result);
|
return Promise.resolve(result);
|
||||||
}
|
}
|
||||||
@@ -832,7 +832,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid);
|
result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid);
|
||||||
const dependencies: string[] = [];
|
const dependencies: string[] = [];
|
||||||
dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d));
|
dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d));
|
||||||
return this.getDependenciesReccursively(dependencies, result, token);
|
return this.getDependenciesRecursively(dependencies, result, token);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,7 +903,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
if (version) {
|
if (version) {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
return this.getLastValidExtensionVersionReccursively(extension, versions);
|
return this.getLastValidExtensionVersionRecursively(extension, versions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLastValidExtensionVersionFromProperties(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion> | null {
|
private getLastValidExtensionVersionFromProperties(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion> | null {
|
||||||
@@ -936,7 +936,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
.then(manifest => manifest ? manifest.engines.vscode : Promise.reject<string>('Error while reading manifest'));
|
.then(manifest => manifest ? manifest.engines.vscode : Promise.reject<string>('Error while reading manifest'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLastValidExtensionVersionReccursively(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion | null> {
|
private getLastValidExtensionVersionRecursively(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion | null> {
|
||||||
if (!versions.length) {
|
if (!versions.length) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
@@ -945,7 +945,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
return this.getEngine(version)
|
return this.getEngine(version)
|
||||||
.then(engine => {
|
.then(engine => {
|
||||||
if (!isEngineValid(engine)) {
|
if (!isEngineValid(engine)) {
|
||||||
return this.getLastValidExtensionVersionReccursively(extension, versions.slice(1));
|
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
version.properties = version.properties || [];
|
version.properties = version.properties || [];
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { startsWithIgnoreCase } from 'vs/base/common/strings';
|
|||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
|
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
export const IFileService = createDecorator<IFileService>('fileService');
|
export const IFileService = createDecorator<IFileService>('fileService');
|
||||||
|
|
||||||
@@ -123,10 +124,15 @@ export interface IFileService {
|
|||||||
*/
|
*/
|
||||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use writeFile instead
|
||||||
|
*/
|
||||||
|
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the content replacing its previous value.
|
* Updates the content replacing its previous value.
|
||||||
*/
|
*/
|
||||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
|
writeFile(resource: URI, bufferOrReadable: VSBuffer | VSBufferReadable, options?: IWriteFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the file/folder to a new path identified by the resource.
|
* Moves the file/folder to a new path identified by the resource.
|
||||||
@@ -143,12 +149,17 @@ export interface IFileService {
|
|||||||
copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
|
copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new file with the given path. The returned promise
|
* @deprecated use createFile2 instead
|
||||||
|
*/
|
||||||
|
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new file with the given path and optional contents. The returned promise
|
||||||
* will have the stat model object as a result.
|
* will have the stat model object as a result.
|
||||||
*
|
*
|
||||||
* The optional parameter content can be used as value to fill into the new file.
|
* The optional parameter content can be used as value to fill into the new file.
|
||||||
*/
|
*/
|
||||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
createFile2(resource: URI, bufferOrReadable?: VSBuffer | VSBufferReadable, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new folder with the given path. The returned promise
|
* Creates a new folder with the given path. The returned promise
|
||||||
@@ -650,17 +661,6 @@ export interface ITextSnapshot {
|
|||||||
read(): string | null;
|
read(): string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StringSnapshot implements ITextSnapshot {
|
|
||||||
private _value: string | null;
|
|
||||||
constructor(value: string) {
|
|
||||||
this._value = value;
|
|
||||||
}
|
|
||||||
read(): string | null {
|
|
||||||
let ret = this._value;
|
|
||||||
this._value = null;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Helper method to convert a snapshot into its full string form.
|
* Helper method to convert a snapshot into its full string form.
|
||||||
*/
|
*/
|
||||||
@@ -674,6 +674,35 @@ export function snapshotToString(snapshot: ITextSnapshot): string {
|
|||||||
return chunks.join('');
|
return chunks.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TextSnapshotReadable implements VSBufferReadable {
|
||||||
|
private preambleHandled: boolean;
|
||||||
|
|
||||||
|
constructor(private snapshot: ITextSnapshot, private preamble?: string) { }
|
||||||
|
|
||||||
|
read(): VSBuffer | null {
|
||||||
|
let value = this.snapshot.read();
|
||||||
|
|
||||||
|
// Handle preamble if provided
|
||||||
|
if (!this.preambleHandled) {
|
||||||
|
this.preambleHandled = true;
|
||||||
|
|
||||||
|
if (typeof this.preamble === 'string') {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
value = this.preamble + value;
|
||||||
|
} else {
|
||||||
|
value = this.preamble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return VSBuffer.fromString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streamable content and meta information of a file.
|
* Streamable content and meta information of a file.
|
||||||
*/
|
*/
|
||||||
@@ -724,7 +753,20 @@ export interface IResolveContentOptions {
|
|||||||
position?: number;
|
position?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUpdateContentOptions {
|
export interface IWriteFileOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last known modification time of the file. This can be used to prevent dirty writes.
|
||||||
|
*/
|
||||||
|
mtime?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The etag of the file. This can be used to prevent dirty writes.
|
||||||
|
*/
|
||||||
|
etag?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWriteTextFileOptions extends IWriteFileOptions {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The encoding to use when updating a file.
|
* The encoding to use when updating a file.
|
||||||
@@ -746,21 +788,6 @@ export interface IUpdateContentOptions {
|
|||||||
* ask the user to authenticate as super user.
|
* ask the user to authenticate as super user.
|
||||||
*/
|
*/
|
||||||
writeElevated?: boolean;
|
writeElevated?: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* The last known modification time of the file. This can be used to prevent dirty writes.
|
|
||||||
*/
|
|
||||||
mtime?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The etag of the file. This can be used to prevent dirty writes.
|
|
||||||
*/
|
|
||||||
etag?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run mkdirp before saving.
|
|
||||||
*/
|
|
||||||
mkdirp?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IResolveFileOptions {
|
export interface IResolveFileOptions {
|
||||||
@@ -797,7 +824,7 @@ export interface ICreateFileOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FileOperationError extends Error {
|
export class FileOperationError extends Error {
|
||||||
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IResolveContentOptions & IUpdateContentOptions & ICreateFileOptions) {
|
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IResolveContentOptions & IWriteTextFileOptions & ICreateFileOptions) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,7 +1159,7 @@ export interface ILegacyFileService extends IDisposable {
|
|||||||
|
|
||||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||||
|
|
||||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
|
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
|
|
||||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ export class SharedProcessService implements ISharedProcessService {
|
|||||||
@IEnvironmentService environmentService: IEnvironmentService
|
@IEnvironmentService environmentService: IEnvironmentService
|
||||||
) {
|
) {
|
||||||
this.withSharedProcessConnection = windowsService.whenSharedProcessReady()
|
this.withSharedProcessConnection = windowsService.whenSharedProcessReady()
|
||||||
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.getCurrentWindowId()}`));
|
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.windowId}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
getChannel(channelName: string): IChannel {
|
getChannel(channelName: string): IChannel {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
|
|||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
|
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
|
||||||
|
import { listProcesses } from 'vs/base/node/ps';
|
||||||
|
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
|
|
||||||
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
|
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
|
||||||
|
|
||||||
@@ -44,6 +46,35 @@ export class IssueService implements IIssueService {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on('vscode:listProcesses', async (event: Event) => {
|
||||||
|
const processes = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const mainPid = await this.launchService.getMainProcessId();
|
||||||
|
processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(mainPid) });
|
||||||
|
(await this.launchService.getRemoteDiagnostics({ includeProcesses: true }))
|
||||||
|
.forEach(data => {
|
||||||
|
if (isRemoteDiagnosticError(data)) {
|
||||||
|
processes.push({
|
||||||
|
name: data.hostName,
|
||||||
|
rootProcess: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (data.processes) {
|
||||||
|
processes.push({
|
||||||
|
name: data.hostName,
|
||||||
|
rootProcess: data.processes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this.logService.error(`Listing processes failed: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.sender.send('vscode:listProcessesResponse', processes);
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on('vscode:issuePerformanceInfoRequest', (event: Event) => {
|
ipcMain.on('vscode:issuePerformanceInfoRequest', (event: Event) => {
|
||||||
this.getPerformanceInfo().then(msg => {
|
this.getPerformanceInfo().then(msg => {
|
||||||
event.sender.send('vscode:issuePerformanceInfoResponse', msg);
|
event.sender.send('vscode:issuePerformanceInfoResponse', msg);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { BrowserWindow, ipcMain, Event as IpcEvent } from 'electron';
|
|||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { hasArgs } from 'vs/platform/environment/node/argv';
|
import { hasArgs } from 'vs/platform/environment/node/argv';
|
||||||
import { coalesce } from 'vs/base/common/arrays';
|
import { coalesce } from 'vs/base/common/arrays';
|
||||||
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
|
|
||||||
export const ID = 'launchService';
|
export const ID = 'launchService';
|
||||||
export const ILaunchService = createDecorator<ILaunchService>(ID);
|
export const ILaunchService = createDecorator<ILaunchService>(ID);
|
||||||
@@ -71,7 +71,7 @@ export interface ILaunchService {
|
|||||||
getMainProcessId(): Promise<number>;
|
getMainProcessId(): Promise<number>;
|
||||||
getMainProcessInfo(): Promise<IMainProcessInfo>;
|
getMainProcessInfo(): Promise<IMainProcessInfo>;
|
||||||
getLogsPath(): Promise<string>;
|
getLogsPath(): Promise<string>;
|
||||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]>;
|
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LaunchChannel implements IServerChannel {
|
export class LaunchChannel implements IServerChannel {
|
||||||
@@ -299,9 +299,9 @@ export class LaunchService implements ILaunchService {
|
|||||||
return Promise.resolve(this.environmentService.logsPath);
|
return Promise.resolve(this.environmentService.logsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
|
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]> {
|
||||||
const windows = this.windowsMainService.getWindows();
|
const windows = this.windowsMainService.getWindows();
|
||||||
const promises: Promise<IDiagnosticInfo | undefined>[] = windows.map(window => {
|
const promises: Promise<IDiagnosticInfo | IRemoteDiagnosticError | undefined>[] = windows.map(window => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (window.remoteAuthority) {
|
if (window.remoteAuthority) {
|
||||||
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
|
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
|
||||||
@@ -315,18 +315,14 @@ export class LaunchService implements ILaunchService {
|
|||||||
ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
|
ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
|
||||||
// No data is returned if getting the connection fails.
|
// No data is returned if getting the connection fails.
|
||||||
if (!data) {
|
if (!data) {
|
||||||
resolve();
|
resolve({ hostName: window.remoteAuthority!, errorMessage: `Unable to resolve connection to '${window.remoteAuthority}'.` });
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof (data) === 'string') {
|
|
||||||
reject(new Error(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(data);
|
resolve(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve();
|
resolve({ hostName: window.remoteAuthority!, errorMessage: `Fetching remote diagnostics for '${window.remoteAuthority}' timed out.` });
|
||||||
}, 5000);
|
}, 5000);
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
@@ -334,7 +330,7 @@ export class LaunchService implements ILaunchService {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo => !!x));
|
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo | IRemoteDiagnosticError => !!x));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFolderURIs(window: ICodeWindow): URI[] {
|
private getFolderURIs(window: ICodeWindow): URI[] {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class LifecycleService extends AbstractLifecycleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private registerListeners(): void {
|
private registerListeners(): void {
|
||||||
const windowId = this.windowService.getCurrentWindowId();
|
const windowId = this.windowService.windowId;
|
||||||
|
|
||||||
// Main side indicates that window is about to unload, check for vetos
|
// Main side indicates that window is about to unload, check for vetos
|
||||||
ipc.on('vscode:onBeforeUnload', (_event: unknown, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => {
|
ipc.on('vscode:onBeforeUnload', (_event: unknown, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTr
|
|||||||
import { ITreeEvent, ITreeRenderer, IAsyncDataSource, IDataSource, ITreeMouseEvent } from 'vs/base/browser/ui/tree/tree';
|
import { ITreeEvent, ITreeRenderer, IAsyncDataSource, IDataSource, ITreeMouseEvent } from 'vs/base/browser/ui/tree/tree';
|
||||||
import { AsyncDataTree, IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree';
|
import { AsyncDataTree, IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||||
import { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree';
|
import { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree';
|
||||||
import { IKeyboardNavigationEventFilter } from 'vs/base/browser/ui/tree/abstractTree';
|
import { IKeyboardNavigationEventFilter, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
|
||||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||||
|
|
||||||
export type ListWidget = List<any> | PagedList<any> | ITree | ObjectTree<any, any> | DataTree<any, any, any> | AsyncDataTree<any, any, any>;
|
export type ListWidget = List<any> | PagedList<any> | ITree | ObjectTree<any, any> | DataTree<any, any, any> | AsyncDataTree<any, any, any>;
|
||||||
@@ -659,8 +659,9 @@ export interface IOpenEvent<T> {
|
|||||||
browserEvent?: UIEvent;
|
browserEvent?: UIEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IResourceResultsNavigationOptions {
|
export interface IResourceResultsNavigationOptions2 {
|
||||||
openOnFocus: boolean;
|
openOnFocus?: boolean;
|
||||||
|
openOnSelection?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectionKeyboardEvent extends KeyboardEvent {
|
export interface SelectionKeyboardEvent extends KeyboardEvent {
|
||||||
@@ -676,14 +677,24 @@ export function getSelectionKeyboardEvent(typeArg = 'keydown', preserveFocus?: b
|
|||||||
|
|
||||||
export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
|
export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
|
||||||
|
|
||||||
|
private options: IResourceResultsNavigationOptions2;
|
||||||
|
|
||||||
private readonly _onDidOpenResource = new Emitter<IOpenEvent<T | null>>();
|
private readonly _onDidOpenResource = new Emitter<IOpenEvent<T | null>>();
|
||||||
readonly onDidOpenResource: Event<IOpenEvent<T | null>> = this._onDidOpenResource.event;
|
readonly onDidOpenResource: Event<IOpenEvent<T | null>> = this._onDidOpenResource.event;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData>,
|
private tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData>,
|
||||||
private options?: IResourceResultsNavigationOptions
|
options?: IResourceResultsNavigationOptions2
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.options = {
|
||||||
|
...<IResourceResultsNavigationOptions2>{
|
||||||
|
openOnSelection: true
|
||||||
|
},
|
||||||
|
...(options || {})
|
||||||
|
};
|
||||||
|
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +703,10 @@ export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
|
|||||||
this._register(this.tree.onDidChangeFocus(e => this.onFocus(e)));
|
this._register(this.tree.onDidChangeFocus(e => this.onFocus(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
|
if (this.options && this.options.openOnSelection) {
|
||||||
|
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
|
||||||
|
}
|
||||||
|
|
||||||
this._register(this.tree.onDidOpen(e => this.onSelection(e)));
|
this._register(this.tree.onDidOpen(e => this.onSelection(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,15 +780,9 @@ function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingS
|
|||||||
|
|
||||||
export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> {
|
export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> {
|
||||||
|
|
||||||
readonly contextKeyService: IContextKeyService;
|
private internals: WorkbenchTreeInternals<any, T, TFilterData>;
|
||||||
|
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||||
protected disposables: IDisposable[];
|
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||||
|
|
||||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
|
||||||
private hasDoubleSelection: IContextKey<boolean>;
|
|
||||||
private hasMultiSelection: IContextKey<boolean>;
|
|
||||||
|
|
||||||
private _useAltAsMultipleSelectionModifier: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
@@ -788,132 +796,19 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||||
|
super(container, delegate, renderers, treeOptions);
|
||||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
this.disposables.push(disposable);
|
||||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
this.disposables.push(this.internals);
|
||||||
}
|
|
||||||
|
|
||||||
const getAutomaticKeyboardNavigation = () => {
|
|
||||||
// give priority to the context key value to disable this completely
|
|
||||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
|
||||||
|
|
||||||
if (automaticKeyboardNavigation) {
|
|
||||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return automaticKeyboardNavigation;
|
|
||||||
};
|
|
||||||
|
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
|
||||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
|
||||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
|
||||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
|
||||||
|
|
||||||
super(container, delegate, renderers, {
|
|
||||||
keyboardSupport: false,
|
|
||||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
|
||||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
|
||||||
...workbenchListOptions,
|
|
||||||
indent: configurationService.getValue(treeIndentKey),
|
|
||||||
automaticKeyboardNavigation: getAutomaticKeyboardNavigation(),
|
|
||||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
|
||||||
filterOnType: keyboardNavigation === 'filter',
|
|
||||||
horizontalScrolling,
|
|
||||||
openOnSingleClick,
|
|
||||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
|
||||||
});
|
|
||||||
|
|
||||||
this.disposables.push(workbenchListOptionsDisposable);
|
|
||||||
|
|
||||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
|
||||||
|
|
||||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
|
||||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);
|
|
||||||
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
|
|
||||||
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
|
|
||||||
|
|
||||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
|
||||||
|
|
||||||
const interestingContextKeys = new Set();
|
|
||||||
interestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationKey);
|
|
||||||
const updateKeyboardNavigation = () => {
|
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
|
||||||
this.updateOptions({
|
|
||||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
|
||||||
filterOnType: keyboardNavigation === 'filter'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.disposables.push(
|
|
||||||
this.contextKeyService,
|
|
||||||
(listService as ListService).register(this),
|
|
||||||
attachListStyler(this, themeService),
|
|
||||||
this.onDidChangeSelection(() => {
|
|
||||||
const selection = this.getSelection();
|
|
||||||
const focus = this.getFocus();
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
|
||||||
this.hasMultiSelection.set(selection.length > 1);
|
|
||||||
this.hasDoubleSelection.set(selection.length === 2);
|
|
||||||
}),
|
|
||||||
this.onDidChangeFocus(() => {
|
|
||||||
const selection = this.getSelection();
|
|
||||||
const focus = this.getFocus();
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
|
||||||
}),
|
|
||||||
configurationService.onDidChangeConfiguration(e => {
|
|
||||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
|
||||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
|
||||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(treeIndentKey)) {
|
|
||||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
|
||||||
this.updateOptions({ indent });
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
|
||||||
updateKeyboardNavigation();
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
this.contextKeyService.onDidChangeContext(e => {
|
|
||||||
if (e.affectsSome(interestingContextKeys)) {
|
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get useAltAsMultipleSelectionModifier(): boolean {
|
|
||||||
return this._useAltAsMultipleSelectionModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(): void {
|
|
||||||
super.dispose();
|
|
||||||
this.disposables = dispose(this.disposables);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<TInput, T, TFilterData> {
|
export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<TInput, T, TFilterData> {
|
||||||
|
|
||||||
readonly contextKeyService: IContextKeyService;
|
private internals: WorkbenchTreeInternals<TInput, T, TFilterData>;
|
||||||
|
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||||
private hasDoubleSelection: IContextKey<boolean>;
|
|
||||||
private hasMultiSelection: IContextKey<boolean>;
|
|
||||||
|
|
||||||
private _useAltAsMultipleSelectionModifier: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
@@ -928,127 +823,19 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||||
|
super(container, delegate, renderers, dataSource, treeOptions);
|
||||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
this.disposables.push(disposable);
|
||||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
this.disposables.push(this.internals);
|
||||||
}
|
|
||||||
|
|
||||||
const getAutomaticKeyboardNavigation = () => {
|
|
||||||
// give priority to the context key value to disable this completely
|
|
||||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
|
||||||
|
|
||||||
if (automaticKeyboardNavigation) {
|
|
||||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return automaticKeyboardNavigation;
|
|
||||||
};
|
|
||||||
|
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
|
||||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
|
||||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
|
||||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
|
||||||
|
|
||||||
super(container, delegate, renderers, dataSource, {
|
|
||||||
keyboardSupport: false,
|
|
||||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
|
||||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
|
||||||
...workbenchListOptions,
|
|
||||||
indent: configurationService.getValue(treeIndentKey),
|
|
||||||
automaticKeyboardNavigation: getAutomaticKeyboardNavigation(),
|
|
||||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
|
||||||
filterOnType: keyboardNavigation === 'filter',
|
|
||||||
horizontalScrolling,
|
|
||||||
openOnSingleClick,
|
|
||||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
|
||||||
});
|
|
||||||
|
|
||||||
this.disposables.push(workbenchListOptionsDisposable);
|
|
||||||
|
|
||||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
|
||||||
|
|
||||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
|
||||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);
|
|
||||||
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
|
|
||||||
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
|
|
||||||
|
|
||||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
|
||||||
|
|
||||||
const interestingContextKeys = new Set();
|
|
||||||
interestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationKey);
|
|
||||||
const updateKeyboardNavigation = () => {
|
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
|
||||||
this.updateOptions({
|
|
||||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
|
||||||
filterOnType: keyboardNavigation === 'filter'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.disposables.push(
|
|
||||||
this.contextKeyService,
|
|
||||||
(listService as ListService).register(this),
|
|
||||||
attachListStyler(this, themeService),
|
|
||||||
this.onDidChangeSelection(() => {
|
|
||||||
const selection = this.getSelection();
|
|
||||||
const focus = this.getFocus();
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
|
||||||
this.hasMultiSelection.set(selection.length > 1);
|
|
||||||
this.hasDoubleSelection.set(selection.length === 2);
|
|
||||||
}),
|
|
||||||
this.onDidChangeFocus(() => {
|
|
||||||
const selection = this.getSelection();
|
|
||||||
const focus = this.getFocus();
|
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
|
||||||
}),
|
|
||||||
configurationService.onDidChangeConfiguration(e => {
|
|
||||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
|
||||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
|
||||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(treeIndentKey)) {
|
|
||||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
|
||||||
this.updateOptions({ indent });
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
|
||||||
updateKeyboardNavigation();
|
|
||||||
}
|
|
||||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
this.contextKeyService.onDidChangeContext(e => {
|
|
||||||
if (e.affectsSome(interestingContextKeys)) {
|
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get useAltAsMultipleSelectionModifier(): boolean {
|
|
||||||
return this._useAltAsMultipleSelectionModifier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends AsyncDataTree<TInput, T, TFilterData> {
|
export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends AsyncDataTree<TInput, T, TFilterData> {
|
||||||
|
|
||||||
readonly contextKeyService: IContextKeyService;
|
private internals: WorkbenchTreeInternals<TInput, T, TFilterData>;
|
||||||
|
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||||
private hasDoubleSelection: IContextKey<boolean>;
|
|
||||||
private hasMultiSelection: IContextKey<boolean>;
|
|
||||||
|
|
||||||
private _useAltAsMultipleSelectionModifier: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
@@ -1063,31 +850,51 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||||
|
super(container, delegate, renderers, dataSource, treeOptions);
|
||||||
|
this.disposables.push(disposable);
|
||||||
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
|
this.disposables.push(this.internals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
function workbenchTreeDataPreamble<T, TFilterData>(
|
||||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
container: HTMLElement,
|
||||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
options: IAbstractTreeOptions<T, TFilterData>,
|
||||||
|
contextKeyService: IContextKeyService,
|
||||||
|
themeService: IThemeService,
|
||||||
|
configurationService: IConfigurationService,
|
||||||
|
keybindingService: IKeybindingService,
|
||||||
|
accessibilityService: IAccessibilityService,
|
||||||
|
): { options: IAbstractTreeOptions<T, TFilterData>, getAutomaticKeyboardNavigation: () => boolean | undefined, disposable: IDisposable } {
|
||||||
|
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
||||||
|
|
||||||
|
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
||||||
|
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
||||||
|
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAutomaticKeyboardNavigation = () => {
|
||||||
|
// give priority to the context key value to disable this completely
|
||||||
|
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||||
|
|
||||||
|
if (automaticKeyboardNavigation) {
|
||||||
|
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAutomaticKeyboardNavigation = () => {
|
return automaticKeyboardNavigation;
|
||||||
// give priority to the context key value to disable this completely
|
};
|
||||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
|
||||||
|
|
||||||
if (automaticKeyboardNavigation) {
|
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||||
}
|
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
||||||
|
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
||||||
|
const [workbenchListOptions, disposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
||||||
|
|
||||||
return automaticKeyboardNavigation;
|
return {
|
||||||
};
|
getAutomaticKeyboardNavigation,
|
||||||
|
disposable,
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
options: {
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
|
||||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
|
||||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
|
||||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
|
||||||
|
|
||||||
super(container, delegate, renderers, dataSource, {
|
|
||||||
keyboardSupport: false,
|
keyboardSupport: false,
|
||||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
||||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
...computeStyles(themeService.getTheme(), defaultListStyles),
|
||||||
@@ -1099,11 +906,30 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
horizontalScrolling,
|
horizontalScrolling,
|
||||||
openOnSingleClick,
|
openOnSingleClick,
|
||||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.disposables.push(workbenchListOptionsDisposable);
|
class WorkbenchTreeInternals<TInput, T, TFilterData> {
|
||||||
|
|
||||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
readonly contextKeyService: IContextKeyService;
|
||||||
|
private hasSelectionOrFocus: IContextKey<boolean>;
|
||||||
|
private hasDoubleSelection: IContextKey<boolean>;
|
||||||
|
private hasMultiSelection: IContextKey<boolean>;
|
||||||
|
private _useAltAsMultipleSelectionModifier: boolean;
|
||||||
|
private disposables: IDisposable[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchDataTree<TInput, T, TFilterData> | WorkbenchAsyncDataTree<TInput, T, TFilterData>,
|
||||||
|
options: IAbstractTreeOptions<T, TFilterData>,
|
||||||
|
getAutomaticKeyboardNavigation: () => boolean | undefined,
|
||||||
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
|
@IListService listService: IListService,
|
||||||
|
@IThemeService themeService: IThemeService,
|
||||||
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
|
@IAccessibilityService accessibilityService: IAccessibilityService,
|
||||||
|
) {
|
||||||
|
this.contextKeyService = createScopedContextKeyService(contextKeyService, tree);
|
||||||
|
|
||||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||||
@@ -1119,7 +945,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
const updateKeyboardNavigation = () => {
|
const updateKeyboardNavigation = () => {
|
||||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||||
this.updateOptions({
|
tree.updateOptions({
|
||||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||||
filterOnType: keyboardNavigation === 'filter'
|
filterOnType: keyboardNavigation === 'filter'
|
||||||
});
|
});
|
||||||
@@ -1127,43 +953,43 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
|
|
||||||
this.disposables.push(
|
this.disposables.push(
|
||||||
this.contextKeyService,
|
this.contextKeyService,
|
||||||
(listService as ListService).register(this),
|
(listService as ListService).register(tree),
|
||||||
attachListStyler(this, themeService),
|
attachListStyler(tree, themeService),
|
||||||
this.onDidChangeSelection(() => {
|
tree.onDidChangeSelection(() => {
|
||||||
const selection = this.getSelection();
|
const selection = tree.getSelection();
|
||||||
const focus = this.getFocus();
|
const focus = tree.getFocus();
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||||
this.hasMultiSelection.set(selection.length > 1);
|
this.hasMultiSelection.set(selection.length > 1);
|
||||||
this.hasDoubleSelection.set(selection.length === 2);
|
this.hasDoubleSelection.set(selection.length === 2);
|
||||||
}),
|
}),
|
||||||
this.onDidChangeFocus(() => {
|
tree.onDidChangeFocus(() => {
|
||||||
const selection = this.getSelection();
|
const selection = tree.getSelection();
|
||||||
const focus = this.getFocus();
|
const focus = tree.getFocus();
|
||||||
|
|
||||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||||
}),
|
}),
|
||||||
configurationService.onDidChangeConfiguration(e => {
|
configurationService.onDidChangeConfiguration(e => {
|
||||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
if (e.affectsConfiguration(openModeSettingKey)) {
|
||||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
tree.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
||||||
}
|
}
|
||||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||||
}
|
}
|
||||||
if (e.affectsConfiguration(treeIndentKey)) {
|
if (e.affectsConfiguration(treeIndentKey)) {
|
||||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
const indent = configurationService.getValue<number>(treeIndentKey);
|
||||||
this.updateOptions({ indent });
|
tree.updateOptions({ indent });
|
||||||
}
|
}
|
||||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
||||||
updateKeyboardNavigation();
|
updateKeyboardNavigation();
|
||||||
}
|
}
|
||||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
tree.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.contextKeyService.onDidChangeContext(e => {
|
this.contextKeyService.onDidChangeContext(e => {
|
||||||
if (e.affectsSome(interestingContextKeys)) {
|
if (e.affectsSome(interestingContextKeys)) {
|
||||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
tree.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
||||||
@@ -1173,6 +999,10 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
get useAltAsMultipleSelectionModifier(): boolean {
|
get useAltAsMultipleSelectionModifier(): boolean {
|
||||||
return this._useAltAsMultipleSelectionModifier;
|
return this._useAltAsMultipleSelectionModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
this.disposables = dispose(this.disposables);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export interface IRemoteAgentEnvironment {
|
|||||||
pid: number;
|
pid: number;
|
||||||
appRoot: URI;
|
appRoot: URI;
|
||||||
appSettingsHome: URI;
|
appSettingsHome: URI;
|
||||||
appSettingsPath: URI;
|
settingsPath: URI;
|
||||||
logsPath: URI;
|
logsPath: URI;
|
||||||
extensionsPath: URI;
|
extensionsPath: URI;
|
||||||
extensionHostLogsPath: URI;
|
extensionHostLogsPath: URI;
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
export const REMOTE_HOST_SCHEME = 'vscode-remote';
|
export const REMOTE_HOST_SCHEME = Schemas.vscodeRemote;
|
||||||
|
|
||||||
export function getRemoteAuthority(uri: URI): string | undefined {
|
export function getRemoteAuthority(uri: URI): string | undefined {
|
||||||
return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined;
|
return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined;
|
||||||
|
|||||||
21
src/vs/platform/remote/common/tunnel.ts
Normal file
21
src/vs/platform/remote/common/tunnel.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
|
export const ITunnelService = createDecorator<ITunnelService>('tunnelService');
|
||||||
|
|
||||||
|
export interface RemoteTunnel {
|
||||||
|
readonly tunnelRemotePort: number;
|
||||||
|
readonly tunnelLocalPort: number;
|
||||||
|
|
||||||
|
dispose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITunnelService {
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
openTunnel(remotePort: number): Promise<RemoteTunnel> | undefined;
|
||||||
|
}
|
||||||
@@ -3,10 +3,42 @@
|
|||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as net from 'net';
|
||||||
|
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||||
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
|
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||||
|
|
||||||
export const nodeWebSocketFactory = new class implements IWebSocketFactory {
|
export const nodeWebSocketFactory = new class implements IWebSocketFactory {
|
||||||
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
|
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
|
||||||
throw new Error(`Not implemented`);
|
const errorListener = (err: any) => callback(err, undefined);
|
||||||
|
|
||||||
|
const socket = net.createConnection({ host: host, port: port }, () => {
|
||||||
|
socket.removeListener('error', errorListener);
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc6455#section-4
|
||||||
|
const buffer = Buffer.alloc(16);
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
buffer[i] = Math.round(Math.random() * 256);
|
||||||
|
}
|
||||||
|
const nonce = buffer.toString('base64');
|
||||||
|
|
||||||
|
let headers = [
|
||||||
|
`GET ws://${host}:${port}/?${query}&skipWebSocketFrames=true HTTP/1.1`,
|
||||||
|
`Connection: Upgrade`,
|
||||||
|
`Upgrade: websocket`,
|
||||||
|
`Sec-WebSocket-Key: ${nonce}`
|
||||||
|
];
|
||||||
|
socket.write(headers.join('\r\n') + '\r\n\r\n');
|
||||||
|
|
||||||
|
const onData = (data: Buffer) => {
|
||||||
|
const strData = data.toString();
|
||||||
|
if (strData.indexOf('\r\n\r\n') >= 0) {
|
||||||
|
// headers received OK
|
||||||
|
socket.off('data', onData);
|
||||||
|
callback(undefined, new NodeSocket(socket));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
socket.on('data', onData);
|
||||||
|
});
|
||||||
|
socket.once('error', errorListener);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
21
src/vs/platform/remote/node/tunnelService.ts
Normal file
21
src/vs/platform/remote/node/tunnelService.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||||
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
|
|
||||||
|
export class TunnelService implements ITunnelService {
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
openTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSingleton(ITunnelService, TunnelService);
|
||||||
@@ -67,13 +67,21 @@ export interface IStatusbarService {
|
|||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an entry to the statusbar with the given alignment and priority. Use the returned IDisposable
|
* Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor
|
||||||
* to remove the statusbar entry.
|
* to update or remove the statusbar entry.
|
||||||
*/
|
*/
|
||||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority?: number): IDisposable;
|
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints something to the status bar area with optional auto dispose and delay.
|
* Prints something to the status bar area with optional auto dispose and delay.
|
||||||
*/
|
*/
|
||||||
setStatusMessage(message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable;
|
setStatusMessage(message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IStatusbarEntryAccessor extends IDisposable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to update an existing status bar entry.
|
||||||
|
*/
|
||||||
|
update(properties: IStatusbarEntry): void;
|
||||||
}
|
}
|
||||||
@@ -226,8 +226,8 @@ export interface IWindowService {
|
|||||||
|
|
||||||
readonly hasFocus: boolean;
|
readonly hasFocus: boolean;
|
||||||
|
|
||||||
getConfiguration(): IWindowConfiguration;
|
readonly windowId: number;
|
||||||
getCurrentWindowId(): number;
|
|
||||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||||
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||||
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||||
@@ -459,7 +459,7 @@ export class ActiveWindowManager implements IDisposable {
|
|||||||
|
|
||||||
this.firstActiveWindowIdPromise = createCancelablePromise(_ => windowsService.getActiveWindowId());
|
this.firstActiveWindowIdPromise = createCancelablePromise(_ => windowsService.getActiveWindowId());
|
||||||
this.firstActiveWindowIdPromise
|
this.firstActiveWindowIdPromise
|
||||||
.then(id => this.activeWindowId = id)
|
.then(id => this.activeWindowId = typeof this.activeWindowId === 'number' ? this.activeWindowId : id)
|
||||||
.finally(this.firstActiveWindowIdPromise = undefined);
|
.finally(this.firstActiveWindowIdPromise = undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/vs/vscode.proposed.d.ts
vendored
16
src/vs/vscode.proposed.d.ts
vendored
@@ -812,28 +812,28 @@ declare module 'vscode' {
|
|||||||
/**
|
/**
|
||||||
* The id of the comment
|
* The id of the comment
|
||||||
*/
|
*/
|
||||||
commentId: string;
|
readonly commentId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text of the comment
|
* The text of the comment
|
||||||
*/
|
*/
|
||||||
body: MarkdownString;
|
readonly body: MarkdownString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional label describing the [Comment](#Comment)
|
* Optional label describing the [Comment](#Comment)
|
||||||
* Label will be rendered next to userName if exists.
|
* Label will be rendered next to userName if exists.
|
||||||
*/
|
*/
|
||||||
label?: string;
|
readonly label?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The display name of the user who created the comment
|
* The display name of the user who created the comment
|
||||||
*/
|
*/
|
||||||
userName: string;
|
readonly userName: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The icon path for the user who created the comment
|
* The icon path for the user who created the comment
|
||||||
*/
|
*/
|
||||||
userIconPath?: Uri;
|
readonly userIconPath?: Uri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use userIconPath instead. The avatar src of the user who created the comment
|
* @deprecated Use userIconPath instead. The avatar src of the user who created the comment
|
||||||
@@ -869,17 +869,17 @@ declare module 'vscode' {
|
|||||||
/**
|
/**
|
||||||
* The command to be executed if the comment is selected in the Comments Panel
|
* The command to be executed if the comment is selected in the Comments Panel
|
||||||
*/
|
*/
|
||||||
selectCommand?: Command;
|
readonly selectCommand?: Command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command to be executed when users try to save the edits to the comment
|
* The command to be executed when users try to save the edits to the comment
|
||||||
*/
|
*/
|
||||||
editCommand?: Command;
|
readonly editCommand?: Command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command to be executed when users try to delete the comment
|
* The command to be executed when users try to delete the comment
|
||||||
*/
|
*/
|
||||||
deleteCommand?: Command;
|
readonly deleteCommand?: Command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deprecated
|
* Deprecated
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocum
|
|||||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||||
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { toLocalResource } from 'vs/base/common/resources';
|
||||||
|
|
||||||
export class BoundModelReferenceCollection {
|
export class BoundModelReferenceCollection {
|
||||||
|
|
||||||
@@ -69,6 +71,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
|||||||
private readonly _textFileService: ITextFileService;
|
private readonly _textFileService: ITextFileService;
|
||||||
private readonly _fileService: IFileService;
|
private readonly _fileService: IFileService;
|
||||||
private readonly _untitledEditorService: IUntitledEditorService;
|
private readonly _untitledEditorService: IUntitledEditorService;
|
||||||
|
private readonly _environmentService: IWorkbenchEnvironmentService;
|
||||||
|
|
||||||
private _toDispose: IDisposable[];
|
private _toDispose: IDisposable[];
|
||||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||||
@@ -85,12 +88,14 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
|||||||
@IFileService fileService: IFileService,
|
@IFileService fileService: IFileService,
|
||||||
@ITextModelService textModelResolverService: ITextModelService,
|
@ITextModelService textModelResolverService: ITextModelService,
|
||||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||||
|
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||||
) {
|
) {
|
||||||
this._modelService = modelService;
|
this._modelService = modelService;
|
||||||
this._textModelResolverService = textModelResolverService;
|
this._textModelResolverService = textModelResolverService;
|
||||||
this._textFileService = textFileService;
|
this._textFileService = textFileService;
|
||||||
this._fileService = fileService;
|
this._fileService = fileService;
|
||||||
this._untitledEditorService = untitledEditorService;
|
this._untitledEditorService = untitledEditorService;
|
||||||
|
this._environmentService = environmentService;
|
||||||
|
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||||
this._modelIsSynced = {};
|
this._modelIsSynced = {};
|
||||||
@@ -214,10 +219,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleUntitledScheme(uri: URI): Promise<boolean> {
|
private _handleUntitledScheme(uri: URI): Promise<boolean> {
|
||||||
const asFileUri = uri.with({ scheme: Schemas.file });
|
const asLocalUri = toLocalResource(uri, this._environmentService.configuration.remoteAuthority);
|
||||||
return this._fileService.resolve(asFileUri).then(stats => {
|
return this._fileService.resolve(asLocalUri).then(stats => {
|
||||||
// don't create a new file ontop of an existing file
|
// don't create a new file ontop of an existing file
|
||||||
return Promise.reject(new Error('file already exists on disk'));
|
return Promise.reject(new Error('file already exists'));
|
||||||
}, err => {
|
}, err => {
|
||||||
return this._doCreateUntitled(uri).then(resource => !!resource);
|
return this._doCreateUntitled(uri).then(resource => !!resource);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
|||||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
|
||||||
namespace delta {
|
namespace delta {
|
||||||
|
|
||||||
@@ -330,12 +331,12 @@ export class MainThreadDocumentsAndEditors {
|
|||||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||||
@IBulkEditService bulkEditService: IBulkEditService,
|
@IBulkEditService bulkEditService: IBulkEditService,
|
||||||
@IPanelService panelService: IPanelService
|
@IPanelService panelService: IPanelService,
|
||||||
|
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||||
) {
|
) {
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||||
|
|
||||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService);
|
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService);
|
||||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||||
|
|
||||||
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
|
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileSer
|
|||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||||
@@ -105,10 +106,6 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
|||||||
|
|
||||||
// --- forwarding calls
|
// --- forwarding calls
|
||||||
|
|
||||||
private static _asBuffer(data: Uint8Array): Buffer {
|
|
||||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
stat(resource: URI): Promise<IStat> {
|
stat(resource: URI): Promise<IStat> {
|
||||||
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
|
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -116,11 +113,11 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readFile(resource: URI): Promise<Uint8Array> {
|
readFile(resource: URI): Promise<Uint8Array> {
|
||||||
return this._proxy.$readFile(this._handle, resource);
|
return this._proxy.$readFile(this._handle, resource).then(buffer => buffer.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
||||||
return this._proxy.$writeFile(this._handle, resource, RemoteFileSystemProvider._asBuffer(content), opts);
|
return this._proxy.$writeFile(this._handle, resource, VSBuffer.wrap(content), opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||||
@@ -153,12 +150,12 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
|||||||
|
|
||||||
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||||
return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
|
return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
|
||||||
data.set(readData, offset);
|
data.set(readData.buffer, offset);
|
||||||
return readData.byteLength;
|
return readData.byteLength;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||||
return this._proxy.$write(this._handle, fd, pos, Buffer.from(data, offset, length));
|
return this._proxy.$write(this._handle, fd, pos, VSBuffer.wrap(data).slice(offset, offset + length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||||
|
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
) {
|
) {
|
||||||
// Nothing
|
// Nothing
|
||||||
@@ -256,8 +257,9 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
|||||||
|
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
const source = new CancellationTokenSource();
|
const source = new CancellationTokenSource();
|
||||||
|
const editorOrModel = findEditor(model, this._codeEditorService) || model;
|
||||||
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', overrides);
|
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', overrides);
|
||||||
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, model, FormattingMode.Silent, source.token);
|
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, editorOrModel, FormattingMode.Silent, source.token);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
|
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
|
||||||
|
|||||||
@@ -3,47 +3,55 @@
|
|||||||
* 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.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
||||||
export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||||
|
|
||||||
private readonly _entries: { [id: number]: IDisposable };
|
private readonly entries: Map<number, { accessor: IStatusbarEntryAccessor, alignment: MainThreadStatusBarAlignment, priority: number }> = new Map();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
_extHostContext: IExtHostContext,
|
||||||
@IStatusbarService private readonly _statusbarService: IStatusbarService
|
@IStatusbarService private readonly statusbarService: IStatusbarService
|
||||||
) {
|
) { }
|
||||||
this._entries = Object.create(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
for (const key in this._entries) {
|
this.entries.forEach(entry => entry.accessor.dispose());
|
||||||
this._entries[key].dispose();
|
this.entries.clear();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
||||||
|
const entry = { text, tooltip, command, color, extensionId };
|
||||||
|
|
||||||
// Dispose any old
|
// Reset existing entry if alignment or priority changed
|
||||||
this.$dispose(id);
|
let existingEntry = this.entries.get(id);
|
||||||
|
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
|
||||||
|
dispose(existingEntry.accessor);
|
||||||
|
this.entries.delete(id);
|
||||||
|
existingEntry = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Add new
|
// Create new entry if not existing
|
||||||
const entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
|
if (!existingEntry) {
|
||||||
this._entries[id] = entry;
|
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, alignment, priority), alignment, priority });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise update
|
||||||
|
else {
|
||||||
|
existingEntry.accessor.update(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$dispose(id: number) {
|
$dispose(id: number) {
|
||||||
const disposeable = this._entries[id];
|
const entry = this.entries.get(id);
|
||||||
if (disposeable) {
|
if (entry) {
|
||||||
disposeable.dispose();
|
dispose(entry.accessor);
|
||||||
|
this.entries.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this._entries[id];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,22 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape } from '../common/extHost.protocol';
|
||||||
|
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||||
export class MainThreadWindow implements MainThreadWindowShape {
|
export class MainThreadWindow implements MainThreadWindowShape {
|
||||||
|
|
||||||
private readonly proxy: ExtHostWindowShape;
|
private readonly proxy: ExtHostWindowShape;
|
||||||
private disposables: IDisposable[] = [];
|
private disposables: IDisposable[] = [];
|
||||||
|
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
extHostContext: IExtHostContext,
|
||||||
@IWindowService private readonly windowService: IWindowService,
|
@IWindowService private readonly windowService: IWindowService,
|
||||||
@IWindowsService private readonly windowsService: IWindowsService
|
@IWindowsService private readonly windowsService: IWindowsService,
|
||||||
|
@ITunnelService private readonly tunnelService: ITunnelService,
|
||||||
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||||
) {
|
) {
|
||||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow);
|
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow);
|
||||||
|
|
||||||
@@ -29,13 +34,54 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
|||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.disposables = dispose(this.disposables);
|
this.disposables = dispose(this.disposables);
|
||||||
|
|
||||||
|
for (const tunnel of this._tunnels.values()) {
|
||||||
|
tunnel.then(tunnel => tunnel.dispose());
|
||||||
|
}
|
||||||
|
this._tunnels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
$getWindowVisibility(): Promise<boolean> {
|
$getWindowVisibility(): Promise<boolean> {
|
||||||
return this.windowService.isFocused();
|
return this.windowService.isFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
$openUri(uri: UriComponents): Promise<boolean> {
|
async $openUri(uriComponent: UriComponents): Promise<boolean> {
|
||||||
return this.windowsService.openExternal(URI.revive(uri).toString(true));
|
const uri = URI.revive(uriComponent);
|
||||||
|
if (!!this.environmentService.configuration.remoteAuthority) {
|
||||||
|
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||||
|
const port = this.getLocalhostPort(uri);
|
||||||
|
if (typeof port === 'number') {
|
||||||
|
const tunnel = await this.getOrCreateTunnel(port);
|
||||||
|
if (tunnel) {
|
||||||
|
const tunneledUrl = uri.toString().replace(
|
||||||
|
new RegExp(`^${uri.scheme}://localhost:${port}/`),
|
||||||
|
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`);
|
||||||
|
return this.windowsService.openExternal(tunneledUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.windowsService.openExternal(uri.toString(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLocalhostPort(uri: URI): number | undefined {
|
||||||
|
const match = /^localhost:(\d+)$/.exec(uri.authority);
|
||||||
|
if (match) {
|
||||||
|
return +match[1];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||||
|
const existing = this._tunnels.get(remotePort);
|
||||||
|
if (existing) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
const tunnel = this.tunnelService.openTunnel(remotePort);
|
||||||
|
if (tunnel) {
|
||||||
|
this._tunnels.set(remotePort, tunnel);
|
||||||
|
}
|
||||||
|
return tunnel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user