Merge remote-tracking branch 'origin/master' into alex/node-modules-webpack

This commit is contained in:
Alexandru Dima
2020-12-17 14:13:14 +01:00
27 changed files with 405 additions and 286 deletions
+1 -1
View File
@@ -1 +1 @@
2020-12-15T15:34:44.634Z
2020-12-17T07:59:24.060Z
@@ -1,25 +1,4 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
echo -n $VSCODE_QUALITY > .build/quality
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
- script: |
set -e
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -34,9 +13,19 @@ steps:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
- task: DownloadPipelineArtifact@2
inputs:
artifact: Compilation
path: $(Build.ArtifactStagingDirectory)
displayName: Download compilation output
- script: |
set -e
tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
displayName: Extract compilation output
- script: |
set -e
cat << EOF > ~/.netrc
machine github.com
login vscode
@@ -66,6 +55,7 @@ steps:
- script: |
echo -n $(VSCODE_ARCH) > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
@@ -1,25 +1,4 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
echo -n $VSCODE_QUALITY > .build/quality
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
- script: |
set -e
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -34,6 +13,17 @@ steps:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
- task: DownloadPipelineArtifact@2
inputs:
artifact: Compilation
path: $(Build.ArtifactStagingDirectory)
displayName: Download compilation output
- script: |
set -e
tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
displayName: Extract compilation output
- task: Docker@1
displayName: "Pull image"
inputs:
@@ -45,7 +35,6 @@ steps:
- script: |
set -e
cat << EOF > ~/.netrc
machine github.com
login vscode
@@ -69,6 +58,7 @@ steps:
- script: |
echo -n "alpine" > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
@@ -1,25 +1,4 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
echo -n $VSCODE_QUALITY > .build/quality
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
- script: |
set -e
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -34,6 +13,17 @@ steps:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
- task: DownloadPipelineArtifact@2
inputs:
artifact: Compilation
path: $(Build.ArtifactStagingDirectory)
displayName: Download compilation output
- script: |
set -e
tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
displayName: Extract compilation output
- script: |
set -e
cat << EOF > ~/.netrc
@@ -59,6 +49,7 @@ steps:
- script: |
echo -n $(VSCODE_ARCH) > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
@@ -76,12 +67,19 @@ steps:
- script: |
set -e
if [ -z "$CC" ] || [ -z "$CXX" ]
then
export npm_config_arch=$(NPM_ARCH)
if [ -z "$CC" ] || [ -z "$CXX" ]; then
export CC=$(which gcc-5)
export CXX=$(which g++-5)
fi
export npm_config_arch=$(NPM_ARCH)
if [ "$VSCODE_ARCH" == "x64" ]; then
export VSCODE_REMOTE_CC=$(which gcc-4.8)
export VSCODE_REMOTE_CXX=$(which g++-4.8)
export VSCODE_REMOTE_NODE_GYP=$(which node-gyp)
fi
for i in {1..3}; do # try 3 times, for Terrapin
yarn --frozen-lockfile && break
if [ $i -eq 3 ]; then
@@ -103,16 +101,6 @@ steps:
vstsFeed: "npm-vscode"
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- script: |
set -e
export CC=$(which gcc-4.8)
export CXX=$(which g++-4.8)
export npm_config_node_gyp=$(which node-gyp)
cd remote && rm -rf node_modules/
yarn
displayName: Rebuild remote modules with gcc-4.8
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'))
- script: |
set -e
node build/azure-pipelines/mixin
+2 -2
View File
@@ -8,8 +8,8 @@ schedules:
- master
variables:
? ${{ if and(eq(variables['VSCODE_PUBLISH'], ''), or(eq(variables['Build.Reason'], 'IndividualCI'), eq(variables['Build.Reason'], 'BatchedCI'))) }}
: VSCODE_PUBLISH: "false"
${{ if and(eq(variables['VSCODE_PUBLISH'], ''), or(eq(variables['Build.Reason'], 'IndividualCI'), eq(variables['Build.Reason'], 'BatchedCI'))) }}:
VSCODE_PUBLISH: "false"
resources:
containers:
+27 -38
View File
@@ -1,36 +1,17 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
echo -n $VSCODE_QUALITY > .build/quality
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flag
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
dryRun: true
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.x"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: AzureKeyVault@1
displayName: "Azure Key Vault: Get Secrets"
inputs:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -43,22 +24,22 @@ steps:
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
displayName: Prepare tooling
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
git pull --no-rebase https://github.com/$(VSCODE_MIXIN_REPO).git $(node -p "require('./package.json').distro")
displayName: Merge distro
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
npx https://aka.ms/enablesecurefeed standAlone
displayName: Switch to Terrapin packages
timeoutInMinutes: 5
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['ENABLE_TERRAPIN'], 'true'))
condition: and(succeeded(), eq(variables['ENABLE_TERRAPIN'], 'true'))
- script: |
mkdir -p .build
echo -n $(VSCODE_ARCH) > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
@@ -66,15 +47,22 @@ steps:
keyfile: ".build/arch, .build/terrapin, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock"
targetfolder: "**/node_modules, !**/node_modules/**/node_modules"
vstsFeed: "npm-vscode"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
if [ -z "$CC" ] || [ -z "$CXX" ]
then
export npm_config_arch=$(NPM_ARCH)
if [ -z "$CC" ] || [ -z "$CXX" ]; then
export CC=$(which gcc-5)
export CXX=$(which g++-5)
fi
if [ "$VSCODE_ARCH" == "x64" ]; then
export VSCODE_REMOTE_CC=$(which gcc-4.8)
export VSCODE_REMOTE_CXX=$(which g++-4.8)
export VSCODE_REMOTE_NODE_GYP=$(which node-gyp)
fi
for i in {1..3}; do # try 3 times, for Terrapin
yarn --frozen-lockfile && break
if [ $i -eq 3 ]; then
@@ -87,21 +75,20 @@ steps:
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
displayName: Install dependencies
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: ".build/arch, .build/terrapin, build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock"
targetfolder: "**/node_modules, !**/node_modules/**/node_modules"
vstsFeed: "npm-vscode"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
# Mixin must run before optimize, because the CSS loader will inline small SVGs
- script: |
set -e
node build/azure-pipelines/mixin
displayName: Mix in quality
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -111,14 +98,13 @@ steps:
yarn gulp minify-vscode-reh
yarn gulp minify-vscode-reh-web
displayName: Compile
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
node build/azure-pipelines/upload-sourcemaps
displayName: Upload sourcemaps
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['VSCODE_PUBLISH'], 'false'))
condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'))
- script: |
set -e
@@ -126,13 +112,16 @@ steps:
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
node build/azure-pipelines/common/createBuild.js $VERSION
displayName: Create build
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['VSCODE_PUBLISH'], 'false'))
condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
# we gotta tarball everything in order to preserve file permissions
- script: |
set -e
tar -czf $(Build.ArtifactStagingDirectory)/compilation.tar.gz .build out-*
displayName: Compress compilation artifact
- task: PublishPipelineArtifact@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz
artifactName: Compilation
displayName: Publish compilation artifact
+2 -5
View File
@@ -1,9 +1,4 @@
steps:
- script: |
mkdir -p .build
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flag
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -36,7 +31,9 @@ steps:
displayName: Merge distro
- script: |
mkdir -p .build
echo -n $(VSCODE_ARCH) > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
+12 -21
View File
@@ -1,25 +1,4 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
echo -n $VSCODE_QUALITY > .build/quality
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare compilation cache flag
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
- script: |
set -e
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -34,6 +13,17 @@ steps:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
- task: DownloadPipelineArtifact@2
inputs:
artifact: Compilation
path: $(Build.ArtifactStagingDirectory)
displayName: Download compilation output
- script: |
set -e
tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
displayName: Extract compilation output
- script: |
set -e
cat << EOF > ~/.netrc
@@ -59,6 +49,7 @@ steps:
- script: |
echo -n "web" > .build/arch
echo -n $ENABLE_TERRAPIN > .build/terrapin
displayName: Prepare yarn cache flag
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
@@ -1,25 +1,4 @@
steps:
- powershell: |
mkdir .build -ea 0
"$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit
"$env:VSCODE_QUALITY" | Out-File -Encoding ascii -NoNewLine .build\quality
"$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin
displayName: Prepare compilation cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: "build/.cachesalt, .build/commit, .build/quality, .build/terrapin"
targetfolder: ".build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min"
vstsFeed: "npm-vscode"
platformIndependent: true
alias: "Compilation"
- powershell: |
$ErrorActionPreference = "Stop"
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "12.18.3"
@@ -39,6 +18,18 @@ steps:
azureSubscription: "vscode-builds-subscription"
KeyVaultName: vscode
- task: DownloadPipelineArtifact@2
inputs:
artifact: Compilation
path: $(Build.ArtifactStagingDirectory)
displayName: Download compilation output
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { tar --force-local -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz }
displayName: Extract compilation output
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
@@ -62,6 +53,7 @@ steps:
- powershell: |
"$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch
"$env:ENABLE_TERRAPIN" | Out-File -Encoding ascii -NoNewLine .build\terrapin
displayName: Prepare yarn cache flags
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
+8 -1
View File
@@ -34,7 +34,14 @@ function yarnInstall(location, opts) {
yarnInstall('extensions'); // node modules shared by all extensions
if (!(process.platform === 'win32' && (process.arch === 'arm64' || process.env['npm_config_arch'] === 'arm64'))) {
yarnInstall('remote'); // node modules used by vscode server
const env = { ...process.env };
if (process.env['VSCODE_REMOTE_CC']) { env['CC'] = process.env['VSCODE_REMOTE_CC']; }
if (process.env['VSCODE_REMOTE_CXX']) { env['CXX'] = process.env['VSCODE_REMOTE_CXX']; }
if (process.env['VSCODE_REMOTE_NODE_GYP']) { env['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; }
console.log('remote yarn install env', JSON.stringify(env, undefined, ' '));
yarnInstall('remote', { env }); // node modules used by vscode server
yarnInstall('remote/web'); // node modules used by vscode web
}
@@ -6,7 +6,7 @@
import { localize } from 'vs/nls';
import { coalesce } from 'vs/base/common/arrays';
import { IStateService } from 'vs/platform/state/node/state';
import { app, JumpListCategory } from 'electron';
import { app, JumpListCategory, JumpListItem } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { getBaseLabel, getPathLabel, splitName } from 'vs/base/common/labels';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
@@ -350,34 +350,40 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa
this.removeRecentlyOpened(toRemove);
// Add entries
jumpList.push({
type: 'custom',
name: localize('recentFolders', "Recent Workspaces"),
items: coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => {
const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri;
const title = recent.label ? splitName(recent.label).name : this.getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome);
let hasWorkspaces = false;
const items: JumpListItem[] = coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => {
const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri;
const title = recent.label ? splitName(recent.label).name : this.getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome);
let description;
let args;
if (isSingleFolderWorkspaceIdentifier(workspace)) {
description = localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService));
args = `--folder-uri "${workspace.toString()}"`;
} else {
description = localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService));
args = `--file-uri "${workspace.configPath.toString()}"`;
}
let description;
let args;
if (isSingleFolderWorkspaceIdentifier(workspace)) {
description = localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService));
args = `--folder-uri "${workspace.toString()}"`;
} else {
hasWorkspaces = true;
description = localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService));
args = `--file-uri "${workspace.configPath.toString()}"`;
}
return {
type: 'task',
title: title.substr(0, 255), // Windows seems to be picky around the length of entries
description: description.substr(0, 255), // (see https://github.com/microsoft/vscode/issues/111177)
program: process.execPath,
args,
iconPath: 'explorer.exe', // simulate folder icon
iconIndex: 0
};
}))
});
return {
type: 'task',
title: title.substr(0, 255), // Windows seems to be picky around the length of entries
description: description.substr(0, 255), // (see https://github.com/microsoft/vscode/issues/111177)
program: process.execPath,
args,
iconPath: 'explorer.exe', // simulate folder icon
iconIndex: 0
};
}));
if (items.length > 0) {
jumpList.push({
type: 'custom',
name: hasWorkspaces ? localize('recentFoldersAndWorkspaces', "Recent Folders & Workspaces") : localize('recentFolders', "Recent Folders"),
items
});
}
}
// Recent
@@ -16,10 +16,19 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { raceCancellation } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import Severity from 'vs/base/common/severity';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@extHostCustomer
export class MainThreadFileSystemEventService {
static readonly MementoKeyAdditionalEdits = `file.particpants.additionalEdits`;
private readonly _listener = new DisposableStore();
constructor(
@@ -27,7 +36,11 @@ export class MainThreadFileSystemEventService {
@IFileService fileService: IFileService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
@IBulkEditService bulkEditService: IBulkEditService,
@IProgressService progressService: IProgressService
@IProgressService progressService: IProgressService,
@IDialogService dialogService: IDialogService,
@IStorageService storageService: IStorageService,
@ILogService logService: ILogService,
@IEnvironmentService envService: IEnvironmentService
) {
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
@@ -92,9 +105,60 @@ export class MainThreadFileSystemEventService {
return;
}
const edit = reviveWorkspaceEditDto2(data);
await bulkEditService.apply(edit, { undoRedoGroupId });
const needsConfirmation = data.edit.edits.some(edit => edit.metadata?.needsConfirmation);
let showPreview = storageService.getBoolean(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, StorageScope.GLOBAL);
if (envService.extensionTestsLocationURI) {
// don't show dialog in tests
showPreview = false;
}
if (showPreview === undefined) {
// show a user facing message
let message: string;
if (data.extensionNames.length === 1) {
message = localize('ask.1', "Extension '{0}' wants to make additional edits for this file operation.", data.extensionNames[0]);
} else {
message = localize('ask.N', "{0} extensions want to make additional edits for this file operation.", data.extensionNames.length);
}
if (needsConfirmation) {
// edit which needs confirmation -> always show dialog
const answer = await dialogService.show(Severity.Info, message, [localize('preview', "Show Preview"), localize('cancel', "Skip additional edits")], { cancelId: 1 });
showPreview = true;
if (answer.choice === 1) {
// no additional edits wanted
return;
}
} else {
// choice
const answer = await dialogService.show(Severity.Info, message,
[localize('ok', "OK"), localize('preview', "Show Preview"), localize('cancel', "Skip additional edits")],
{
cancelId: 2,
checkbox: { label: localize('again', "Don't ask again") }
}
);
if (answer.choice === 2) {
// no additional edits wanted, don't persist cancel option
return;
}
showPreview = answer.choice === 1;
if (answer.checkboxChecked /* && answer.choice !== 2 */) {
storageService.store(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, showPreview, StorageScope.GLOBAL, StorageTarget.USER);
}
}
}
logService.info('[onWill-handler] applying additional workspace edit from extensions', data.extensionNames);
await bulkEditService.apply(
reviveWorkspaceEditDto2(data.edit),
{ undoRedoGroupId, showPreview }
);
}
private _progressLabel(operation: FileOperation): string {
switch (operation) {
case FileOperation.CREATE:
@@ -119,10 +183,21 @@ export class MainThreadFileSystemEventService {
dispose(): void {
this._listener.dispose();
}
}
registerAction2(class ResetMemento extends Action2 {
constructor() {
super({
id: 'files.participants.resetChoice',
title: localize('label', "Reset choice for 'File operation needs preview'"),
f1: true
});
}
run(accessor: ServicesAccessor) {
accessor.get(IStorageService).remove(MainThreadFileSystemEventService.MementoKeyAdditionalEdits, StorageScope.GLOBAL);
}
});
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
id: 'files',
@@ -1157,9 +1157,14 @@ export interface SourceTargetPair {
target: UriComponents;
}
export interface IWillRunFileOperationParticipation {
edit: IWorkspaceEditDto;
extensionNames: string[]
}
export interface ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents): void;
$onWillRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
$onWillRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined>;
$onDidRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[]): void;
}
@@ -8,7 +8,7 @@ import { IRelativePattern, parse } from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import type * as vscode from 'vscode';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, SourceTargetPair, IWorkspaceEditDto } from './extHost.protocol';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, SourceTargetPair, IWorkspaceEditDto, IWillRunFileOperationParticipation } from './extHost.protocol';
import * as typeConverter from './extHostTypeConverters';
import { Disposable, WorkspaceEdit } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -177,7 +177,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
};
}
async $onWillRunFileOperation(operation: FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
async $onWillRunFileOperation(operation: FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined> {
switch (operation) {
case FileOperation.MOVE:
return await this._fireWillEvent(this._onWillRenameFile, { files: files.map(f => ({ oldUri: URI.revive(f.source!), newUri: URI.revive(f.target) })) }, timeout, token);
@@ -189,8 +189,9 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
return undefined;
}
private async _fireWillEvent<E extends IWaitUntil>(emitter: AsyncEmitter<E>, data: Omit<E, 'waitUntil'>, timeout: number, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
private async _fireWillEvent<E extends IWaitUntil>(emitter: AsyncEmitter<E>, data: Omit<E, 'waitUntil'>, timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined> {
const extensionNames = new Set<string>();
const edits: WorkspaceEdit[] = [];
await emitter.fireAsync(data, token, async (thenable, listener) => {
@@ -199,10 +200,11 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
const result = await Promise.resolve(thenable);
if (result instanceof WorkspaceEdit) {
edits.push(result);
extensionNames.add((<IExtensionListener<E>>listener).extension.displayName ?? (<IExtensionListener<E>>listener).extension.identifier.value);
}
if (Date.now() - now > timeout) {
this._logService.warn('SLOW file-participant', (<IExtensionListener<E>>listener).extension?.identifier);
this._logService.warn('SLOW file-participant', (<IExtensionListener<E>>listener).extension.identifier);
}
});
@@ -220,6 +222,6 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
let { edits } = typeConverter.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
dto.edits = dto.edits.concat(edits);
}
return dto;
return { edit: dto, extensionNames: Array.from(extensionNames) };
}
}
@@ -49,12 +49,17 @@ abstract class BaseOpenRecentAction extends Action {
tooltip: nls.localize('remove', "Remove from Recently Opened")
};
private readonly dirtyRecentlyOpened: IQuickInputButton = {
private readonly dirtyRecentlyOpenedFolder: IQuickInputButton = {
iconClass: 'dirty-workspace ' + Codicon.closeDirty.classNames,
tooltip: nls.localize('dirtyRecentlyOpened', "Workspace With Dirty Files"),
tooltip: nls.localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"),
alwaysVisible: true
};
private readonly dirtyRecentlyOpenedWorkspace: IQuickInputButton = {
...this.dirtyRecentlyOpenedFolder,
tooltip: nls.localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"),
};
constructor(
id: string,
label: string,
@@ -77,7 +82,9 @@ abstract class BaseOpenRecentAction extends Action {
const recentlyOpened = await this.workspacesService.getRecentlyOpened();
const dirtyWorkspacesAndFolders = await this.workspacesService.getDirtyWorkspaces();
// Identify all folders and workspaces with dirty files
let hasWorkspaces = false;
// Identify all folders and workspaces with unsaved files
const dirtyFolders = new ResourceMap<boolean>();
const dirtyWorkspaces = new ResourceMap<IWorkspaceIdentifier>();
for (const dirtyWorkspace of dirtyWorkspacesAndFolders) {
@@ -85,6 +92,7 @@ abstract class BaseOpenRecentAction extends Action {
dirtyFolders.set(dirtyWorkspace, true);
} else {
dirtyWorkspaces.set(dirtyWorkspace.configPath, dirtyWorkspace);
hasWorkspaces = true;
}
}
@@ -96,6 +104,7 @@ abstract class BaseOpenRecentAction extends Action {
recentFolders.set(recent.folderUri, true);
} else {
recentWorkspaces.set(recent.workspace.configPath, recent.workspace);
hasWorkspaces = true;
}
}
@@ -124,7 +133,7 @@ abstract class BaseOpenRecentAction extends Action {
let keyMods: IKeyMods | undefined;
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") };
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? nls.localize('workspacesAndFolders', "folders & workspaces") : nls.localize('folders', "folders") };
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") };
const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks];
@@ -143,13 +152,14 @@ abstract class BaseOpenRecentAction extends Action {
context.removeItem();
}
// Dirty Workspace
else if (context.button === this.dirtyRecentlyOpened) {
// Dirty Folder/Workspace
else if (context.button === this.dirtyRecentlyOpenedFolder || context.button === this.dirtyRecentlyOpenedWorkspace) {
const isDirtyWorkspace = context.button === this.dirtyRecentlyOpenedWorkspace;
const result = await this.dialogService.confirm({
type: 'question',
title: nls.localize('dirtyWorkspace', "Workspace with Dirty Files"),
message: nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the dirty files?"),
detail: nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with dirty files cannot be removed until all dirty files have been saved or reverted.")
title: isDirtyWorkspace ? nls.localize('dirtyWorkspace', "Workspace with Unsaved Files") : nls.localize('dirtyFolder', "Folder with Unsaved Files"),
message: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : nls.localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"),
detail: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : nls.localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.")
});
if (result.confirmed) {
@@ -170,6 +180,7 @@ abstract class BaseOpenRecentAction extends Action {
let iconClasses: string[];
let fullLabel: string | undefined;
let resource: URI | undefined;
let isWorkspace = false;
// Folder
if (isRecentFolder(recent)) {
@@ -185,6 +196,7 @@ abstract class BaseOpenRecentAction extends Action {
iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.ROOT_FOLDER);
openable = { workspaceUri: resource };
fullLabel = recent.label || this.labelService.getWorkspaceLabel(recent.workspace, { verbose: true });
isWorkspace = true;
}
// File
@@ -200,9 +212,9 @@ abstract class BaseOpenRecentAction extends Action {
return {
iconClasses,
label: name,
ariaLabel: isDirty ? nls.localize('recentDirtyAriaLabel', "{0}, dirty workspace", name) : name,
ariaLabel: isDirty ? isWorkspace ? nls.localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : nls.localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name,
description: parentPath,
buttons: isDirty ? [this.dirtyRecentlyOpened] : [this.removeFromRecentlyOpened],
buttons: isDirty ? [isWorkspace ? this.dirtyRecentlyOpenedWorkspace : this.dirtyRecentlyOpenedFolder] : [this.removeFromRecentlyOpened],
openable,
resource
};
@@ -114,7 +114,7 @@ export class CloseWorkspaceAction extends Action {
async run(): Promise<void> {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.notificationService.info(nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close."));
this.notificationService.info(nls.localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close."));
return;
}
@@ -225,7 +225,7 @@ export class SaveWorkspaceAsAction extends Action {
export class DuplicateWorkspaceInNewWindowAction extends Action {
static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow';
static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate Workspace in New Window");
static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window");
constructor(
id: string,
@@ -259,7 +259,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(AddRootFolderAction),
registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalRemoveRootFolderAction), 'Workspaces: Remove Folder from Workspace...', workspacesCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseWorkspaceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory, EmptyWorkspaceSupportContext);
registry.registerWorkbenchAction(SyncActionDescriptor.from(SaveWorkspaceAsAction), 'Workspaces: Save Workspace As...', workspacesCategory, EmptyWorkspaceSupportContext);
registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateWorkspaceInNewWindowAction), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateWorkspaceInNewWindowAction), 'Workspaces: Duplicate As Workspace in New Window', workspacesCategory);
// --- Menu Registration
@@ -330,8 +330,8 @@ import { isStandalone } from 'vs/base/browser/browser';
nls.localize('activeFolderLong', "`\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)."),
nls.localize('folderName', "`\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder)."),
nls.localize('folderPath', "`\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)."),
nls.localize('rootName', "`\${rootName}`: name of the workspace (e.g. myFolder or myWorkspace)."),
nls.localize('rootPath', "`\${rootPath}`: file path of the workspace (e.g. /Users/Development/myWorkspace)."),
nls.localize('rootName', "`\${rootName}`: name of the opened workspace or folder (e.g. myFolder or myWorkspace)."),
nls.localize('rootPath', "`\${rootPath}`: file path of the opened workspace or folder (e.g. /Users/Development/myWorkspace)."),
nls.localize('appName', "`\${appName}`: e.g. VS Code."),
nls.localize('remoteName', "`\${remoteName}`: e.g. SSH"),
nls.localize('dirty', "`\${dirty}`: a dirty indicator if the active editor is dirty."),
+2 -2
View File
@@ -339,7 +339,7 @@ export const STATUS_BAR_FOREGROUND = registerColor('statusBar.foreground', {
dark: '#FFFFFF',
light: '#FFFFFF',
hc: '#FFFFFF'
}, nls.localize('statusBarForeground', "Status bar foreground color when a workspace is opened. The status bar is shown in the bottom of the window."));
}, nls.localize('statusBarForeground', "Status bar foreground color when a workspace or folder is opened. The status bar is shown in the bottom of the window."));
export const STATUS_BAR_NO_FOLDER_FOREGROUND = registerColor('statusBar.noFolderForeground', {
dark: STATUS_BAR_FOREGROUND,
@@ -351,7 +351,7 @@ export const STATUS_BAR_BACKGROUND = registerColor('statusBar.background', {
dark: '#007ACC',
light: '#007ACC',
hc: null
}, nls.localize('statusBarBackground', "Status bar background color when a workspace is opened. The status bar is shown in the bottom of the window."));
}, nls.localize('statusBarBackground', "Status bar background color when a workspace or folder is opened. The status bar is shown in the bottom of the window."));
export const STATUS_BAR_NO_FOLDER_BACKGROUND = registerColor('statusBar.noFolderBackground', {
dark: '#68217A',
+130 -53
View File
@@ -5,7 +5,7 @@
import 'vs/css!./media/repl';
import { URI as uri } from 'vs/base/common/uri';
import { IAction, IActionViewItem, Action, Separator } from 'vs/base/common/actions';
import { IAction, IActionViewItem } from 'vs/base/common/actions';
import * as dom from 'vs/base/browser/dom';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -26,7 +26,7 @@ import { memoize } from 'vs/base/common/decorators';
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { IDebugService, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State, IReplElement, IDebugConfiguration, REPL_VIEW_ID, CONTEXT_MULTI_SESSION_REPL } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State, IReplElement, IDebugConfiguration, REPL_VIEW_ID, CONTEXT_MULTI_SESSION_REPL, CONTEXT_DEBUG_STATE, getStateLabel } from 'vs/workbench/contrib/debug/common/debug';
import { HistoryNavigator } from 'vs/base/common/history';
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/browser/contextScopedHistoryWidget';
@@ -60,7 +60,8 @@ import { EDITOR_FONT_DEFAULTS, EditorOption } from 'vs/editor/common/config/edit
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
import { ReplFilter, ReplFilterState, ReplFilterActionViewItem } from 'vs/workbench/contrib/debug/browser/replFilter';
import { debugConsoleClearAll, debugConsoleEvaluationPrompt } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { registerAction2, MenuId, MenuItemAction, Action2 } from 'vs/platform/actions/common/actions';
import { registerAction2, MenuId, Action2, IMenuService, IMenu } from 'vs/platform/actions/common/actions';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
const $ = dom.$;
@@ -100,6 +101,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
private filterState: ReplFilterState;
private filterActionViewItem: ReplFilterActionViewItem | undefined;
private multiSessionRepl: IContextKey<boolean>;
private menu: IMenu;
constructor(
options: IViewPaneOptions,
@@ -114,14 +116,16 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
@IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService,
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService,
@IClipboardService private readonly clipboardService: IClipboardService,
@IEditorService private readonly editorService: IEditorService,
@IKeybindingService keybindingService: IKeybindingService,
@IOpenerService openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IMenuService menuService: IMenuService
) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
this.menu = menuService.createMenu(MenuId.DebugConsoleContext, contextKeyService);
this._register(this.menu);
this.history = new HistoryNavigator(JSON.parse(this.storageService.get(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')), 50);
this.filter = new ReplFilter();
this.filterState = new ReplFilterState(this);
@@ -459,6 +463,14 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
this.replInput.layout({ width: width - 30, height: replInputHeight });
}
collapseAll(): void {
this.tree.collapseAll();
}
getReplInput(): CodeEditorWidget {
return this.replInput;
}
focus(): void {
setTimeout(() => this.replInput.focus(), 0);
}
@@ -615,44 +627,12 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
private onContextMenu(e: ITreeContextMenuEvent<IReplElement>): void {
const actions: IAction[] = [];
actions.push(new Action('debug.replCopy', localize('copy', "Copy"), undefined, true, async () => {
const nativeSelection = window.getSelection();
if (nativeSelection) {
await this.clipboardService.writeText(nativeSelection.toString());
}
return Promise.resolve();
}));
actions.push(new Action('workbench.debug.action.copyAll', localize('copyAll', "Copy All"), undefined, true, async () => {
await this.clipboardService.writeText(this.getVisibleContent());
return Promise.resolve();
}));
actions.push(new Action('debug.replPaste', localize('paste', "Paste"), undefined, this.debugService.state !== State.Inactive, async () => {
const clipboardText = await this.clipboardService.readText();
if (clipboardText) {
this.replInput.setValue(this.replInput.getValue().concat(clipboardText));
this.replInput.focus();
const model = this.replInput.getModel();
const lineNumber = model ? model.getLineCount() : 0;
const column = model?.getLineMaxColumn(lineNumber);
if (typeof lineNumber === 'number' && typeof column === 'number') {
this.replInput.setPosition({ lineNumber, column });
}
}
}));
actions.push(new Separator());
actions.push(new Action('debug.collapseRepl', localize('collapse', "Collapse All"), undefined, true, () => {
this.tree.collapseAll();
this.replInput.focus();
return Promise.resolve();
}));
actions.push(new Separator());
actions.push(this.instantiationService.createInstance(MenuItemAction, clearReplCommand, undefined, {}));
const actionsDisposable = createAndFillInContextMenuActions(this.menu, { arg: e.element, shouldForwardArgs: false }, actions);
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => actions,
getActionsContext: () => e.element,
onHide: () => dispose(actions)
onHide: () => dispose(actionsDisposable)
});
}
@@ -864,26 +844,123 @@ registerAction2(class extends ViewAction<Repl> {
}
});
const clearReplCommand = {
id: 'workbench.debug.panel.action.clearReplAction',
viewId: REPL_VIEW_ID,
title: localize('clearRepl', "Clear Console"),
f1: true,
icon: debugConsoleClearAll,
menu: {
id: MenuId.ViewTitle,
group: 'navigation',
when: ContextKeyEqualsExpr.create('view', REPL_VIEW_ID),
order: 30
}
};
registerAction2(class extends ViewAction<Repl> {
constructor() {
super(clearReplCommand);
super({
id: 'workbench.debug.panel.action.clearReplAction',
viewId: REPL_VIEW_ID,
title: localize('clearRepl', "Clear Console"),
f1: true,
icon: debugConsoleClearAll,
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
when: ContextKeyEqualsExpr.create('view', REPL_VIEW_ID),
order: 30
}, {
id: MenuId.DebugConsoleContext,
group: 'z_commands',
order: 20
}]
});
}
runInView(_accessor: ServicesAccessor, view: Repl) {
runInView(_accessor: ServicesAccessor, view: Repl): void {
view.clearRepl();
aria.status(localize('debugConsoleCleared', "Debug console was cleared"));
}
});
registerAction2(class extends ViewAction<Repl> {
constructor() {
super({
id: 'debug.collapseRepl',
title: localize('collapse', "Collapse All"),
viewId: REPL_VIEW_ID,
menu: {
id: MenuId.DebugConsoleContext,
group: 'z_commands',
order: 10
}
});
}
runInView(_accessor: ServicesAccessor, view: Repl): void {
view.collapseAll();
view.focus();
}
});
registerAction2(class extends ViewAction<Repl> {
constructor() {
super({
id: 'debug.replPaste',
title: localize('paste', "Paste"),
viewId: REPL_VIEW_ID,
precondition: CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Inactive)),
menu: {
id: MenuId.DebugConsoleContext,
group: '2_cutcopypaste',
order: 30
}
});
}
async runInView(accessor: ServicesAccessor, view: Repl): Promise<void> {
const clipboardService = accessor.get(IClipboardService);
const clipboardText = await clipboardService.readText();
if (clipboardText) {
const replInput = view.getReplInput();
replInput.setValue(replInput.getValue().concat(clipboardText));
view.focus();
const model = replInput.getModel();
const lineNumber = model ? model.getLineCount() : 0;
const column = model?.getLineMaxColumn(lineNumber);
if (typeof lineNumber === 'number' && typeof column === 'number') {
replInput.setPosition({ lineNumber, column });
}
}
}
});
registerAction2(class extends ViewAction<Repl> {
constructor() {
super({
id: 'workbench.debug.action.copyAll',
title: localize('copyAll', "Copy All"),
viewId: REPL_VIEW_ID,
menu: {
id: MenuId.DebugConsoleContext,
group: '2_cutcopypaste',
order: 20
}
});
}
async runInView(accessor: ServicesAccessor, view: Repl): Promise<void> {
const clipboardService = accessor.get(IClipboardService);
await clipboardService.writeText(view.getVisibleContent());
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'debug.replCopy',
title: localize('copy', "Copy"),
menu: {
id: MenuId.DebugConsoleContext,
group: '2_cutcopypaste',
order: 10
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const clipboardService = accessor.get(IClipboardService);
const nativeSelection = window.getSelection();
if (nativeSelection) {
await clipboardService.writeText(nativeSelection.toString());
}
}
});
@@ -198,8 +198,8 @@ const hotExitConfiguration: IConfigurationPropertySchema = platform.isNative ?
'default': HotExitConfiguration.ON_EXIT,
'markdownEnumDescriptions': [
nls.localize('hotExit.off', 'Disable hot exit. A prompt will show when attempting to close a window with dirty files.'),
nls.localize('hotExit.onExit', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu). All windows without folders opened will be restored upon next launch. A list of workspaces with unsaved files can be accessed via `File > Open Recent > More...`'),
nls.localize('hotExit.onExitAndWindowClose', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu), and also for any window with a folder opened regardless of whether it\'s the last window. All windows without folders opened will be restored upon next launch. A list of workspaces with unsaved files can be accessed via `File > Open Recent > More...`')
nls.localize('hotExit.onExit', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu). All windows without folders opened will be restored upon next launch. A list of previously opened windows with unsaved files can be accessed via `File > Open Recent > More...`'),
nls.localize('hotExit.onExitAndWindowClose', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu), and also for any window with a folder opened regardless of whether it\'s the last window. All windows without folders opened will be restored upon next launch. A list of previously opened windows with unsaved files can be accessed via `File > Open Recent > More...`')
],
'description': nls.localize('hotExit', "Controls whether unsaved files are remembered between sessions, allowing the save prompt when exiting the editor to be skipped.", HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE)
} : {
@@ -89,7 +89,7 @@ export class WorkspaceWatcher extends Disposable {
if (msg.indexOf('ENOSPC') >= 0) {
this.notificationService.prompt(
Severity.Warning,
localize('enospcError', "Unable to watch for file changes in this large workspace. Please follow the instructions link to resolve this issue."),
localize('enospcError', "Unable to watch for file changes in this large workspace folder. Please follow the instructions link to resolve this issue."),
[{
label: localize('learnMore', "Instructions"),
run: () => this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=867693'))
@@ -164,8 +164,6 @@ export class SCMStatusController implements IWorkbenchContribution {
}
private renderActivityCount(): void {
this.badgeDisposable.clear();
const countBadgeType = this.configurationService.getValue<'all' | 'focused' | 'off'>('scm.countBadge');
let count = 0;
@@ -180,7 +178,7 @@ export class SCMStatusController implements IWorkbenchContribution {
const badge = new NumberBadge(count, num => localize('scmPendingChangesBadge', '{0} pending changes', num));
this.badgeDisposable.value = this.activityService.showViewActivity(VIEW_PANE_ID, { badge, clazz: 'scm-viewlet-label' });
} else {
this.badgeDisposable.clear();
this.badgeDisposable.value = undefined;
}
}
@@ -840,7 +840,7 @@ configurationRegistry.registerConfiguration({
'search.seedOnFocus': {
type: 'boolean',
default: false,
description: nls.localize('search.seedOnFocus', "Update workspace search query to the editor's selected text when focusing the search view. This happens either on click or when triggering the `workbench.views.search.focus` command.")
description: nls.localize('search.seedOnFocus', "Update the search query to the editor's selected text when focusing the search view. This happens either on click or when triggering the `workbench.views.search.focus` command.")
},
'search.searchOnTypeDebouncePeriod': {
type: 'number',
@@ -378,7 +378,7 @@ export class QueryBuilder {
});
} else {
// No root folder with name
const searchPathNotFoundError = nls.localize('search.noWorkspaceWithName', "No folder in workspace with name: {0}", searchPathRoot);
const searchPathNotFoundError = nls.localize('search.noWorkspaceWithName', "Workspace folder does not exist: {0}", searchPathRoot);
throw new Error(searchPathNotFoundError);
}
} else {
@@ -1977,7 +1977,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile);
const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal;
if (engine === ExecutionEngine.Process) {
this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in .codeworkspace.'));
this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in workspace configuration files.'));
return this.emptyWorkspaceTaskResults(workspaceFolder);
}
return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors };
@@ -32,7 +32,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."),
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the Welcome page (default)."),
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."),
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty workspace)."),
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."),
localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the Welcome page when opening an empty workbench."),],
...(product.quality !== 'stable'
? [localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the Getting Started page (experimental).")]
@@ -246,7 +246,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
jsonEditor;
if (!this.workspaceSettingsResource) {
this.notificationService.info(nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
this.notificationService.info(nls.localize('openFolderFirst', "Open a folder or workspace first to create workspace or folder settings."));
return Promise.reject(null);
}